Mercurial > hg > monetdb-java
comparison src/main/java/nl/cwi/monetdb/util/CmdLineOpts.java @ 0:a5a898f6886c
Copy of MonetDB java directory changeset e6e32756ad31.
author | Sjoerd Mullender <sjoerd@acm.org> |
---|---|
date | Wed, 21 Sep 2016 09:34:48 +0200 (2016-09-21) |
parents | |
children | 57978db4ee57 17fbaf2635bb |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a5a898f6886c |
---|---|
1 /* | |
2 * This Source Code Form is subject to the terms of the Mozilla Public | |
3 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
5 * | |
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. | |
7 */ | |
8 | |
9 package nl.cwi.monetdb.util; | |
10 | |
11 import java.util.*; | |
12 import java.io.*; | |
13 | |
14 public class CmdLineOpts { | |
15 /** the arguments we handle */ | |
16 private Map<String, OptionContainer> opts = new HashMap<String, OptionContainer>(); | |
17 /** the options themself */ | |
18 private List<OptionContainer> options = new ArrayList<OptionContainer>(); | |
19 | |
20 /** no arguments */ | |
21 public static int CAR_ZERO = 0; | |
22 /** always one argument */ | |
23 public static int CAR_ONE = 1; | |
24 /** zero or one argument */ | |
25 public static int CAR_ZERO_ONE = 2; | |
26 /** zero or many arguments */ | |
27 public static int CAR_ZERO_MANY = 3; | |
28 /** one or many arguments */ | |
29 public static int CAR_ONE_MANY = 4; | |
30 | |
31 public CmdLineOpts() { | |
32 } | |
33 | |
34 public void addOption( | |
35 String shorta, | |
36 String longa, | |
37 int type, | |
38 String defaulta, | |
39 String descriptiona) | |
40 throws OptionsException { | |
41 OptionContainer oc = | |
42 new OptionContainer( | |
43 shorta, | |
44 longa, | |
45 type, | |
46 defaulta, | |
47 descriptiona | |
48 ); | |
49 if (shorta != null) opts.put(shorta, oc); | |
50 if (longa != null) opts.put(longa, oc); | |
51 } | |
52 | |
53 public void removeOption(String name) { | |
54 OptionContainer oc = opts.get(name); | |
55 if (oc != null) { | |
56 opts.remove(oc.shorta); | |
57 opts.remove(oc.longa); | |
58 } | |
59 } | |
60 | |
61 public OptionContainer getOption(String key) throws OptionsException { | |
62 OptionContainer ret = opts.get(key); | |
63 if (ret == null) throw | |
64 new OptionsException("No such option: " + key); | |
65 | |
66 return ret; | |
67 } | |
68 | |
69 public void processFile(File file) throws OptionsException { | |
70 // the file is there, parse it and set its settings | |
71 Properties prop = new Properties(); | |
72 try { | |
73 FileInputStream in = new FileInputStream(file); | |
74 try { | |
75 prop.load(in); | |
76 } finally { | |
77 in.close(); | |
78 } | |
79 | |
80 for (Enumeration<?> e = prop.propertyNames(); e.hasMoreElements(); ) { | |
81 String key = (String) e.nextElement(); | |
82 OptionContainer option = opts.get(key); | |
83 if (option == null) throw | |
84 new OptionsException("Unknown option: " + key); | |
85 option.resetArguments(); | |
86 option.addArgument(prop.getProperty(key)); | |
87 } | |
88 } catch (IOException e) { | |
89 // well... then forget about it | |
90 } | |
91 } | |
92 | |
93 public void processArgs(String args[]) throws OptionsException { | |
94 // parse and set the command line arguments | |
95 OptionContainer option = null; | |
96 int quant = -1; | |
97 int qcount = 0; | |
98 boolean moreData = false; | |
99 for (int i = 0; i < args.length; i++) { | |
100 if (option == null) { | |
101 if (args[i].charAt(0) != '-') throw | |
102 new OptionsException("Unexpected value: " + args[i]); | |
103 | |
104 // see what kind of argument we have | |
105 if (args[i].length() == 1) | |
106 throw new OptionsException("Illegal argument: '-'"); | |
107 if (args[i].charAt(1) == '-') { | |
108 // we have a long argument | |
109 // since we don't accept inline values we can take | |
110 // everything left in the string as argument, unless | |
111 // there is a = in there... | |
112 String tmp = args[i].substring(2); | |
113 int pos = tmp.indexOf('='); | |
114 if (pos == -1) { | |
115 option = opts.get(tmp); | |
116 moreData = false; | |
117 } else { | |
118 option = opts.get(tmp.substring(0, pos)); | |
119 // modify the option a bit so the code below | |
120 // handles the moreData correctly | |
121 args[i] = "-?" + tmp.substring(pos + 1); | |
122 moreData = true; | |
123 } | |
124 } else if (args[i].charAt(1) == 'X') { | |
125 // extra argument, same as long argument | |
126 String tmp = args[i].substring(1); | |
127 int pos = tmp.indexOf('='); | |
128 if (pos == -1) { | |
129 option = opts.get(tmp); | |
130 moreData = false; | |
131 } else { | |
132 option = opts.get(tmp.substring(0, pos)); | |
133 // modify the option a bit so the code below | |
134 // handles the moreData correctly | |
135 args[i] = "-?" + tmp.substring(pos + 1); | |
136 moreData = true; | |
137 } | |
138 } else { | |
139 // single char argument | |
140 option = opts.get("" + args[i].charAt(1)); | |
141 // is there more data left in the argument? | |
142 moreData = args[i].length() > 2 ? true : false; | |
143 } | |
144 | |
145 if (option != null) { | |
146 // make sure we overwrite previously set arguments | |
147 option.resetArguments(); | |
148 int card = option.getCardinality(); | |
149 if (card == CAR_ONE) { | |
150 if (moreData) { | |
151 option.addArgument(args[i].substring(2)); | |
152 option = null; | |
153 } else { | |
154 quant = 1; | |
155 } | |
156 } else if (card == CAR_ZERO_ONE) { | |
157 option.setPresent(); | |
158 qcount = 1; | |
159 quant = 2; | |
160 if (moreData) { | |
161 option.addArgument(args[i].substring(2)); | |
162 option = null; | |
163 } | |
164 } else if (card == CAR_ZERO_MANY) { | |
165 option.setPresent(); | |
166 qcount = 1; | |
167 quant = -1; | |
168 if (moreData) { | |
169 option.addArgument(args[i].substring(2)); | |
170 qcount++; | |
171 } | |
172 } else if (card == CAR_ZERO) { | |
173 option.setPresent(); | |
174 option = null; | |
175 } | |
176 } else { | |
177 throw new OptionsException("Unknown argument: " + args[i]); | |
178 } | |
179 } else { | |
180 // store the `value' | |
181 option.addArgument(args[i]); | |
182 if (++qcount == quant) { | |
183 quant = 0; | |
184 qcount = 0; | |
185 option = null; | |
186 } | |
187 } | |
188 } | |
189 } | |
190 | |
191 /** | |
192 * Returns a help message for all options loaded. | |
193 * | |
194 * @return the help message | |
195 */ | |
196 public String produceHelpMessage() { | |
197 // first calculate how much space is necessary for the options | |
198 int maxlen = 0; | |
199 for (OptionContainer oc : options) { | |
200 String shorta = oc.getShort(); | |
201 String longa = oc.getLong(); | |
202 int len = 0; | |
203 if (shorta != null) len += shorta.length() + 1 + 1; | |
204 if (longa != null) len += longa.length() + 1 + (longa.charAt(0) == 'X' ? 0 : 1) + 1; | |
205 // yes, we don't care about branch mispredictions here ;) | |
206 if (maxlen < len) maxlen = len; | |
207 } | |
208 | |
209 // get the individual strings | |
210 StringBuilder ret = new StringBuilder(); | |
211 for (OptionContainer oc : options) { | |
212 ret.append(produceHelpMessage(oc, maxlen)); | |
213 } | |
214 | |
215 return ret.toString(); | |
216 } | |
217 | |
218 /** | |
219 * Returns the help message for the given OptionContainer. The | |
220 * command line flags will be padded to optwidth spaces to allow for | |
221 * aligning. The description of the flags will be wrapped at 80 | |
222 * characters. | |
223 * | |
224 * @param oc the OptionContainer | |
225 * @param indentwidth padding width for the command line flags | |
226 * @return the help message for the option | |
227 */ | |
228 public String produceHelpMessage(OptionContainer oc, int indentwidth) { | |
229 String desc = oc.getDescription(); | |
230 if (desc == null) return ""; | |
231 | |
232 String shorta = oc.getShort(); | |
233 String longa = oc.getLong(); | |
234 int optwidth = 0; | |
235 if (shorta != null) optwidth += shorta.length() + 1 + 1; | |
236 if (longa != null) optwidth += longa.length() + 1 + (longa.charAt(0) == 'X' ? 0 : 1) + 1; | |
237 int descwidth = 80 - indentwidth; | |
238 | |
239 // default to with of command line flags if no width given | |
240 if (indentwidth <= 0) indentwidth = optwidth; | |
241 | |
242 StringBuilder ret = new StringBuilder(); | |
243 | |
244 // add the command line flags | |
245 if (shorta != null) ret.append('-').append(shorta).append(' '); | |
246 if (longa != null) { | |
247 ret.append('-'); | |
248 if (longa.charAt(0) != 'X') ret.append('-'); | |
249 ret.append(longa).append(' '); | |
250 } | |
251 | |
252 for (int i = optwidth; i < indentwidth; i++) ret.append(' '); | |
253 // add the description, wrap around words | |
254 int pos = 0, lastpos = 0; | |
255 while (pos < desc.length()) { | |
256 pos += descwidth; | |
257 if (lastpos != 0) { | |
258 for (int i = 0; i < indentwidth; i++) ret.append(' '); | |
259 } | |
260 if (pos >= desc.length()) { | |
261 ret.append(desc.substring(lastpos)).append('\n'); | |
262 break; | |
263 } | |
264 int space; | |
265 for (space = pos; desc.charAt(space) != ' '; space--) { | |
266 if (space == 0) { | |
267 space = pos; | |
268 break; | |
269 } | |
270 } | |
271 pos = space; | |
272 ret.append(desc.substring(lastpos, pos)).append('\n'); | |
273 while (desc.charAt(pos) == ' ') pos++; | |
274 lastpos = pos; | |
275 } | |
276 | |
277 return ret.toString(); | |
278 } | |
279 | |
280 public class OptionContainer { | |
281 int cardinality; | |
282 String shorta; | |
283 String longa; | |
284 List<String> values = new ArrayList<String>(); | |
285 String name; | |
286 String defaulta; | |
287 String descriptiona; | |
288 boolean present; | |
289 | |
290 public OptionContainer( | |
291 String shorta, | |
292 String longa, | |
293 int cardinality, | |
294 String defaulta, | |
295 String descriptiona) | |
296 throws IllegalArgumentException | |
297 { | |
298 this.cardinality = cardinality; | |
299 this.shorta = shorta; | |
300 this.longa = longa; | |
301 this.defaulta = defaulta; | |
302 this.descriptiona = descriptiona; | |
303 this.present = false; | |
304 | |
305 if (cardinality != CAR_ZERO && | |
306 cardinality != CAR_ONE && | |
307 cardinality != CAR_ZERO_ONE && | |
308 cardinality != CAR_ZERO_MANY && | |
309 cardinality != CAR_ONE_MANY) | |
310 throw new IllegalArgumentException("unknown cardinality"); | |
311 if (shorta != null && shorta.length() != 1) throw | |
312 new IllegalArgumentException("short option should consist of exactly one character"); | |
313 if (shorta == null && longa == null) throw | |
314 new IllegalArgumentException("either a short or long argument should be given"); | |
315 if ((cardinality == CAR_ZERO || | |
316 cardinality == CAR_ZERO_ONE || | |
317 cardinality == CAR_ZERO_MANY) && | |
318 defaulta != null) { | |
319 throw new IllegalArgumentException("cannot specify a default for a (possible) zero argument option"); | |
320 } | |
321 | |
322 name = (longa != null) ? longa : shorta; | |
323 | |
324 options.add(this); | |
325 } | |
326 | |
327 public void resetArguments() { | |
328 values.clear(); | |
329 } | |
330 | |
331 public void addArgument(String val) throws OptionsException { | |
332 if (cardinality == CAR_ZERO) { | |
333 throw new OptionsException("option " + name + " does not allow arguments"); | |
334 } else if ((cardinality == CAR_ONE || | |
335 cardinality == CAR_ZERO_ONE) && | |
336 values.size() >= 1) { | |
337 throw new OptionsException("option " + name + " does at max allow only one argument"); | |
338 } | |
339 // we can add it | |
340 values.add(val); | |
341 setPresent(); | |
342 } | |
343 | |
344 public void setPresent() { | |
345 present = true; | |
346 } | |
347 | |
348 public boolean isPresent() { | |
349 return present; | |
350 } | |
351 | |
352 public int getCardinality() { | |
353 return cardinality; | |
354 } | |
355 | |
356 public int getArgumentCount() { | |
357 return values.size(); | |
358 } | |
359 | |
360 public String getArgument() { | |
361 String ret = getArgument(1); | |
362 if (ret == null) ret = defaulta; | |
363 return ret; | |
364 } | |
365 | |
366 public String getArgument(int index) { | |
367 String[] args = getArguments(); | |
368 if (index < 1 || index > args.length) return null; | |
369 return args[index - 1]; | |
370 } | |
371 | |
372 public String[] getArguments() { | |
373 return values.toArray(new String[values.size()]); | |
374 } | |
375 | |
376 public String getShort() { | |
377 return shorta; | |
378 } | |
379 | |
380 public String getLong() { | |
381 return longa; | |
382 } | |
383 | |
384 public String getDescription() { | |
385 return descriptiona; | |
386 } | |
387 } | |
388 } |