/*
* Copyright (C) 2012 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.crsh.cli.impl.line;
/**
* Line parser.
*
* @author Julien Viet
*/
public final class LineParser {
public static abstract class Visitor {
public void onChar(int index, Quoting quoting, boolean backslash, char c) { }
public void openStrongQuote(int index) {}
public void closeStrongQuote(int index) {}
public void openWeakQuote(int index) {}
public void closeWeakQuote(int index) {}
public void reset() {}
}
/** . */
private static final int NORMAL = 0, WEAK_QUOTING = 1, STRONG_QUOTING = 2;
/** . */
private int status = NORMAL;
/** . */
private boolean escaped = false;
/** . */
private int index = 0;
/** . */
private final Visitor[] visitors;
public LineParser(Visitor... visitors) {
this.visitors = visitors;
}
public boolean crlf() {
if (escaped) {
escaped = false;
return false;
} else {
switch (status) {
case WEAK_QUOTING:
for (Visitor visitor : visitors) visitor.onChar(index, Quoting.WEAK, false, '\n');
index++;
return false;
case STRONG_QUOTING:
for (Visitor visitor : visitors) visitor.onChar(index, Quoting.STRONG, false, '\n');
index++;
return false;
default:
return true;
}
}
}
public LineParser append(CharSequence s) {
int len = s.length();
for (int index = 0;index < len;index++) {
append(s.charAt(index));
}
return this;
}
public LineParser append(char c) {
if (!escaped) {
switch (status) {
case NORMAL:
switch (c) {
case '\\':
escaped = true;
break;
case '\"':
for (Visitor visitor : visitors) visitor.openWeakQuote(index);
status = WEAK_QUOTING;
index++;
break;
case '\'':
for (Visitor visitor : visitors) visitor.openStrongQuote(index);
index++;
status = STRONG_QUOTING;
break;
default:
for (Visitor visitor : visitors) visitor.onChar(index, null, false, c);
index++;
break;
}
break;
case WEAK_QUOTING:
switch (c) {
case '"':
for (Visitor visitor : visitors) visitor.closeWeakQuote(index);
index++;
status = NORMAL;
break;
case '\\':
escaped = true;
break;
default:
for (Visitor visitor : visitors) visitor.onChar(index, Quoting.WEAK, false, c);
index++;
break;
}
break;
case STRONG_QUOTING:
switch (c) {
case '\'':
for (Visitor visitor : visitors) visitor.closeStrongQuote(index);
index++;
status = NORMAL;
break;
case '\\':
escaped = true;
break;
default:
for (Visitor visitor : visitors) visitor.onChar(index, Quoting.STRONG, false, c);
index++;
break;
}
break;
}
} else {
switch (status) {
case NORMAL:
for (Visitor visitor : visitors) visitor.onChar(index + 1, null, true, c);
index += 2;
break;
case WEAK_QUOTING:
for (Visitor visitor : visitors) visitor.onChar(index + 1, Quoting.WEAK, true, c);
index += 2;
break;
case STRONG_QUOTING:
if (c == '\'') {
// Special case
status = NORMAL;
for (Visitor visitor : visitors) visitor.onChar(index, Quoting.STRONG, false, '\\');
for (Visitor visitor : visitors) visitor.closeStrongQuote(index + 1);
index += 2;
} else {
for (Visitor visitor : visitors) visitor.onChar(index + 1, Quoting.STRONG, true, c);
index += 2;
}
break;
}
escaped = false;
}
return this;
}
public void reset() {
index = 0;
status = NORMAL;
escaped = false;
for (Visitor visitor : visitors) visitor.reset();
}
}