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 }