001: /*
002: * Project: AMODA - Abstract Modeled Application
003: * Class: de.gulden.framework.amoda.environment.commandline.CommandLineArgsParser
004: * Version: snapshot-beautyj-1.1
005: *
006: * Date: 2004-09-29
007: *
008: * This is a snapshot version of the AMODA 0.2 development branch,
009: * it is not released as a seperate version.
010: * For AMODA, see http://amoda.berlios.de/.
011: *
012: * This is licensed under the GNU Lesser General Public License (LGPL)
013: * and comes with NO WARRANTY.
014: *
015: * Author: Jens Gulden
016: * Email: amoda@jensgulden.de
017: */
018:
019: package de.gulden.framework.amoda.environment.commandline;
020:
021: import de.gulden.framework.amoda.generic.core.AbstractArgsParser;
022: import de.gulden.framework.amoda.generic.data.GenericValue;
023: import de.gulden.framework.amoda.generic.option.*;
024: import de.gulden.framework.amoda.model.data.*;
025: import de.gulden.framework.amoda.model.data.Value;
026: import java.lang.*;
027: import java.util.*;
028:
029: /**
030: * Class CommandLineArgsParser.
031: *
032: * @author Jens Gulden
033: * @version snapshot-beautyj-1.1
034: */
035: public class CommandLineArgsParser extends AbstractArgsParser {
036:
037: // ------------------------------------------------------------------------
038: // --- fields ---
039: // ------------------------------------------------------------------------
040:
041: protected String[] args;
042:
043: protected int index;
044:
045: // ------------------------------------------------------------------------
046: // --- constructor ---
047: // ------------------------------------------------------------------------
048:
049: public CommandLineArgsParser(String[] args) {
050: this .args = args;
051: index = 0;
052: }
053:
054: // ------------------------------------------------------------------------
055: // --- methods ---
056: // ------------------------------------------------------------------------
057:
058: public void parseOptions(GenericOptions options) {
059: // format: -option1[=][value] -option2[=][value] ...
060: if (args.length > 0) {
061: int index = 0;
062: String a = args[0];
063: while (a != null) {
064: if ((a.startsWith("-")) && (a.length() >= 2)) {
065: boolean useShortcut = (a.charAt(1) != '-'); // no shortcut if second '-'
066: a = a.substring(useShortcut ? 1 : 2); // remove leading '-' or '--'
067: index++;
068: int eqPos = a.indexOf('=');
069: String possibleValue;
070: if (eqPos == -1) { // not separated by '=', so value _maybe_ follows in next arg (boolean values may have no following value but are implicitly set to true if occurring)
071: if (index < args.length) {
072: possibleValue = args[index];
073: } else {
074: possibleValue = null;
075: }
076: } else {
077: possibleValue = a.substring(eqPos + 1); // (is already known value, not only 'possible')
078: a = a.substring(0, eqPos);
079: }
080: if (getSingleArgParser().parseIndividualOption(a,
081: useShortcut, possibleValue, options)
082: && (eqPos == -1)) { //... increase index only value followed and if value wasn't given after '='
083: index++; // parseOptionInternal returns true if possibleValue has been consumed
084: }
085: this .index = index; // candidate for input values, if no more options follow
086: } else { // not an option: ignore
087: index++;
088: }
089: if (index < args.length) {
090: a = args[index];
091: } else {
092: a = null;
093: }
094: }
095: }
096: }
097:
098: public Collection parseBatchCommands(Collection availableCommands) {
099: // start with first arg, either full-name or shortcut feature name
100: // (when shortcuts used, multiple ones per arg are allowed)
101: // stop parsing when first unknown
102: Collection c = new ArrayList();
103: Map byId = new HashMap();
104: Map byShortcut = new HashMap();
105:
106: for (Iterator it = availableCommands.iterator(); it.hasNext();) {
107: de.gulden.framework.amoda.generic.core.GenericFeature f = (de.gulden.framework.amoda.generic.core.GenericFeature) it
108: .next();
109: byId.put(f.getId(), f);
110: String sc = f.getShortcut();
111: if (sc != null) {
112: byShortcut.put(sc, f);
113: }
114: }
115:
116: // parse
117: while (this .index < this .args.length) {
118: String a = this .args[this .index];
119: de.gulden.framework.amoda.generic.core.GenericFeature f = (de.gulden.framework.amoda.generic.core.GenericFeature) byId
120: .get(a);
121: if (f != null) { // given by full id
122: c.add(f);
123: } else { // shortcuts?
124: // each entry may consist of multiple letters - accept only if all are valid commands
125: int charindex = 0;
126: Collection tempC = new ArrayList();
127: while (charindex < a.length()) {
128: String id = a.substring(charindex, charindex + 1);
129: f = (de.gulden.framework.amoda.generic.core.GenericFeature) byShortcut
130: .get(id);
131: if (f == null) { // not a feature
132: return c; // break here, return result so far, index stays on current
133: } else { // single feature found
134: tempC.add(f);
135: }
136: charindex++;
137: }
138: // now it is sure that all commands are valid, so copy them
139: c.addAll(tempC);
140: }
141: this .index++;
142: }
143: if (c.isEmpty()) {
144: Object defaultCommand = byId.get("default");
145: if (defaultCommand != null) {
146: c.add(defaultCommand);
147: }
148: }
149: return c;
150: }
151:
152: public Value[] parseInputValues() {
153: // parseOptions and parseBatchCommands must have been called before
154: de.gulden.framework.amoda.model.data.Value[] values = new de.gulden.framework.amoda.model.data.Value[args.length
155: - this .index];
156: for (int i = 0; i < values.length; i++) {
157: values[i] = new de.gulden.framework.amoda.generic.data.GenericValue(
158: args[this .index + i]);
159: }
160: return values;
161: }
162:
163: public boolean parseIndividualOption(String name,
164: boolean useShortcut, String suggestedValue,
165: GenericOptions options) {
166: // useShortcut is ignored, both names (id or shortcut) are possible
167: boolean result;
168: de.gulden.framework.amoda.model.option.OptionEntry o;
169: try {
170: o = options.getOptionEntry(name); // IllegalOptionError if unknown option
171: } catch (de.gulden.framework.amoda.model.option.IllegalOptionError ioe) {
172: // try shortcut
173: Object oo = options.getByShortcut(name, true);
174: if ((oo == null)
175: || (!(oo instanceof de.gulden.framework.amoda.model.option.OptionEntry))) {
176: if (options.getApplication().getOptions().getBoolean(
177: "error-on-unknown-option")) {
178: options.getApplication()
179: .error(
180: "unknown option '"
181: + ioe.getMessage() + "'");
182: }
183: return false;
184: } else {
185: o = (de.gulden.framework.amoda.model.option.OptionEntry) oo;
186: }
187: }
188: Class type = o.getType();
189: String v;
190: if (!Boolean.class.isAssignableFrom(type)) { // normal case: non-boolean (value always follows)
191: if (suggestedValue == null) {
192: throw new de.gulden.framework.amoda.model.option.IllegalOptionError(
193: "value for option " + name
194: + " must be specified");
195: } else {
196: v = suggestedValue;
197: result = true; // use up suggestedValue
198: }
199: } else {
200: // boolean, maybe value follows (if no value follows, assume TRUE)
201: if (suggestedValue != null) {
202: if ((GenericValue
203: .isBooleanLiteral(true, suggestedValue) || GenericValue
204: .isBooleanLiteral(false, suggestedValue))) {
205: v = suggestedValue;
206: result = true;
207: } else {
208: v = "true";
209: result = false;
210: }
211: } else {
212: v = "true";
213: result = false;
214: }
215: }
216: ((GenericValue) o.getValue(GenericOptions.STATE_CURRENT))
217: .parseString(v);
218: return result;
219: }
220:
221: } // end CommandLineArgsParser
|