]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/Getopt.java
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / cddl / contrib / opensolaris / cmd / dtrace / test / cmd / jdtrace / Getopt.java
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * ident        "%Z%%M% %I%     %E% SMI"
27  */
28
29 /* Copyright (c) 1988 AT&T */
30 /* All Rights Reserved */
31
32 import java.io.StringWriter;
33 import java.io.PrintWriter;
34
35 /**
36  * A Java port of Solaris {@code lib/libc/port/gen/getopt.c}, which is a
37  * port of System V UNIX getopt.  See <b>getopt(3C)</b> and SUS/XPG
38  * getopt() for function definition and requirements. Unlike that
39  * definition, this implementation moves non-options to the end of the
40  * argv array rather than quitting at the first non-option.
41  */
42 public class Getopt {
43     static final int EOF = -1;
44
45     private String progname;
46     private String[] args;
47     private int argc;
48     private String optstring;
49     private int optind = 0; // args index
50     private int optopt = 0;
51     private String optarg = null;
52     private boolean opterr = true;
53
54     /*
55      * _sp is required to keep state between successive calls to
56      * getopt() while extracting aggregated short-options (ie: -abcd).
57      */
58     private int _sp = 1;
59
60     /**
61      * Creates a {Code Getopt} instance to parse the given command-line
62      * arguments. Modifies the given args array by swapping the
63      * positions of non-options and options so that non-options appear
64      * at the end of the array.
65      */
66     public Getopt(String programName, String[] args,
67             String optionString)
68     {
69         progname = programName;
70         // No defensive copy; Getopt is expected to modify the given
71         // args array
72         this.args = args;
73         argc = this.args.length;
74         optstring = optionString;
75         validate();
76     }
77
78     private void
79     validate()
80     {
81         if (progname == null) {
82             throw new NullPointerException("program name is null");
83         }
84         int i = 0;
85         for (String s : args) {
86             if (s == null) {
87                 throw new NullPointerException("null arg at index " + i);
88             }
89             ++i;
90         }
91         if (optstring == null) {
92             throw new NullPointerException("option string is null");
93         }
94     }
95
96     private static class StringRef {
97         private String s;
98
99         public String
100         get()
101         {
102             return s;
103         }
104
105         public StringRef
106         set(String value)
107         {
108             s = value;
109             return this;
110         }
111     }
112
113     /*
114      * Generalized error processing method. If the optstr parameter is
115      * null, the character c is converted to a string and displayed
116      * instead.
117      */
118     void
119     err(String format, char c, String optstr)
120     {
121         if (opterr && optstring.charAt(0) != ':') {
122             StringWriter w = new StringWriter();
123             PrintWriter p = new PrintWriter(w);
124             p.printf(format, progname, (optstr == null ?
125                     Character.toString(c) : optstr.substring(2)));
126             System.err.println(w.toString());
127         }
128     }
129
130     /*
131      * Determine if the specified character (c) is present in the string
132      * (optstring) as a regular, single character option. If the option
133      * is found, return an index into optstring where the short-option
134      * character is found, otherwise return -1. The characters ':' and
135      * '(' are not allowed.
136      */
137     static int
138     parseshort(String optstring, char c)
139     {
140         if (c == ':' || c == '(') {
141             return -1;
142         }
143
144         int ch;
145         int len = optstring.length();
146         for (int i = 0; i < len; ++i) {
147             ch = optstring.charAt(i);
148             if (ch == c) {
149                 return i;
150             }
151
152             while (i < len && ch == '(') {
153                 for (++i; i < len && (ch = optstring.charAt(i)) != ')'; ++i);
154             }
155         }
156
157         return -1;
158     }
159
160     /**
161      * Determine if the specified string (opt) is present in the string
162      * (optstring) as a long-option contained within parenthesis. If the
163      * long-option specifies option-argument, return a reference to it
164      * in longoptarg.  Otherwise set the longoptarg reference to null.
165      * If the option is found, return an index into optstring at the
166      * position of the short-option character associated with the
167      * long-option; otherwise return -1.
168      *
169      * @param optstring the entire optstring passed to the {@code
170      * Getopt} constructor
171      * @param opt the long option read from the command line
172      * @param longoptarg the value of the option is returned in this
173      * parameter, if an option exists. Possible return values in
174      * longoptarg are:
175      * <ul>
176      * <li><b>NULL:</b> No argument was found</li>
177      * <li><b>empty string (""):</b> Argument was explicitly left empty
178      * by the user (e.g., --option= )</li>
179      * <li><b>valid string:</b> Argument found on the command line</li>
180      * </ul>
181      * @return index to equivalent short-option in optstring, or -1 if
182      * option not found in optstring.
183      */
184     static int
185     parselong(String optstring, String opt, StringRef longoptarg)
186     {
187         int cp; // index into optstring, beginning of one option spec
188         int ip; // index into optstring, traverses every char
189         char ic; // optstring char
190         int il; // optstring length
191         int op; // index into opt
192         char oc; // opt char
193         int ol; // opt length
194         boolean match; // true if opt is matching part of optstring
195
196         longoptarg.set(null);
197         cp = ip = 0;
198         il = optstring.length();
199         ol = opt.length();
200         do {
201             ic = optstring.charAt(ip);
202             if (ic != '(' && ++ip == il)
203                 break;
204             ic = optstring.charAt(ip);
205             if (ic == ':' && ++ip == il)
206                 break;
207             ic = optstring.charAt(ip);
208             while (ic == '(') {
209                 if (++ip == il)
210                     break;
211                 op = 0;
212                 match = true;
213                 while (ip < il && (ic = optstring.charAt(ip)) != ')' &&
214                         op < ol) {
215                     oc = opt.charAt(op++);
216                     match = (ic == oc && match);
217                     ++ip;
218                 }
219
220                 if (match && ip < il && ic == ')' && (op >= ol ||
221                         opt.charAt(op) == '=')) {
222                     if (op < ol && opt.charAt(op) == '=') {
223                         /* may be an empty string - OK */
224                         longoptarg.set(opt.substring(op + 1));
225                     } else {
226                         longoptarg.set(null);
227                     }
228                     return cp;
229                 }
230                 if (ip < il && ic == ')' && ++ip == il)
231                     break;
232                 ic = optstring.charAt(ip);
233             }
234             cp = ip;
235             /*
236              * Handle double-colon in optstring ("a::(longa)") The old
237              * getopt() accepts it and treats it as a required argument.
238              */
239             while ((cp > 0) && (cp < il) && (optstring.charAt(cp) == ':')) {
240                 --cp;
241             }
242         } while (cp < il);
243         return -1;
244     }
245
246     /**
247      * Get the current option value.
248      */
249     public String
250     getOptarg()
251     {
252         return optarg;
253     }
254
255     /**
256      * Get the index of the next option to be parsed.
257      */
258     public int
259     getOptind()
260     {
261         return optind;
262     }
263
264     /**
265      * Gets the command-line arguments.
266      */
267     public String[]
268     getArgv()
269     {
270         // No defensive copy: Getopt is expected to modify the given
271         // args array.
272         return args;
273     }
274
275     /**
276      * Gets the aggregated short option that just failed. Since long
277      * options can't be aggregated, a failed long option can be obtained
278      * by {@code getArgv()[getOptind() - 1]}.
279      */
280     public int
281     getOptopt()
282     {
283         return optopt;
284     }
285
286     /**
287      * Set to {@code false} to suppress diagnostic messages to stderr.
288      */
289     public void
290     setOpterr(boolean err)
291     {
292         opterr = err;
293     }
294
295     /**
296      * Gets the next option character, or -1 if there are no more
297      * options. If getopt() encounters a short-option character or a
298      * long-option string not described in the {@code optionString}
299      * argument to the constructor, it returns the question-mark (?)
300      * character. If it detects a missing option-argument, it also
301      * returns the question-mark (?) character, unless the first
302      * character of the {@code optionString} argument was a colon (:),
303      * in which case getopt() returns the colon (:) character.
304      * <p>
305      * This implementation swaps the positions of options and
306      * non-options in the given argv array.
307      */
308     public int
309     getopt()
310     {
311         char c;
312         int cp;
313         boolean longopt;
314         StringRef longoptarg = new StringRef();
315
316         /*
317          * Has the end of the options been encountered?  The following
318          * implements the SUS requirements:
319          *
320          * If, when getopt() is called:
321          *      - the first character of argv[optind] is not '-'
322          *      - argv[optind] is the string "-"
323          * getopt() returns -1 without changing optind if
324          *      - argv[optind] is the string "--"
325          * getopt() returns -1 after incrementing optind
326          */
327         if (_sp == 1) {
328             boolean nonOption;
329             do {
330                 nonOption = false;
331                 if (optind >= argc || args[optind].equals("-")) {
332                     return EOF;
333                 } else if (args[optind].equals("--")) {
334                     ++optind;
335                     return EOF;
336                 } else if (args[optind].charAt(0) != '-') {
337                     // non-option: here we deviate from the SUS requirements
338                     // by not quitting, and instead move non-options to the
339                     // end of the args array
340                     nonOption = true;
341                     String tmp = args[optind];
342                     if (optind + 1 < args.length) {
343                         System.arraycopy(args, optind + 1, args, optind,
344                                 args.length - (optind + 1));
345                         args[args.length - 1] = tmp;
346                     }
347                     --argc;
348                 }
349             } while (nonOption);
350         }
351
352         /*
353          * Getting this far indicates that an option has been encountered.
354          * Note that the syntax of optstring applies special meanings to
355          * the characters ':' and '(', so they are not permissible as
356          * option letters. A special meaning is also applied to the ')'
357          * character, but its meaning can be determined from context.
358          * Note that the specification only requires that the alnum
359          * characters be accepted.
360          *
361          * If the second character of the argument is a '-' this must be
362          * a long-option, otherwise it must be a short option.  Scan for
363          * the option in optstring by the appropriate algorithm. Either
364          * scan will return an index to the short-option character in
365          * optstring if the option is found and -1 otherwise.
366          *
367          * For an unrecognized long-option, optopt will equal 0, but
368          * since long-options can't aggregate the failing option can be
369          * identified by argv[optind-1].
370          */
371         optopt = c = args[optind].charAt(_sp);
372         optarg = null;
373         longopt = (_sp == 1 && c == '-');
374         if (!(longopt
375                 ? ((cp = parselong(optstring, args[optind].substring(2),
376                 longoptarg)) != -1)
377                 : ((cp = parseshort(optstring, c)) != -1))) {
378             err("%s: illegal option -- %s", c,
379                     (longopt ? args[optind] : null));
380             /*
381              * Note: When the long option is unrecognized, optopt will
382              * be '-' here, which matches the specification.
383              */
384             if (args[optind].length() == ++_sp || longopt) {
385                 ++optind;
386                 _sp = 1;
387             }
388             return '?';
389         }
390         optopt = c = optstring.charAt(cp);
391
392         /*
393          * A valid option has been identified.  If it should have an
394          * option-argument, process that now.  SUS defines the setting
395          * of optarg as follows:
396          *
397          *   1. If the option was the last character in an element of
398          *   argv, then optarg contains the next element of argv, and
399          *   optind is incremented by 2. If the resulting value of
400          *   optind is not less than argc, this indicates a missing
401          *   option-argument, and getopt() returns an error indication.
402          *
403          *   2. Otherwise, optarg points to the string following the
404          *   option character in that element of argv, and optind is
405          *   incremented by 1.
406          *
407          * The second clause allows -abcd (where b requires an
408          * option-argument) to be interpreted as "-a -b cd".
409          *
410          * Note that the option-argument can legally be an empty string,
411          * such as:
412          *      command --option= operand
413          * which explicitly sets the value of --option to nil
414          */
415         if (cp + 1 < optstring.length() && optstring.charAt(cp + 1) == ':') {
416             // The option takes an argument
417             if (!longopt && ((_sp + 1) < args[optind].length())) {
418                 optarg = args[optind++].substring(_sp + 1);
419             } else if (longopt && (longoptarg.get() != null)) {
420                 /*
421                  * The option argument was explicitly set to the empty
422                  * string on the command line (--option=)
423                  */
424                 optind++;
425                 optarg = longoptarg.get();
426             } else if (++optind >= argc) {
427                 err("%s: option requires an argument -- %s", c,
428                         (longopt ? args[optind - 1] : null));
429                 _sp = 1;
430                 optarg = null;
431                 return (optstring.charAt(0) == ':' ? ':' : '?');
432             } else
433                 optarg = args[optind++];
434                 _sp = 1;
435             } else {
436                 // The option does NOT take an argument
437                 if (longopt && (longoptarg.get() != null)) {
438                 // User supplied an arg to an option that takes none
439                 err("%s: option doesn't take an argument -- %s", (char)0,
440                         (longopt ? args[optind] : null));
441                 optarg = longoptarg.set(null).get();
442                 c = '?';
443             }
444
445             if (longopt || args[optind].length() == ++_sp) {
446                 _sp = 1;
447                 ++optind;
448             }
449             optarg = null;
450         }
451         return (c);
452     }
453 }