/** * This method parses a string and build a set of sorting instructions. The parsing may only be * partial on the case the rules are to be merged sometime later. * * @param stop_on_reset If this parameter is true then the parser stops when it encounters a reset * instruction. In the other case, it tries to parse the subrules and merged it in the same * repository. * @param v Output vector for the set of instructions. * @param base_offset Offset in the string to begin parsing. * @param rules Rules to be parsed. * @return -1 if the parser reached the end of the string, an integer representing the offset in * the string at which it stopped parsing. * @throws ParseException if something turned wrong during the parsing. To get details decode the * message. */ private int subParseString(boolean stop_on_reset, ArrayList v, int base_offset, String rules) throws ParseException { boolean ignoreChars = (base_offset == 0); int operator = -1; StringBuffer sb = new StringBuffer(); boolean doubleQuote = false; boolean eatingChars = false; boolean nextIsModifier = false; boolean isModifier = false; int i; main_parse_loop: for (i = 0; i < rules.length(); i++) { char c = rules.charAt(i); int type = -1; if (!eatingChars && ((c >= 0x09 && c <= 0x0D) || (c == 0x20))) continue; isModifier = nextIsModifier; nextIsModifier = false; if (eatingChars && c != '\'') { doubleQuote = false; sb.append(c); continue; } if (doubleQuote && eatingChars) { sb.append(c); doubleQuote = false; continue; } switch (c) { case '!': throw new ParseException( "Modifier '!' is not yet supported by Classpath", i + base_offset); case '<': type = CollationSorter.GREATERP; break; case ';': type = CollationSorter.GREATERS; break; case ',': type = CollationSorter.GREATERT; break; case '=': type = CollationSorter.EQUAL; break; case '\'': eatingChars = !eatingChars; doubleQuote = true; break; case '@': if (ignoreChars) throw new ParseException( "comparison list has not yet been started. You may only use" + "(<,;=&)", i + base_offset); // Inverse the order of secondaries from now on. nextIsModifier = true; type = CollationSorter.INVERSE_SECONDARY; break; case '&': type = CollationSorter.RESET; if (stop_on_reset) break main_parse_loop; break; default: if (operator < 0) throw new ParseException("operator missing at " + (i + base_offset), i + base_offset); if (!eatingChars && ((c >= 0x21 && c <= 0x2F) || (c >= 0x3A && c <= 0x40) || (c >= 0x5B && c <= 0x60) || (c >= 0x7B && c <= 0x7E))) throw new ParseException("unquoted punctuation character '" + c + "'", i + base_offset); // type = ignoreChars ? CollationSorter.IGNORE : -1; sb.append(c); break; } if (type < 0) continue; if (operator < 0) { operator = type; continue; } if (sb.length() == 0 && !isModifier) throw new ParseException("text element empty at " + (i + base_offset), i + base_offset); if (operator == CollationSorter.RESET) { /* Reposition in the sorting list at the position * indicated by the text element. */ String subrules = rules.substring(i); ArrayList sorted_rules = new ArrayList(); int idx; // Parse the subrules but do not iterate through all // sublist. This is the priviledge of the first call. idx = subParseString(true, sorted_rules, base_offset + i, subrules); // Merge new parsed rules into the list. mergeRules(base_offset + i, sb.toString(), v, sorted_rules); sb.setLength(0); // Reset state to none. operator = -1; type = -1; // We have found a new subrule at 'idx' but it has not been parsed. if (idx >= 0) { i += idx - 1; continue main_parse_loop; } else // No more rules. break main_parse_loop; } CollationSorter sorter = new CollationSorter(); if (operator == CollationSorter.GREATERP) ignoreChars = false; sorter.comparisonType = operator; sorter.textElement = sb.toString(); sorter.hashText = sorter.textElement.hashCode(); sorter.offset = base_offset + rules.length(); sorter.ignore = ignoreChars; sb.setLength(0); v.add(sorter); operator = type; } if (operator >= 0) { CollationSorter sorter = new CollationSorter(); int pos = rules.length() + base_offset; if ((sb.length() != 0 && nextIsModifier) || (sb.length() == 0 && !nextIsModifier && !eatingChars)) throw new ParseException("text element empty at " + pos, pos); if (operator == CollationSorter.GREATERP) ignoreChars = false; sorter.comparisonType = operator; sorter.textElement = sb.toString(); sorter.hashText = sorter.textElement.hashCode(); sorter.offset = base_offset + pos; sorter.ignore = ignoreChars; v.add(sorter); } if (i == rules.length()) return -1; else return i; }