001: /* Soot - a J*va Optimization Framework
002: * Copyright (C) 2003 John Jorgensen
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the
016: * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
017: * Boston, MA 02111-1307, USA.
018: */
019:
020: package soot.util.cfgcmd;
021:
022: import soot.G;
023: import soot.CompilationDeathException;
024:
025: /**
026: * A class used by CFG utilities that need to match different option
027: * strings with classes that implement those options.
028: *
029: * A <code>CFGOptionMatcher</code> maintains a set of named
030: * options, and provides a means for matching abbreviated option
031: * values against those names.
032: */
033:
034: public class CFGOptionMatcher {
035:
036: /**
037: * The type stored within a <code>CFGOptionMatcher</code>. Options to
038: * be stored in a <code>CFGOptionMatcher</code> must extend this
039: * class.
040: */
041: public static abstract class CFGOption {
042: private final String name;
043:
044: protected CFGOption(String name) {
045: this .name = name;
046: }
047:
048: public String name() {
049: return name;
050: }
051: };
052:
053: private CFGOption[] options;
054:
055: /**
056: * Creates a CFGOptionMatcher.
057: *
058: * @param options The set of command options to be stored.
059: */
060: public CFGOptionMatcher(CFGOption[] options) {
061: this .options = options;
062: }
063:
064: /**
065: * Searches the options in this <code>CFGOptionMatcher</code>
066: * looking for one whose name begins with the passed string
067: * (ignoring the case of letters in the string).
068: *
069: * @param quarry The string to be matched against the stored
070: * option names.
071: *
072: * @return The matching {@link CFGOption}, if exactly one of the
073: * stored option names begins with <code>quarry</code>.
074: *
075: * @throws soot.CompilationDeathException if <code>quarry</code>
076: * matches none of the option names, or if it matches more than
077: * one.
078: */
079: public CFGOption match(String quarry)
080: throws soot.CompilationDeathException {
081: String uncasedQuarry = quarry.toLowerCase();
082: int match = -1;
083: for (int i = 0; i < options.length; i++) {
084: String uncasedName = options[i].name().toLowerCase();
085: if (uncasedName.startsWith(uncasedQuarry)) {
086: if (match == -1) {
087: match = i;
088: } else {
089: G.v().out.println(quarry
090: + " is ambiguous; it matches "
091: + options[match].name() + " and "
092: + options[i].name());
093: throw new CompilationDeathException(
094: CompilationDeathException.COMPILATION_ABORTED,
095: "Option parse error");
096: }
097: }
098: }
099: if (match == -1) {
100: G.v().out.println("\"" + quarry + "\""
101: + " does not match any value.");
102: throw new CompilationDeathException(
103: CompilationDeathException.COMPILATION_ABORTED,
104: "Option parse error");
105: } else {
106: return options[match];
107: }
108: }
109:
110: /**
111: * Returns a string containing the names of all the
112: * options in this <code>CFGOptionMatcher</code>, separated by
113: * '|' characters. The string is intended for use in
114: * help messages.
115: *
116: * @param initialIndent The number of blank spaces to insert at the
117: * beginning of the returned string. Ignored if
118: * negative.
119: *
120: * @param rightMargin If positive, newlines will be inserted to try
121: * to keep the length of each line in the
122: * returned string less than or equal to
123: * <code>rightMargin</code>.
124: *
125: * @param hangingIndent If positive, this number of spaces will be
126: * inserted immediately after each newline
127: * inserted to respect the <code>rightMargin</code>.
128: */
129: public String help(int initialIndent, int rightMargin,
130: int hangingIndent) {
131:
132: StringBuffer newLineBuf = new StringBuffer(2 + rightMargin);
133: newLineBuf.append('\n');
134: if (hangingIndent < 0) {
135: hangingIndent = 0;
136: }
137: for (int i = 0; i < hangingIndent; i++) {
138: newLineBuf.append(' ');
139: }
140: String newLine = newLineBuf.toString();
141:
142: StringBuffer result = new StringBuffer();
143: int lineLength = 0;
144: for (int i = 0; i < initialIndent; i++) {
145: lineLength++;
146: result.append(' ');
147: }
148:
149: for (int i = 0; i < options.length; i++) {
150: if (i > 0) {
151: result.append('|');
152: lineLength++;
153: }
154: String name = options[i].name();
155: int nameLength = name.length();
156: if ((lineLength + nameLength) > rightMargin) {
157: result.append(newLine);
158: lineLength = hangingIndent;
159: }
160: result.append(name);
161: lineLength += nameLength;
162: }
163: return result.toString();
164: }
165: }
|