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