1 salcianu 1.1 // Option.java, created Wed Apr  9 13:52:03 2003 by salcianu
  2 salcianu 1.1 // Copyright (C) 2003 Alexandru Salcianu <salcianu@MIT.EDU>
  3 salcianu 1.1 // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 salcianu 1.1 package harpoon.Util.Options;
  5 salcianu 1.1 
  6 salcianu 1.1 import java.util.Map;
  7 salcianu 1.1 import java.util.HashMap;
  8 salcianu 1.1 import java.util.List;
  9 salcianu 1.1 import java.util.LinkedList;
 10 salcianu 1.1 import java.util.Iterator;
 11 salcianu 1.1 import java.util.ListIterator;
 12 salcianu 1.1 import java.util.StringTokenizer;
 13 salcianu 1.1 
 14 salcianu 1.1 import java.io.PrintStream;
 15 salcianu 1.1 
 16 salcianu 1.1 /**
 17 salcianu 1.1  * <code>Option</code>
 18 salcianu 1.1  * 
 19 salcianu 1.1  * @author  Alexandru Salcianu <salcianu@MIT.EDU>
 20 cananian 1.4  * @version $Id: Option.java,v 1.4 2004/02/08 03:21:58 cananian Exp $
 21 salcianu 1.1  */
 22 salcianu 1.1 public abstract class Option {
 23 salcianu 1.1 
 24 salcianu 1.1     public Option(String optionName, String argSummary, String optArgSummary,
 25 salcianu 1.1                   String helpMessage) {
 26 salcianu 1.1         this.optionName = optionName;
 27 salcianu 1.1 
 28 salcianu 1.1         if(argSummary == null) argSummary = "";
 29 salcianu 1.1         if(optArgSummary == null) optArgSummary = "";
 30 salcianu 1.1 
 31 salcianu 1.1         StringTokenizer argTokenizer = new StringTokenizer(argSummary);
 32 salcianu 1.1         StringTokenizer optArgTokenizer = new StringTokenizer(optArgSummary);
 33 salcianu 1.1 
 34 salcianu 1.1         this.compArgs = new String[argTokenizer.countTokens()];
 35 salcianu 1.1         this.optArgs  = new String[optArgTokenizer.countTokens()];
 36 salcianu 1.1         this.description = 
 37 salcianu 1.1             buildDescription(optionName, argTokenizer, optArgTokenizer);
 38 salcianu 1.1         this.helpMessage = helpMessage;
 39 salcianu 1.1     }
 40 salcianu 1.1 
 41 salcianu 1.1     public Option(String optionName, String argSummary, String helpMessage) {
 42 salcianu 1.1         this(optionName, argSummary, null, helpMessage);
 43 salcianu 1.1     }
 44 salcianu 1.1 
 45 salcianu 1.1     public Option(String optionName, String helpMessage) {
 46 salcianu 1.1         this(optionName, null, null, helpMessage);
 47 salcianu 1.1     }
 48 salcianu 1.1 
 49 salcianu 1.1     public Option(String optionName) {
 50 salcianu 1.1         this(optionName, null, null, null);
 51 salcianu 1.1     }
 52 salcianu 1.1 
 53 salcianu 1.1     protected final String optionName;
 54 salcianu 1.1     protected final String[] compArgs;
 55 salcianu 1.1     protected final String[] optArgs;
 56 salcianu 1.1     protected final String description;
 57 salcianu 1.1     protected final String helpMessage;
 58 salcianu 1.1 
 59 salcianu 1.1     protected void setArg(int i, String arg) { compArgs[i] = arg; }
 60 salcianu 1.1     public String getArg(int i) { return compArgs[i]; }
 61 salcianu 1.1 
 62 salcianu 1.1     protected void setOptionalArg(int i, String arg) { optArgs[i] = arg; }
 63 salcianu 1.1     public String getOptionalArg(int i) { return optArgs[i]; }
 64 salcianu 1.1 
 65 salcianu 1.1     public String optionName() { return optionName; }
 66 salcianu 1.1     public int numberArgs() { return compArgs.length; }
 67 salcianu 1.1     public int numberOptionalArgs() { return optArgs.length; }
 68 salcianu 1.1     public String description() { return description; }
 69 salcianu 1.1 
 70 salcianu 1.1     public abstract void action();
 71 salcianu 1.1     
 72 salcianu 1.1     public void printHelp(PrintStream ps) {
 73 salcianu 1.1         ps.println(description);
 74 salcianu 1.1         if((helpMessage != null) && (helpMessage.length() > 0)) {
 75 salcianu 1.1             ps.print("\t");
 76 salcianu 1.1             ps.println(helpMessage);
 77 salcianu 1.1         }
 78 salcianu 1.1     }
 79 salcianu 1.1 
 80 salcianu 1.1     public String toString() { return optionName; }
 81 salcianu 1.1 
 82 salcianu 1.1 
 83 salcianu 1.1     private static String buildDescription(String optionName,
 84 salcianu 1.1                                            StringTokenizer argTok,
 85 salcianu 1.1                                            StringTokenizer optArgTok) {
 86 salcianu 1.1         StringBuffer sb = new StringBuffer();
 87 salcianu 1.1 
 88 salcianu 1.2         sb.append("-");
 89 salcianu 1.2         if(optionName.length() > 1)
 90 salcianu 1.2             sb.append("-");
 91 salcianu 1.1         sb.append(optionName);
 92 salcianu 1.1 
 93 salcianu 1.1         if(argTok.countTokens() > 0) {
 94 salcianu 1.1             sb.append(" ");
 95 salcianu 1.1             while(argTok.hasMoreTokens()) {
 96 salcianu 1.1                 sb.append(" ");
 97 salcianu 1.1                 sb.append(argTok.nextToken());
 98 salcianu 1.1             }
 99 salcianu 1.1         }
100 salcianu 1.1 
101 salcianu 1.1         if(optArgTok.countTokens() > 0) {
102 salcianu 1.1             sb.append("  [");
103 salcianu 1.1             while(optArgTok.hasMoreTokens()) {
104 salcianu 1.1                 sb.append(" ");
105 salcianu 1.1                 sb.append(optArgTok.nextToken());
106 salcianu 1.1             }
107 salcianu 1.1             sb.append(" ]");
108 salcianu 1.1         }
109 salcianu 1.1 
110 salcianu 1.1         return sb.toString();
111 salcianu 1.1     }
112 salcianu 1.1 
113 salcianu 1.1 
114 cananian 1.3     public static String[] parseOptions(List<Option> options,
115 salcianu 1.1                                         String[] args) {
116 cananian 1.3         List<String> unparsedArgs = 
117 salcianu 1.1             parseOptions(options, array2list(args));
118 salcianu 1.1         return 
119 cananian 1.3             unparsedArgs.toArray(new String[unparsedArgs.size()]);
120 salcianu 1.1     }
121 salcianu 1.1 
122 salcianu 1.1 
123 cananian 1.3     public static List<String> parseOptions(List<Option> options,
124 cananian 1.3                                                 List<String> args) {
125 salcianu 1.1         
126 cananian 1.3         Map<String,Option> arg2option = new HashMap<String,Option>();
127 cananian 1.4         for(Option option : options) {
128 salcianu 1.1             arg2option.put(option.optionName(), option);
129 salcianu 1.1         }
130 salcianu 1.1 
131 cananian 1.3         List<String> unparsedArgs = new LinkedList<String>();
132 salcianu 1.1 
133 cananian 1.3         for(ListIterator<String> it = args.listIterator(); it.hasNext();) {
134 cananian 1.3             String arg = it.next();
135 salcianu 1.1             if(!isOption(arg) || !arg2option.containsKey(getOption(arg))) {
136 salcianu 1.1                 unparsedArgs.add(arg);
137 salcianu 1.1                 continue;
138 salcianu 1.1             }
139 salcianu 1.1 
140 cananian 1.3             Option option = arg2option.get(getOption(arg));
141 salcianu 1.1             parseOptionArgs(option, it);
142 salcianu 1.1 
143 salcianu 1.1             option.action();
144 salcianu 1.1         }
145 salcianu 1.1         
146 salcianu 1.1         return unparsedArgs;
147 salcianu 1.1     }
148 salcianu 1.1 
149 salcianu 1.1     // checks whether arg is an option (i.e., it starts with a '-')
150 salcianu 1.1     public static boolean isOption(String arg) {
151 salcianu 1.1         return (arg.length() > 0) && (arg.charAt(0) == '-');
152 salcianu 1.1     }
153 salcianu 1.1 
154 salcianu 1.1     // peels off all the '-' characters from the beginning of arg
155 salcianu 1.1     public static String getOption(String arg) {
156 salcianu 1.1         int i = 0; 
157 salcianu 1.1         while((i < arg.length()) && (arg.charAt(i) == '-')) i++;
158 salcianu 1.1         assert i > 0 : arg + " is not an option at all";
159 salcianu 1.1         return arg.substring(i);
160 salcianu 1.1     }
161 salcianu 1.1 
162 salcianu 1.1     private static void parseOptionArgs(Option option,
163 cananian 1.3                                         ListIterator<String> it) {
164 salcianu 1.1         for(int i = 0; i < option.numberArgs(); i++) {
165 salcianu 1.1             String arg = null;
166 cananian 1.3             if(!it.hasNext() || isOption(arg = it.next())) {
167 salcianu 1.1                 System.err.println("Error while parsing argument #" + i +
168 salcianu 1.1                                    " for option " + option);
169 salcianu 1.1                 System.err.println("Help:");
170 salcianu 1.1                 option.printHelp(System.err);
171 salcianu 1.1                 System.exit(1);
172 salcianu 1.1             }
173 salcianu 1.1             option.setArg(i, arg);
174 salcianu 1.1         }
175 salcianu 1.1 
176 salcianu 1.1         for(int i = 0; i < option.numberOptionalArgs(); i++) {
177 salcianu 1.1             if(!it.hasNext()) break;
178 cananian 1.3             String arg = it.next();
179 salcianu 1.1             if(isOption(arg)) {
180 salcianu 1.1                 it.previous(); // put the arg back
181 salcianu 1.1                 return;
182 salcianu 1.1             }
183 salcianu 1.1             option.setOptionalArg(i, arg);
184 salcianu 1.1         }
185 salcianu 1.1     }
186 salcianu 1.1 
187 salcianu 1.1 
188 salcianu 1.1     public static List/*<String>*/ array2list(String[] a) {
189 salcianu 1.1         List/*<String>*/ list = new LinkedList/*<String>*/();
190 salcianu 1.1         for(int i = 0; i < a.length; i++) {
191 salcianu 1.1             if(a[i] != null)
192 salcianu 1.1                 list.add(a[i]);
193 salcianu 1.1         }
194 salcianu 1.1         return list;
195 salcianu 1.1     }
196 salcianu 1.1 
197 salcianu 1.1 
198 salcianu 1.1     public static void main(String[] args) {
199 salcianu 1.1         List/*<Option>*/ options = new LinkedList/*<Option>*/();
200 salcianu 1.1         options.add
201 salcianu 1.1             (new Option("fileoption", "<file>", "File to compile") {
202 salcianu 1.1                 public void action() {
203 salcianu 1.1                     System.out.println("Option " + description());
204 salcianu 1.1                 }});
205 salcianu 1.1         options.add
206 salcianu 1.1             (new Option("fast") {
207 salcianu 1.1                 public void action() {
208 salcianu 1.1                     System.out.println("Option " + description());
209 salcianu 1.1                 }});
210 salcianu 1.1         options.add
211 salcianu 1.1             (new Option("seriousOpt", "<arg1> <arg2>",
212 salcianu 1.1                         "<optArg1> <optArg2> <optArg3>",
213 salcianu 1.1                         "Serious arg!") {
214 salcianu 1.1                 public void action() {
215 salcianu 1.1                     System.out.println("Option " + description());
216 salcianu 1.1                 }});
217 salcianu 1.1 
218 salcianu 1.1         args = parseOptions(options, args);
219 salcianu 1.1 
220 salcianu 1.1         System.out.print("Remaining options: [ ");
221 salcianu 1.1         for (int i = 0; i < args.length; i++)
222 salcianu 1.1             System.out.print(args[i] + " ");
223 salcianu 1.1         System.out.println("]");
224 salcianu 1.1     }
225 salcianu 1.1 
226 salcianu 1.1 }