]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - tools/elftosb/common/options.h
merged tx6dl-devel into denx master branch
[karo-tx-uboot.git] / tools / elftosb / common / options.h
1 // ****************************************************************************
2 // ^FILE: options.h - option parsing classes
3 //
4 // ^DESCRIPTION:
5 //    This file defines classes used to parse command-line options.
6 //    Options may be parsed from an array of strings, or from any structure
7 //    for which a corresponding option-iterator exists.
8 //
9 // ^HISTORY:
10 //    03/06/92  Brad Appleton   <bradapp@enteract.com>   Created
11 //
12 //    03/23/93  Brad Appleton   <bradapp@enteract.com>
13 //    - Added OptIstreamIter class
14 //
15 //    03/08/94  Brad Appleton   <bradapp@enteract.com>
16 //    - Added Options::reset() member function
17 //
18 //    07/31/97  Brad Appleton   <bradapp@enteract.com>
19 //    - Added PARSE_POS control flag and POSITIONAL return value
20 //
21 //        04/30/06  Chris Reed
22 //    - Updated to modern C++ and STL
23 //    - Converted comments to doxygen style
24 // ^^**************************************************************************
25
26 #ifndef _options_h
27 #define _options_h
28
29 #ifdef USE_STDIO
30         #include <stdio.h>
31 #else
32         #include <iostream>
33 #endif
34
35
36 //! Abstract class to iterate through options/arguments
37 //!
38 class OptIter {
39 public:
40    OptIter(void) {}
41    virtual ~OptIter(void);
42
43       //! curr() returns the current item in the iterator without
44       //! advancing on to the next item. If we are at the end of items
45       //! then NULL is returned.
46    virtual const char *
47    curr(void) = 0;
48
49       //! next() advances to the next item.
50    virtual void
51    next(void) = 0;
52
53       //! operator() returns the current item in the iterator and then
54       //! advances on to the next item. If we are at the end of items
55       //! then NULL is returned.
56    virtual const char *
57    operator()(void);
58 } ;
59
60 //! Abstract class for a rewindable OptIter
61 //!
62 class OptIterRwd : public OptIter {
63 public:
64    OptIterRwd(void);
65
66    virtual ~OptIterRwd(void);
67
68    virtual const char *
69    curr(void) = 0;
70
71    virtual void
72    next(void) = 0;
73
74    virtual const char *
75    operator()(void) = 0;
76
77       //! rewind() resets the "current-element" to the first one in the "list"
78    virtual void
79    rewind(void) = 0;
80 } ;
81
82 //! Class to iterate through an array of tokens. The array may be terminated
83 //! by NULL or a count containing the number of tokens may be given.
84 //!
85 class OptArgvIter : public OptIterRwd {
86 private:
87    int            ndx;   // index of current arg
88    int            ac;    // arg count
89    const char * const * av;  // arg vector
90
91 public:
92    OptArgvIter(const char * const argv[])
93       : av(argv), ac(-1), ndx(0) {}
94
95    OptArgvIter(int argc, const char * const argv[])
96       : av(argv), ac(argc), ndx(0) {}
97
98    virtual
99    ~OptArgvIter(void);
100
101    virtual const char *
102    curr(void);
103
104    virtual void
105    next(void);
106
107    virtual const char *
108    operator()(void);
109
110    virtual void
111    rewind(void);
112
113       //! index returns the current index to use for argv[]
114    int index(void)  { return  ndx; }
115 } ;
116
117
118 //! Class to iterate through a string containing delimiter-separated tokens
119 //!
120 class OptStrTokIter : public OptIterRwd {
121 private:
122    unsigned     len;        // length of token-string
123    const char * str;        // the token-string
124    const char * seps;       // delimiter-set (separator-characters)
125    const char * cur;        // current token
126    char       * tokstr;     // our copy of the token-string
127
128    static const char * default_delims;  // default delimiters = whitespace
129
130 public:
131    OptStrTokIter(const char * tokens, const char * delimiters =0);
132
133    virtual
134    ~OptStrTokIter(void);
135
136    virtual const char *
137    curr(void);
138
139    virtual void
140    next(void);
141
142    virtual const char *
143    operator()(void);
144
145    virtual void
146    rewind(void);
147
148       //! delimiters() with NO arguments returns the current set of delimiters,
149       //! If an argument is given then it is used as the new set of delimiters.
150    const char *
151    delimiters(void)  { return  seps; }
152
153    void
154    delimiters(const char * delims) {
155       seps = (delims) ? delims : default_delims ;
156    }
157 } ;
158
159
160 //! OptIstreamIter is a class for iterating over arguments that come
161 //! from an input stream. Each line of the input stream is considered
162 //! to be a set of white-space separated tokens. If the the first
163 //! non-white character on a line is '#' ('!' for VMS systems) then
164 //! the line is considered a comment and is ignored.
165 //!
166 //! \note If a line is more than 1022 characters in length then we
167 //! treat it as if it were several lines of length 1022 or less.
168 //!
169 //! \note The string tokens returned by this iterator are pointers
170 //!         to temporary buffers which may not necessarily stick around
171 //!         for too long after the call to curr() or operator(), hence
172 //!         if you need the string value to persist - you will need to
173 //!         make a copy.
174 //!
175 class OptIstreamIter : public OptIter {
176 private:
177    std::istream & is ;
178    OptStrTokIter * tok_iter ;
179
180    void
181    fill(void);
182
183 public:
184    static const unsigned  MAX_LINE_LEN ;
185
186    OptIstreamIter(std::istream & input);
187
188    virtual
189    ~OptIstreamIter(void);
190
191    virtual const char *
192    curr(void);
193
194    virtual void
195    next(void);
196
197    virtual const char *
198    operator()(void);
199 } ;
200
201
202 //! \brief parse command-line options
203 //!
204 //! \section Synopsis
205 //! \code
206 //!   #include <options.h>
207 //!
208 //!   Options opts(cmdname, optv);
209 //!   char cmdname[], *optv[];
210 //! \endcode
211 //! \section Description
212 //! The Options constructor expects a command-name (usually argv[0]) and
213 //! a pointer to an array of strings.  The last element in this array MUST
214 //! be NULL. Each non-NULL string in the array must have the following format:
215 //!
216 //!   The 1st character must be the option-name ('c' for a -c option).
217 //!
218 //!   The 2nd character must be one of '|', '?', ':', '*', or '+'.
219 //!      '|' -- indicates that the option takes NO argument;
220 //!      '?' -- indicates that the option takes an OPTIONAL argument;
221 //!      ':' -- indicates that the option takes a REQUIRED argument;
222 //!      '*' -- indicates that the option takes 0 or more arguments;
223 //!      '+' -- indicates that the option takes 1 or more arguments;
224 //!
225 //!   The remainder of the string must be the long-option name.
226 //!
227 //!   If desired, the long-option name may be followed by one or more
228 //!   spaces and then by the name of the option value. This name will
229 //!   be used when printing usage messages. If the option-value-name
230 //!   is not given then the string "<value>" will be used in usage
231 //!   messages.
232 //!
233 //!   One may use a space to indicate that a particular option does not
234 //!   have a corresponding long-option.  For example, "c: " (or "c:")
235 //!   means the -c option takes a value & has NO corresponding long-option.
236 //!
237 //!   To specify a long-option that has no corresponding single-character
238 //!   option is a bit trickier: Options::operator() still needs an "option-
239 //!   character" to return when that option is matched. One may use a whitespace
240 //!   character or a non-printable character as the single-character option
241 //!   in such a case. (hence " |hello" would only match "--hello").
242 //!
243 //!   \section Exceptions Exceptions to the above
244 //!   If the 1st character of the string is '-', then the rest of the
245 //!   string must correspond to the above format, and the option is
246 //!   considered to be a hidden-option. This means it will be parsed
247 //!   when actually matching options from the command-line, but will
248 //!   NOT show-up if a usage message is printed using the usage() member
249 //!   function. Such an example might be "-h|hidden". If you want to
250 //!   use any "dummy" options (options that are not parsed, but that
251 //!   to show up in the usage message), you can specify them along with
252 //!   any positional parameters to the usage() member function.
253 //!
254 //!   If the 2nd character of the string is '\0' then it is assumed
255 //!   that there is no corresponding long-option and that the option
256 //!   takes no argument (hence "f", and "f| " are equivalent).
257 //!
258 //!   \code
259 //!      const char * optv[] = {
260 //!          "c:count   <number>",
261 //!          "s?str     <string>",
262 //!          "x",
263 //!          " |hello",
264 //!          "g+groups  <newsgroup>",
265 //!          NULL
266 //!      } ;
267 //!    \endcode
268 //!      optv[] now corresponds to the following:
269 //!
270 //!            usage: cmdname [-c|--count <number>] [-s|--str [<string>]]
271 //!                           [-x] [--hello] [-g|--groups <newsgroup> ...]
272 //!
273 //! Long-option names are matched case-insensitive and only a unique prefix
274 //! of the name needs to be specified.
275 //!
276 //! Option-name characters are case-sensitive!
277 //!
278 //! \section Caveat
279 //! Because of the way in which multi-valued options and options with optional
280 //! values are handled, it is NOT possible to supply a value to an option in
281 //! a separate argument (different argv[] element) if the value is OPTIONAL
282 //! and begins with a '-'. What this means is that if an option "-s" takes an
283 //! optional value value and you wish to supply a value of "-foo" then you must
284 //! specify this on the command-line as "-s-foo" instead of "-s -foo" because
285 //! "-s -foo" will be considered to be two separate sets of options.
286 //!
287 //! A multi-valued option is terminated by another option or by the end-of
288 //! options. The following are all equivalent (if "-l" is a multi-valued
289 //! option and "-x" is an option that takes no value):
290 //!
291 //!    cmdname -x -l item1 item2 item3 -- arg1 arg2 arg3
292 //!    cmdname -x -litem1 -litem2 -litem3 -- arg1 arg2 arg3
293 //!    cmdname -l item1 item2 item3 -x arg1 arg2 arg3
294 //!
295 //!
296 //! \code
297 //!    #include <options.h>
298 //!
299 //!    static const char * optv[] = {
300 //!       "H|help",
301 //!       "c:count   <number>",
302 //!       "s?str     <string>",
303 //!       "x",
304 //!       " |hello",
305 //!       "g+groups  <newsgroup>",
306 //!       NULL
307 //!    } ;
308 //!
309 //!    main(int argc, char * argv[]) {
310 //!       int  optchar;
311 //!       const char * optarg;
312 //!       const char * str = "default_string";
313 //!       int  count = 0, xflag = 0, hello = 0;
314 //!       int  errors = 0, ngroups = 0;
315 //!    
316 //!       Options  opts(*argv, optv);
317 //!       OptArgvIter  iter(--argc, ++argv);
318 //!    
319 //!       while( optchar = opts(iter, optarg) ) {
320 //!          switch (optchar) {
321 //!          case 'H' :
322 //!             opts.usage(cout, "files ...");
323 //!             exit(0);
324 //!             break;
325 //!          case 'g' :
326 //!             ++ngroups; break;  //! the groupname is in "optarg"
327 //!          case 's' :
328 //!             str = optarg; break;
329 //!          case 'x' :
330 //!             ++xflag; break;
331 //!          case ' ' :
332 //!             ++hello; break;
333 //!          case 'c' :
334 //!             if (optarg == NULL)  ++errors;
335 //!             else  count = (int) atol(optarg);
336 //!             break;
337 //!          default :  ++errors; break;
338 //!          } //!switch
339 //!       }
340 //!    
341 //!       if (errors || (iter.index() == argc)) {
342 //!          if (! errors) {
343 //!             cerr << opts.name() << ": no filenames given." << endl ;
344 //!          }
345 //!          opts.usage(cerr, "files ...");
346 //!          exit(1);
347 //!       }
348 //!    
349 //!       cout << "xflag=" << ((xflag) ? "ON"  : "OFF") << endl
350 //!            << "hello=" << ((hello) ? "YES" : "NO") << endl
351 //!            << "count=" << count << endl
352 //!            << "str=\"" << ((str) ? str : "No value given!") << "\"" << endl
353 //!            << "ngroups=" << ngroups << endl ;
354 //!    
355 //!       if (iter.index() < argc) {
356 //!          cout << "files=" ;
357 //!          for (int i = iter.index() ; i < argc ; i++) {
358 //!             cout << "\"" << argv[i] << "\" " ;
359 //!          }
360 //!          cout << endl ;
361 //!       }
362 //!    }
363 //! \endcode
364 class Options {
365 private:
366    unsigned       explicit_end : 1;  //!< were we terminated because of "--"?
367    unsigned       optctrls : 7;  //!< control settings (a set of OptCtrl masks)
368    const char  * const * optvec; //!< vector of option-specifications (last=NULL)
369    const char   * nextchar;      //!< next option-character to process
370    const char   * listopt;       //!< last list-option we matched
371    const char   * cmdname;       //!< name of the command
372
373    void
374    check_syntax(void) const;
375
376    const char *
377    match_opt(char opt, int ignore_case =0) const;
378
379    const char *
380    match_longopt(const char * opt, int  len, int & ambiguous) const;
381
382    int
383    parse_opt(OptIter & iter, const char * & optarg);
384
385    int
386    parse_longopt(OptIter & iter, const char * & optarg);
387
388 public:
389    enum OptCtrl {
390       DEFAULT    = 0x00,  //!< Default setting
391       ANYCASE    = 0x01,  //!< Ignore case when matching short-options
392       QUIET      = 0x02,  //!< Dont print error messages
393       PLUS       = 0x04,  //!< Allow "+" as a long-option prefix
394       SHORT_ONLY = 0x08,  //!< Dont accept long-options
395       LONG_ONLY  = 0x10,  //!< Dont accept short-options
396                             //!< (also allows "-" as a long-option prefix).
397       NOGUESSING = 0x20,  //!< Normally, when we see a short (long) option
398                             //!< on the command line that doesnt match any
399                             //!< known short (long) options, then we try to
400                             //!< "guess" by seeing if it will match any known
401                             //!< long (short) option. Setting this mask prevents
402                             //!< this "guessing" from occurring.
403       PARSE_POS = 0x40    //!< By default, Options will not present positional
404                             //!< command-line arguments to the user and will
405                             //!< instead stop parsing when the first positonal
406                             //!< argument has been encountered. If this flag
407                             //!< is given, Options will present positional
408                             //!< arguments to the user with a return code of
409                             //!< POSITIONAL; ENDOPTS will be returned only
410                             //!< when the end of the argument list is reached.
411    } ;
412
413       //! Error return values for operator()
414       //!
415    enum OptRC {
416       ENDOPTS    =  0,
417       BADCHAR    = -1,
418       BADKWD     = -2,
419       AMBIGUOUS  = -3,
420       POSITIONAL = -4
421    } ;
422
423    Options(const char * name, const char * const optv[]);
424
425    virtual
426    ~Options(void);
427
428       //! name() returns the command name
429    const char *
430    name(void) const { return  cmdname; }
431
432       //! ctrls() (with no arguments) returns the existing control settings
433    unsigned
434    ctrls(void) const { return  optctrls; }
435
436       //! ctrls() (with 1 argument) sets new control settings
437    void
438    ctrls(unsigned newctrls) { optctrls = newctrls; }
439
440       //! reset for another pass to parse for options
441    void
442    reset(void) { nextchar = listopt = NULL; }
443   
444       //! usage() prints options usage (followed by any positional arguments
445       //! listed in the parameter "positionals") on the given outstream
446    void
447    usage(std::ostream & os, const char * positionals) const ;
448
449       //! operator() iterates through the arguments as necessary (using the
450       //! given iterator) and returns the character value of the option
451       //! (or long-option) that it matched. If the option has a value
452       //! then the value given may be found in optarg (otherwise optarg
453       //! will be NULL).
454       //!
455       //! 0 is returned upon end-of-options. At this point, "iter" may
456       //! be used to process any remaining positional parameters. If the
457       //! PARSE_POS control-flag is set then 0 is returned only when all
458       //! arguments in "iter" have been exhausted.
459       //!
460       //! If an invalid option is found then BADCHAR is returned and *optarg
461       //! is the unrecognized option character.
462       //!
463       //! If an invalid long-option is found then BADKWD is returned and optarg
464       //! points to the bad long-option.
465       //!
466       //! If an ambiguous long-option is found then AMBIGUOUS is returned and
467       //! optarg points to the ambiguous long-option.
468       //!
469       //! If the PARSE_POS control-flag is set then POSITIONAL is returned
470       //! when a positional argument is encountered and optarg points to
471       //! the positonal argument (and "iter" is advanced to the next argument
472       //! in the iterator).
473       //!
474       //! Unless Options::QUIET is used, missing option-arguments and
475       //! invalid options (and the like) will automatically cause error
476       //! messages to be issued to cerr.
477    int
478    operator()(OptIter & iter, const char * & optarg) ;
479
480       //! Call this member function after operator() has returned 0
481       //! if you want to know whether or not options were explicitly
482       //! terminated because "--" appeared on the command-line.
483       //!
484    int
485    explicit_endopts() const { return  explicit_end; }
486 } ;
487
488 #endif /* _options_h */