]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/tools/misc/src/com/ibm/icu/dev/tool/UOption.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / tools / misc / src / com / ibm / icu / dev / tool / UOption.java
1 /*\r
2 **********************************************************************\r
3 * Copyright (c) 2002-2004, International Business Machines\r
4 * Corporation and others.  All Rights Reserved.\r
5 **********************************************************************\r
6 * Author: Alan Liu\r
7 * Created: November 15 2002\r
8 * Since: ICU 2.4\r
9 **********************************************************************\r
10 */\r
11 package com.ibm.icu.dev.tool;\r
12 \r
13 /**\r
14  * A command-line option.  A UOption specifies the name of an option\r
15  * and whether or not it takes an argument.  It is a mutable object\r
16  * that later contains the option argument, if any, and a boolean\r
17  * flag stating whether the option was seen or not.\r
18  *\r
19  * The static method parseArgs() takes an array of command-line\r
20  * arguments and an array of UOptions and parses the command-line\r
21  * arguments.\r
22  *\r
23  * This deliberately resembles the icu4c file uoption.[ch].\r
24  */\r
25 public class UOption {\r
26 \r
27     // Deliberated public data members\r
28     public String  longName;\r
29     public String  value;\r
30     public Fn      optionFn;\r
31     public Object  context;\r
32     public char    shortName;\r
33     public int     hasArg;\r
34     public boolean doesOccur;\r
35 \r
36     // Values of hasArg\r
37     public static final int NO_ARG       = 0;\r
38     public static final int REQUIRES_ARG = 1;\r
39     public static final int OPTIONAL_ARG = 2;\r
40 \r
41     // Analog of UOptionFn.  We don't pass in the context because the\r
42     // functor can get it from the UOption.\r
43     public interface Fn {\r
44         int handle(UOption option);\r
45     }\r
46 \r
47     /**\r
48      * Create a UOption with the given attributes.\r
49      */\r
50     public static UOption create(String aLongName,\r
51                                 char aShortName,\r
52                                 int hasArgument) {\r
53         return new UOption(aLongName, aShortName, hasArgument);\r
54     }\r
55 \r
56     /**\r
57      * Create a UOption with the given attributes.\r
58      * Synonym for create(), for C compatibility.\r
59      */\r
60     public static UOption DEF(String aLongName,\r
61                               char aShortName,\r
62                               int hasArgument) {\r
63         return create(aLongName, aShortName, hasArgument);\r
64     }\r
65 \r
66     // Standard canned options.  These create a new object when\r
67     // called.  Since the UOption object is mutable, we cannot use\r
68     // static final instances.\r
69     public static UOption HELP_H()             { return create("help", 'h', NO_ARG); }\r
70     public static UOption HELP_QUESTION_MARK() { return create("help", '?', NO_ARG); }\r
71     public static UOption VERBOSE()            { return create("verbose", 'v', NO_ARG); }\r
72     public static UOption QUIET()              { return create("quiet", 'q', NO_ARG); }\r
73     public static UOption VERSION()            { return create("version", 'V', NO_ARG); }\r
74     public static UOption COPYRIGHT()          { return create("copyright", 'c', NO_ARG); }\r
75 \r
76     public static UOption DESTDIR()            { return create("destdir", 'd', REQUIRES_ARG); }\r
77     public static UOption SOURCEDIR()          { return create("sourcedir", 's', REQUIRES_ARG); }\r
78     public static UOption ENCODING()           { return create("encoding", 'e', REQUIRES_ARG); }\r
79     public static UOption ICUDATADIR()         { return create("icudatadir", 'i', REQUIRES_ARG); }\r
80     public static UOption PACKAGE_NAME()       { return create("package-name", 'p', REQUIRES_ARG); }\r
81     public static UOption BUNDLE_NAME()        { return create("bundle-name", 'b', REQUIRES_ARG); }\r
82 \r
83     /**\r
84      * Java Command line argument parser.\r
85      *\r
86      * This function takes the argv[] command line and a description of\r
87      * the program's options in form of an array of UOption structures.\r
88      * Each UOption defines a long and a short name (a string and a character)\r
89      * for options like "--foo" and "-f".\r
90      *\r
91      * Each option is marked with whether it does not take an argument,\r
92      * requires one, or optionally takes one. The argument may follow in\r
93      * the same argv[] entry for short options, or it may always follow\r
94      * in the next argv[] entry.\r
95      *\r
96      * An argument is in the next argv[] entry for both long and short name\r
97      * options, except it is taken from directly behind the short name in\r
98      * its own argv[] entry if there are characters following the option letter.\r
99      * An argument in its own argv[] entry must not begin with a '-'\r
100      * unless it is only the '-' itself. There is no restriction of the\r
101      * argument format if it is part of the short name options's argv[] entry.\r
102      *\r
103      * The argument is stored in the value field of the corresponding\r
104      * UOption entry, and the doesOccur field is set to 1 if the option\r
105      * is found at all.\r
106      *\r
107      * Short name options without arguments can be collapsed into a single\r
108      * argv[] entry. After an option letter takes an argument, following\r
109      * letters will be taken as its argument.\r
110      *\r
111      * If the same option is found several times, then the last\r
112      * argument value will be stored in the value field.\r
113      *\r
114      * For each option, a function can be called. This could be used\r
115      * for options that occur multiple times and all arguments are to\r
116      * be collected.\r
117      *\r
118      * All options are removed from the argv[] array itself. If the parser\r
119      * is successful, then it returns the number of remaining non-option\r
120      * strings.  (Unlike C, the Java argv[] array does NOT contain\r
121      * the program name in argv[0].)\r
122      *\r
123      * An option "--" ends option processing; everything after this\r
124      * remains in the argv[] array.\r
125      *\r
126      * An option string "-" alone is treated as a non-option.\r
127      *\r
128      * If an option is not recognized or an argument missing, then\r
129      * the parser returns with the negative index of the argv[] entry\r
130      * where the error was detected.\r
131      *\r
132      * @param argv this parameter is modified\r
133      * @param start the first argument in argv[] to examine.  Must be\r
134      * 0..argv.length-1.  Arguments from 0..start-1 are ignored.\r
135      * @param options this parameter is modified\r
136      * @return the number of unprocessed arguments in argv[], including\r
137      * arguments 0..start-1.\r
138      */\r
139     public static int parseArgs(String argv[], int start, UOption options[]) {\r
140         String arg;\r
141         int i=start, remaining=start;\r
142         char c;\r
143         boolean stopOptions=false;\r
144 \r
145         while(i<argv.length) {\r
146             arg=argv[i];\r
147             if(!stopOptions && arg.length()>1 && arg.charAt(0)=='-') {\r
148                 /* process an option */\r
149                 c=arg.charAt(1);\r
150                 UOption option=null;\r
151                 arg=arg.substring(2);\r
152                 if(c=='-') {\r
153                     /* process a long option */\r
154                     if(arg.length()==0) {\r
155                         /* stop processing options after "--" */\r
156                         stopOptions=true;\r
157                     } else {\r
158                         /* search for the option string */\r
159                         int j;\r
160                         for(j=0; j<options.length; ++j) {\r
161                             if(options[j].longName != null && arg.equals(options[j].longName)) {\r
162                                 option=options[j];\r
163                                 break;\r
164                             }\r
165                         }\r
166                         if(option==null) {\r
167                             /* no option matches */\r
168                             syntaxError("Unknown option " + argv[i]);\r
169                         }\r
170                         option.doesOccur=true;\r
171 \r
172                         if(option.hasArg!=NO_ARG) {\r
173                             /* parse the argument for the option, if any */\r
174                             if(i+1<argv.length && !(argv[i+1].length()>1 && argv[i+1].charAt(0)=='-')) {\r
175                                 /* argument in the next argv[], and there is not an option in there */\r
176                                 option.value=argv[++i];\r
177                             } else if(option.hasArg==REQUIRES_ARG) {\r
178                                 /* there is no argument, but one is required: return with error */\r
179                                 syntaxError("Option " + argv[i] + " lacks required argument");\r
180                             }\r
181                         }\r
182                     }\r
183                 } else {\r
184                     /* process one or more short options */\r
185                     for (;;) {\r
186                         /* search for the option letter */\r
187                         int j;\r
188                         for(j=0; j<options.length; ++j) {\r
189                             if(c==options[j].shortName) {\r
190                                 option=options[j];\r
191                                 break;\r
192                             }\r
193                         }\r
194                         if(option==null) {\r
195                             /* no option matches */\r
196                             syntaxError("Unknown option '" + c + "' in " + argv[i]);\r
197                         }\r
198                         option.doesOccur=true;\r
199 \r
200                         if(option.hasArg!=NO_ARG) {\r
201                             /* parse the argument for the option, if any */\r
202                             if(arg.length()!=0) {\r
203                                 /* argument following in the same argv[] */\r
204                                 option.value=arg;\r
205                                 /* do not process the rest of this arg as option letters */\r
206                                 break;\r
207                             } else if(i+1<argv.length && !(argv[i+1].length()>1 && argv[i+1].charAt(0)=='-')) {\r
208                                 /* argument in the next argv[], and there is not an option in there */\r
209                                 option.value=argv[++i];\r
210                                 /* this break is redundant because we know that *arg==0 */\r
211                                 break;\r
212                             } else if(option.hasArg==REQUIRES_ARG) {\r
213                                 /* there is no argument, but one is required: return with error */\r
214                                 syntaxError("Option -" + c + " lacks required argument");\r
215                             }\r
216                         }\r
217 \r
218                         /* get the next option letter */\r
219                         option=null;\r
220                         if (arg.length()==0) break;\r
221                         c=arg.charAt(0);\r
222                         arg=arg.substring(1);\r
223                     }\r
224                 }\r
225 \r
226                 if(option!=null && option.optionFn!=null && option.optionFn.handle(option)<0) {\r
227                     /* the option function was called and returned an error */\r
228                     syntaxError("Option handler failed for " + argv[i]);\r
229                 }\r
230 \r
231                 /* go to next argv[] */\r
232                 ++i;\r
233             } else {\r
234                 /* move a non-option up in argv[] */\r
235                 argv[remaining++]=arg;\r
236                 ++i;\r
237             }\r
238         }\r
239         return remaining;\r
240     }\r
241 \r
242     /**\r
243      * Allows the default to be set in an option list.\r
244      * @param s\r
245      * @return this\r
246      */public UOption setDefault(String s) {\r
247         value = s;\r
248         return this;\r
249     }\r
250 \r
251     /**\r
252      * Convenient method.\r
253      */\r
254     public static int parseArgs(String argv[], UOption options[]) {\r
255         return parseArgs(argv, 0, options);\r
256     }\r
257 \r
258     /**\r
259      * Constructor.\r
260      */\r
261     private UOption(String aLongName,\r
262                     char aShortName,\r
263                     int hasArgument) {\r
264         longName = aLongName;\r
265         shortName = aShortName;\r
266         hasArg = hasArgument;\r
267     }\r
268 \r
269     /**\r
270      * Throw an exception indicating a syntax error.\r
271      */\r
272     private static void syntaxError(String message) {\r
273         throw new IllegalArgumentException("Error in argument list: " + message);\r
274     }\r
275 }\r