diff options
author | Jonah Graham | 2018-11-20 16:20:42 +0000 |
---|---|---|
committer | Jonah Graham | 2018-11-22 21:47:02 +0000 |
commit | 170e654b4796bad1453ae85a427b97317d67a69a (patch) | |
tree | 6ca9b8a8fedd5fd25f97eb79c408312e256ff981 /dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIParser.java | |
parent | 35996a5c5ca5c254959ba48241eaada6dbf8628d (diff) | |
download | org.eclipse.cdt-170e654b4796bad1453ae85a427b97317d67a69a.tar.gz org.eclipse.cdt-170e654b4796bad1453ae85a427b97317d67a69a.tar.xz org.eclipse.cdt-170e654b4796bad1453ae85a427b97317d67a69a.zip |
Bug 540373: Cleanup: Format & Remove trailing whitespace
This was done by selecting all projects in Eclipse then
Source -> Clean Up... -> choosing:
- Format source code
- Remove trailing white spaces on all lines
and completing the wizard
Change-Id: I63685372c6bcc67719bcf145123bcb72e5b00394
Diffstat (limited to 'dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIParser.java')
-rw-r--r-- | dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIParser.java | 976 |
1 files changed, 489 insertions, 487 deletions
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIParser.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIParser.java index eb486c9b10a..7e0b3c5b48e 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIParser.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIParser.java @@ -95,491 +95,493 @@ import java.util.List; </pre> */ public class MIParser { - public enum RecordType { ResultRecord, OOBRecord, PrimaryPrompt } - - public String primaryPrompt = "(gdb)"; //$NON-NLS-1$ - public String cliPrompt = primaryPrompt; - public String secondaryPrompt = ">"; //$NON-NLS-1$ - - public RecordType getRecordType(String line) { - int i = 0; - if (Character.isDigit(line.charAt(0))) { - i = 1; - while (i < line.length() && Character.isDigit(line.charAt(i))) { - i++; - } - } - - if (i < line.length() && line.charAt(i) == '^') { - return RecordType.ResultRecord; - } else if (line.startsWith(primaryPrompt, i)) { - return RecordType.PrimaryPrompt; - //break; // Do nothing. - } else { - return RecordType.OOBRecord; - } - } - - /** - * - */ - public MIResultRecord parseMIResultRecord(String line) { - StringBuffer buffer = new StringBuffer(line); - // Fetch the Token/Id - int id = parseToken(buffer); - // Consume the '^' - buffer.deleteCharAt(0); - - MIResultRecord rr = new MIResultRecord(); - rr.setToken(id); - if (buffer.toString().startsWith(MIResultRecord.DONE)) { - rr.setResultClass(MIResultRecord.DONE); - buffer.delete(0, MIResultRecord.DONE.length()); - } else if (buffer.toString().startsWith(MIResultRecord.ERROR)) { - rr.setResultClass(MIResultRecord.ERROR); - buffer.delete(0, MIResultRecord.ERROR.length()); - } else if (buffer.toString().startsWith(MIResultRecord.EXIT)) { - rr.setResultClass(MIResultRecord.EXIT); - buffer.delete(0, MIResultRecord.EXIT.length()); - } else if (buffer.toString().startsWith(MIResultRecord.RUNNING)) { - rr.setResultClass(MIResultRecord.RUNNING); - buffer.delete(0, MIResultRecord.RUNNING.length()); - } else if (buffer.toString().startsWith(MIResultRecord.CONNECTED)) { - rr.setResultClass(MIResultRecord.CONNECTED); - buffer.delete(0, MIResultRecord.CONNECTED.length()); - } else { - // Error throw an exception? - } - - // Results are separated by commas. - if (buffer.length() > 0 && buffer.charAt(0) == ',') { - buffer.deleteCharAt(0); - MIResult[] res = processMIResults(new FSB(buffer)); - rr.setMIResults(res); - } - return rr; - } - - /** - * Find OutOfBand Records depending on the starting token. - */ - public MIOOBRecord parseMIOOBRecord(String line) { - StringBuffer buffer = new StringBuffer(line); - int id = parseToken(buffer); - MIOOBRecord oob = null; - char c = buffer.length() != 0 ? buffer.charAt(0) : 0; - if (c == '*' || c == '+' || c == '=') { - // Consume the first char - buffer.deleteCharAt(0); - MIAsyncRecord async = null; - switch (c) { - case '*' : - async = new MIExecAsyncOutput(); - break; - - case '+' : - async = new MIStatusAsyncOutput(); - break; - - case '=' : - async = new MINotifyAsyncOutput(); - break; - default : - assert false; - async = new MINotifyAsyncOutput(); - } - async.setToken(id); - // Extract the Async-Class - int i = buffer.toString().indexOf(','); - if (i != -1) { - String asyncClass = buffer.substring(0, i); - async.setAsyncClass(asyncClass); - // Consume the async-class and the comma - buffer.delete(0, i + 1); - } else { - async.setAsyncClass(buffer.toString().trim()); - buffer.setLength(0); - } - MIResult[] res = processMIResults(new FSB(buffer)); - async.setMIResults(res); - oob = async; - } else if (c == '~' || c == '@' || c == '&') { - // Consume the first char - buffer.deleteCharAt(0); - MIStreamRecord stream = null; - switch (c) { - case '~' : - stream = new MIConsoleStreamOutput(); - break; - - case '@' : - stream = new MITargetStreamOutput(); - break; - - case '&' : - stream = new MILogStreamOutput(); - break; - default : - assert false; - stream = new MIConsoleStreamOutput(); - } - // translateCString() assumes that the leading " is deleted - if (buffer.length() > 0 && buffer.charAt(0) == '"') { - buffer.deleteCharAt(0); - } - // Don't parse any backslashes - backslashes within stream records - // aren't escaped. - stream.setCString(translateCString(new FSB(buffer), false)); - oob = stream; - } else { - // Badly format MI line, just pass it to the user as target stream - MIStreamRecord stream = new MITargetStreamOutput(); - stream.setCString(line + "\n"); //$NON-NLS-1$ - oob = stream; - } - return oob; - } - - private int parseToken(StringBuffer buffer) { - int id = -1; - // Fetch the Token/Id - if (Character.isDigit(buffer.charAt(0))) { - int i = 1; - while (i < buffer.length() && Character.isDigit(buffer.charAt(i))) { - i++; - } - String numbers = buffer.substring(0, i); - try { - id = Integer.parseInt(numbers); - } catch (NumberFormatException e) { - } - // Consume the token. - buffer.delete(0, i); - } - return id; - } - - /** - * Assuming that the usual leading comma was consumed. - * Extract the MI Result comma seperated responses. - */ - private MIResult[] processMIResults(FSB buffer) { - List<MIResult> aList = new ArrayList<MIResult>(); - MIResult result = processMIResult(buffer); - if (result != null) { - aList.add(result); - } - while (buffer.length() > 0 && buffer.charAt(0) == ',') { - buffer.deleteCharAt(0); - result = processMIResult(buffer); - if (result != null) { - aList.add(result); - } - } - return aList.toArray(new MIResult[aList.size()]); - } - - /** - * Construct the DsfMIResult. Characters will be consume/delete - * moving forward constructing the AST. - */ - private MIResult processMIResult(FSB buffer) { - MIResult result = new MIResult(); - int equal; - if (buffer.length() > 0 && Character.isLetter(buffer.charAt(0)) && (equal = buffer.indexOf('=')) != -1) { - // Result is a variable and value - String variable = buffer.substring(0, equal); - result.setVariable(variable); - buffer.delete(0, equal + 1); - MIValue value = processMIValue(buffer); - result.setMIValue(value); - } else { - MIValue value = processMIValue(buffer); - if (value != null) { - // Result is a value only (bug 527419) - result.setMIValue(value); - } else { - result.setVariable(buffer.toString()); - result.setMIValue(new MIConst()); // Empty string:??? - buffer.setLength(0); - } - } - return result; - } - - /** - * Find a DsfMIValue implementation or return null. - */ - private MIValue processMIValue(FSB buffer) { - MIValue value = null; - if (buffer.length() > 0) { - if (buffer.charAt(0) == '{') { - buffer.deleteCharAt(0); - value = processMITuple(buffer); - } else if (buffer.charAt(0) == '[') { - buffer.deleteCharAt(0); - value = processMIList(buffer); - } else if (buffer.charAt(0) == '"') { - buffer.deleteCharAt(0); - MIConst cnst = new MIConst(); - // Parse backslashes - backslashes within result - // and out of band records are escaped. - cnst.setCString(translateCString(buffer, true)); - value = cnst; - } - } - return value; - } - - /** - * Assuming the starting '{' was deleted form the StringBuffer, - * go to the closing '}' consuming/deleting all the characters. - * This is usually call by processMIvalue(); - */ - private MIValue processMITuple(FSB buffer) { - MITuple tuple = new MITuple(); - List<MIValue> valueList = new ArrayList<MIValue>(); - List<MIResult> resultList = new ArrayList<MIResult>(); - // Catch closing '}' - while (buffer.length() > 0 && buffer.charAt(0) != '}') { - // Try for the DsfMIValue first - MIValue value = processMIValue(buffer); - if (value != null) { - valueList.add(value); - } else { - MIResult result = processMIResult(buffer); - if (result != null) { - resultList.add(result); - } - } - if (buffer.length() > 0 && buffer.charAt(0) == ',') { - buffer.deleteCharAt(0); - } - } - if (buffer.length() > 0 && buffer.charAt(0) == '}') { - buffer.deleteCharAt(0); - } - MIValue[] values = valueList.toArray(new MIValue[valueList.size()]); - MIResult[] res = resultList.toArray(new MIResult[resultList.size()]); - tuple.setMIValues(values); - tuple.setMIResults(res); - return tuple; - } - - /** - * Assuming the leading '[' was deleted, find the closing - * ']' consuming/delete chars from the StringBuffer. - */ - private MIValue processMIList(FSB buffer) { - MIList list = new MIList(); - List<MIValue> valueList = new ArrayList<MIValue>(); - List<MIResult> resultList = new ArrayList<MIResult>(); - // catch closing ']' - while (buffer.length() > 0 && buffer.charAt(0) != ']') { - // Try for the DsfMIValue first - MIValue value = processMIValue(buffer); - if (value != null) { - valueList.add(value); - } else { - MIResult result = processMIResult(buffer); - if (result != null) { - resultList.add(result); - } - } - if (buffer.length() > 0 && buffer.charAt(0) == ',') { - buffer.deleteCharAt(0); - } - } - if (buffer.length() > 0 && buffer.charAt(0) == ']') { - buffer.deleteCharAt(0); - } - MIValue[] values = valueList.toArray(new MIValue[valueList.size()]); - MIResult[] res = resultList.toArray(new MIResult[resultList.size()]); - list.setMIValues(values); - list.setMIResults(res); - return list; - } - - /** - * MI C-String rather MIConst values are enclosed in double quotes - * and any double quotes or backslashes in the string are escaped. - * Assuming the starting double quote was removed. This method will - * stop at the closing double quote, remove the extra backslash escaping - * and return the string __without__ the enclosing double quotes. The - * original string buffer will move forward. - * @param buffer The string buffer to read from. - * @param parseBackslashes Defines whether backslashes should be parsed. - * This parameter is necessary to differentiate between records which - * contain escaped backslashes and records which do not. - * @return The translated C string. - */ - private String translateCString(FSB buffer, boolean parseBackslashes) { - boolean escape = false; - boolean closingQuotes = false; - - StringBuffer sb = new StringBuffer(); - - int index = 0; - for (; index < buffer.length() && !closingQuotes; index++) { - char c = buffer.charAt(index); - if (c == '\\') { - if (escape) { - sb.append(c); - if (!parseBackslashes) { - sb.append(c); - } - escape = false; - } else { - escape = true; - } - } else if (c == '"') { - if (escape) { - sb.append(c); - escape = false; - } else { - // Bail out. - closingQuotes = true; - } - } else { - if (escape) { - sb.append('\\'); - } - sb.append(c); - escape = false; - } - } - buffer.delete(0, index); - return sb.toString(); - } - - /** - * Tests if this string starts with the specified prefix beginning - * a specified index. - * - * @param value the string. - * @param prefix the prefix. - * @return <code>true</code> if prefix starts value. - */ - public boolean startsWith(StringBuffer value, String prefix) { - int vlen = value.length(); - int plen = prefix.length(); - - if (vlen < plen) { - return false; - } - for (int i = 0; i < plen; i++) { - if (value.charAt(i) != prefix.charAt(i)) { - return false; - } - } - return true; - } - - /** - * Fast String Buffer class. MIParser does a lot - * of deleting off the front of a string, that's clearly - * an order N operation for StringBuffer which makes - * the MIParser an order N^2 operation. There are "issues" - * with this for large arrays. Use of FSB rather than String - * Buffer makes MIParser N rather than N^2 because FSB can - * delete from the front in constant time. - */ - public class FSB { - StringBuffer buf; - int pos; - boolean shared; - - public FSB(StringBuffer buf) { - this.buf = buf; - pos = 0; - shared = false; - } - - public FSB(FSB fbuf) { - pos = fbuf.pos; - buf = fbuf.buf; - shared = true; - } - - public int length() { - int res = buf.length() - pos; - if (res < 0) - return 0; - - return res; - } - - public char charAt(int index) { - return buf.charAt(index + pos); - } - - private void resolveCopy() { - if (shared) { - buf = new StringBuffer(buf.toString()); - shared = false; - } - } - - public FSB deleteCharAt(int index) { - if (index == 0) { - pos++; - } else { - resolveCopy(); - buf = buf.deleteCharAt(pos + index); - } - - return this; - } - - public FSB delete(int start, int end) { - if (start == 0) { - pos = pos + end - start; - } else { - resolveCopy(); - buf.delete(start + pos, end + pos); - } - - return this; - } - - public void setLength(int a) { - if (a == 0) - pos = buf.length(); - else { - // panic! fortunately we don't do this. - } - } - - public String substring(int start, int end) { - return buf.substring(start + pos, end + pos); - } - - @Override - public String toString() { - return buf.substring(pos, buf.length()); - } - - int indexOf(char c) { - int len = buf.length(); - for (int i = pos; i < len; i++) { - if (buf.charAt(i) == c) - return i - pos; - } - - return -1; - } - - boolean startsWith(String s) { - int len = Math.min(s.length(), length()); - if (len < s.length()) - return false; - - for (int i = 0; i < len; i++) { - if (s.charAt(i) != buf.charAt(pos + i)) - return false; - } - - return true; - } - } + public enum RecordType { + ResultRecord, OOBRecord, PrimaryPrompt + } + + public String primaryPrompt = "(gdb)"; //$NON-NLS-1$ + public String cliPrompt = primaryPrompt; + public String secondaryPrompt = ">"; //$NON-NLS-1$ + + public RecordType getRecordType(String line) { + int i = 0; + if (Character.isDigit(line.charAt(0))) { + i = 1; + while (i < line.length() && Character.isDigit(line.charAt(i))) { + i++; + } + } + + if (i < line.length() && line.charAt(i) == '^') { + return RecordType.ResultRecord; + } else if (line.startsWith(primaryPrompt, i)) { + return RecordType.PrimaryPrompt; + //break; // Do nothing. + } else { + return RecordType.OOBRecord; + } + } + + /** + * + */ + public MIResultRecord parseMIResultRecord(String line) { + StringBuffer buffer = new StringBuffer(line); + // Fetch the Token/Id + int id = parseToken(buffer); + // Consume the '^' + buffer.deleteCharAt(0); + + MIResultRecord rr = new MIResultRecord(); + rr.setToken(id); + if (buffer.toString().startsWith(MIResultRecord.DONE)) { + rr.setResultClass(MIResultRecord.DONE); + buffer.delete(0, MIResultRecord.DONE.length()); + } else if (buffer.toString().startsWith(MIResultRecord.ERROR)) { + rr.setResultClass(MIResultRecord.ERROR); + buffer.delete(0, MIResultRecord.ERROR.length()); + } else if (buffer.toString().startsWith(MIResultRecord.EXIT)) { + rr.setResultClass(MIResultRecord.EXIT); + buffer.delete(0, MIResultRecord.EXIT.length()); + } else if (buffer.toString().startsWith(MIResultRecord.RUNNING)) { + rr.setResultClass(MIResultRecord.RUNNING); + buffer.delete(0, MIResultRecord.RUNNING.length()); + } else if (buffer.toString().startsWith(MIResultRecord.CONNECTED)) { + rr.setResultClass(MIResultRecord.CONNECTED); + buffer.delete(0, MIResultRecord.CONNECTED.length()); + } else { + // Error throw an exception? + } + + // Results are separated by commas. + if (buffer.length() > 0 && buffer.charAt(0) == ',') { + buffer.deleteCharAt(0); + MIResult[] res = processMIResults(new FSB(buffer)); + rr.setMIResults(res); + } + return rr; + } + + /** + * Find OutOfBand Records depending on the starting token. + */ + public MIOOBRecord parseMIOOBRecord(String line) { + StringBuffer buffer = new StringBuffer(line); + int id = parseToken(buffer); + MIOOBRecord oob = null; + char c = buffer.length() != 0 ? buffer.charAt(0) : 0; + if (c == '*' || c == '+' || c == '=') { + // Consume the first char + buffer.deleteCharAt(0); + MIAsyncRecord async = null; + switch (c) { + case '*': + async = new MIExecAsyncOutput(); + break; + + case '+': + async = new MIStatusAsyncOutput(); + break; + + case '=': + async = new MINotifyAsyncOutput(); + break; + default: + assert false; + async = new MINotifyAsyncOutput(); + } + async.setToken(id); + // Extract the Async-Class + int i = buffer.toString().indexOf(','); + if (i != -1) { + String asyncClass = buffer.substring(0, i); + async.setAsyncClass(asyncClass); + // Consume the async-class and the comma + buffer.delete(0, i + 1); + } else { + async.setAsyncClass(buffer.toString().trim()); + buffer.setLength(0); + } + MIResult[] res = processMIResults(new FSB(buffer)); + async.setMIResults(res); + oob = async; + } else if (c == '~' || c == '@' || c == '&') { + // Consume the first char + buffer.deleteCharAt(0); + MIStreamRecord stream = null; + switch (c) { + case '~': + stream = new MIConsoleStreamOutput(); + break; + + case '@': + stream = new MITargetStreamOutput(); + break; + + case '&': + stream = new MILogStreamOutput(); + break; + default: + assert false; + stream = new MIConsoleStreamOutput(); + } + // translateCString() assumes that the leading " is deleted + if (buffer.length() > 0 && buffer.charAt(0) == '"') { + buffer.deleteCharAt(0); + } + // Don't parse any backslashes - backslashes within stream records + // aren't escaped. + stream.setCString(translateCString(new FSB(buffer), false)); + oob = stream; + } else { + // Badly format MI line, just pass it to the user as target stream + MIStreamRecord stream = new MITargetStreamOutput(); + stream.setCString(line + "\n"); //$NON-NLS-1$ + oob = stream; + } + return oob; + } + + private int parseToken(StringBuffer buffer) { + int id = -1; + // Fetch the Token/Id + if (Character.isDigit(buffer.charAt(0))) { + int i = 1; + while (i < buffer.length() && Character.isDigit(buffer.charAt(i))) { + i++; + } + String numbers = buffer.substring(0, i); + try { + id = Integer.parseInt(numbers); + } catch (NumberFormatException e) { + } + // Consume the token. + buffer.delete(0, i); + } + return id; + } + + /** + * Assuming that the usual leading comma was consumed. + * Extract the MI Result comma seperated responses. + */ + private MIResult[] processMIResults(FSB buffer) { + List<MIResult> aList = new ArrayList<MIResult>(); + MIResult result = processMIResult(buffer); + if (result != null) { + aList.add(result); + } + while (buffer.length() > 0 && buffer.charAt(0) == ',') { + buffer.deleteCharAt(0); + result = processMIResult(buffer); + if (result != null) { + aList.add(result); + } + } + return aList.toArray(new MIResult[aList.size()]); + } + + /** + * Construct the DsfMIResult. Characters will be consume/delete + * moving forward constructing the AST. + */ + private MIResult processMIResult(FSB buffer) { + MIResult result = new MIResult(); + int equal; + if (buffer.length() > 0 && Character.isLetter(buffer.charAt(0)) && (equal = buffer.indexOf('=')) != -1) { + // Result is a variable and value + String variable = buffer.substring(0, equal); + result.setVariable(variable); + buffer.delete(0, equal + 1); + MIValue value = processMIValue(buffer); + result.setMIValue(value); + } else { + MIValue value = processMIValue(buffer); + if (value != null) { + // Result is a value only (bug 527419) + result.setMIValue(value); + } else { + result.setVariable(buffer.toString()); + result.setMIValue(new MIConst()); // Empty string:??? + buffer.setLength(0); + } + } + return result; + } + + /** + * Find a DsfMIValue implementation or return null. + */ + private MIValue processMIValue(FSB buffer) { + MIValue value = null; + if (buffer.length() > 0) { + if (buffer.charAt(0) == '{') { + buffer.deleteCharAt(0); + value = processMITuple(buffer); + } else if (buffer.charAt(0) == '[') { + buffer.deleteCharAt(0); + value = processMIList(buffer); + } else if (buffer.charAt(0) == '"') { + buffer.deleteCharAt(0); + MIConst cnst = new MIConst(); + // Parse backslashes - backslashes within result + // and out of band records are escaped. + cnst.setCString(translateCString(buffer, true)); + value = cnst; + } + } + return value; + } + + /** + * Assuming the starting '{' was deleted form the StringBuffer, + * go to the closing '}' consuming/deleting all the characters. + * This is usually call by processMIvalue(); + */ + private MIValue processMITuple(FSB buffer) { + MITuple tuple = new MITuple(); + List<MIValue> valueList = new ArrayList<MIValue>(); + List<MIResult> resultList = new ArrayList<MIResult>(); + // Catch closing '}' + while (buffer.length() > 0 && buffer.charAt(0) != '}') { + // Try for the DsfMIValue first + MIValue value = processMIValue(buffer); + if (value != null) { + valueList.add(value); + } else { + MIResult result = processMIResult(buffer); + if (result != null) { + resultList.add(result); + } + } + if (buffer.length() > 0 && buffer.charAt(0) == ',') { + buffer.deleteCharAt(0); + } + } + if (buffer.length() > 0 && buffer.charAt(0) == '}') { + buffer.deleteCharAt(0); + } + MIValue[] values = valueList.toArray(new MIValue[valueList.size()]); + MIResult[] res = resultList.toArray(new MIResult[resultList.size()]); + tuple.setMIValues(values); + tuple.setMIResults(res); + return tuple; + } + + /** + * Assuming the leading '[' was deleted, find the closing + * ']' consuming/delete chars from the StringBuffer. + */ + private MIValue processMIList(FSB buffer) { + MIList list = new MIList(); + List<MIValue> valueList = new ArrayList<MIValue>(); + List<MIResult> resultList = new ArrayList<MIResult>(); + // catch closing ']' + while (buffer.length() > 0 && buffer.charAt(0) != ']') { + // Try for the DsfMIValue first + MIValue value = processMIValue(buffer); + if (value != null) { + valueList.add(value); + } else { + MIResult result = processMIResult(buffer); + if (result != null) { + resultList.add(result); + } + } + if (buffer.length() > 0 && buffer.charAt(0) == ',') { + buffer.deleteCharAt(0); + } + } + if (buffer.length() > 0 && buffer.charAt(0) == ']') { + buffer.deleteCharAt(0); + } + MIValue[] values = valueList.toArray(new MIValue[valueList.size()]); + MIResult[] res = resultList.toArray(new MIResult[resultList.size()]); + list.setMIValues(values); + list.setMIResults(res); + return list; + } + + /** + * MI C-String rather MIConst values are enclosed in double quotes + * and any double quotes or backslashes in the string are escaped. + * Assuming the starting double quote was removed. This method will + * stop at the closing double quote, remove the extra backslash escaping + * and return the string __without__ the enclosing double quotes. The + * original string buffer will move forward. + * @param buffer The string buffer to read from. + * @param parseBackslashes Defines whether backslashes should be parsed. + * This parameter is necessary to differentiate between records which + * contain escaped backslashes and records which do not. + * @return The translated C string. + */ + private String translateCString(FSB buffer, boolean parseBackslashes) { + boolean escape = false; + boolean closingQuotes = false; + + StringBuffer sb = new StringBuffer(); + + int index = 0; + for (; index < buffer.length() && !closingQuotes; index++) { + char c = buffer.charAt(index); + if (c == '\\') { + if (escape) { + sb.append(c); + if (!parseBackslashes) { + sb.append(c); + } + escape = false; + } else { + escape = true; + } + } else if (c == '"') { + if (escape) { + sb.append(c); + escape = false; + } else { + // Bail out. + closingQuotes = true; + } + } else { + if (escape) { + sb.append('\\'); + } + sb.append(c); + escape = false; + } + } + buffer.delete(0, index); + return sb.toString(); + } + + /** + * Tests if this string starts with the specified prefix beginning + * a specified index. + * + * @param value the string. + * @param prefix the prefix. + * @return <code>true</code> if prefix starts value. + */ + public boolean startsWith(StringBuffer value, String prefix) { + int vlen = value.length(); + int plen = prefix.length(); + + if (vlen < plen) { + return false; + } + for (int i = 0; i < plen; i++) { + if (value.charAt(i) != prefix.charAt(i)) { + return false; + } + } + return true; + } + + /** + * Fast String Buffer class. MIParser does a lot + * of deleting off the front of a string, that's clearly + * an order N operation for StringBuffer which makes + * the MIParser an order N^2 operation. There are "issues" + * with this for large arrays. Use of FSB rather than String + * Buffer makes MIParser N rather than N^2 because FSB can + * delete from the front in constant time. + */ + public class FSB { + StringBuffer buf; + int pos; + boolean shared; + + public FSB(StringBuffer buf) { + this.buf = buf; + pos = 0; + shared = false; + } + + public FSB(FSB fbuf) { + pos = fbuf.pos; + buf = fbuf.buf; + shared = true; + } + + public int length() { + int res = buf.length() - pos; + if (res < 0) + return 0; + + return res; + } + + public char charAt(int index) { + return buf.charAt(index + pos); + } + + private void resolveCopy() { + if (shared) { + buf = new StringBuffer(buf.toString()); + shared = false; + } + } + + public FSB deleteCharAt(int index) { + if (index == 0) { + pos++; + } else { + resolveCopy(); + buf = buf.deleteCharAt(pos + index); + } + + return this; + } + + public FSB delete(int start, int end) { + if (start == 0) { + pos = pos + end - start; + } else { + resolveCopy(); + buf.delete(start + pos, end + pos); + } + + return this; + } + + public void setLength(int a) { + if (a == 0) + pos = buf.length(); + else { + // panic! fortunately we don't do this. + } + } + + public String substring(int start, int end) { + return buf.substring(start + pos, end + pos); + } + + @Override + public String toString() { + return buf.substring(pos, buf.length()); + } + + int indexOf(char c) { + int len = buf.length(); + for (int i = pos; i < len; i++) { + if (buf.charAt(i) == c) + return i - pos; + } + + return -1; + } + + boolean startsWith(String s) { + int len = Math.min(s.length(), length()); + if (len < s.length()) + return false; + + for (int i = 0; i < len; i++) { + if (s.charAt(i) != buf.charAt(pos + i)) + return false; + } + + return true; + } + } } |