]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - tools/elftosb/common/options.cpp
merged tx6dl-devel into denx master branch
[karo-tx-uboot.git] / tools / elftosb / common / options.cpp
1 // ****************************************************************************
2 // ^FILE: options.c - implement the functions defined in <options.h>
3 //
4 // ^HISTORY:
5 //    01/16/92  Brad Appleton   <bradapp@enteract.com>  Created
6 //
7 //    03/23/93  Brad Appleton   <bradapp@enteract.com>
8 //    - Added OptIstreamIter class
9 //
10 //    10/08/93  Brad Appleton   <bradapp@enteract.com>
11 //    - Added "hidden" options
12 //
13 //    02/08/94  Brad Appleton   <bradapp@enteract.com>
14 //    - Added "OptionSpec" class
15 //    - Permitted use of stdio instead of iostreams via #ifdef USE_STDIO
16 //
17 //    03/08/94  Brad Appleton   <bradapp@enteract.com>
18 //    - completed support for USE_STDIO
19 //    - added #ifdef NO_USAGE for people who always want to print their own
20 //    - Fixed stupid NULL pointer error in OptionsSpec class
21 //
22 //    07/31/97  Brad Appleton   <bradapp@enteract.com>
23 //    - Added PARSE_POS control flag and POSITIONAL return value.
24 // ^^**************************************************************************
25
26 // #include <stdlib.h>
27 #include <ctype.h>
28 #include <string.h>
29
30 #include "options.h"
31
32 using namespace std;
33
34 extern "C" {
35    void  exit(int);
36 }
37
38 static const char ident[] = "@(#)Options  1.05" ;
39
40    // I need a portable version of "tolower" that does NOT modify
41    // non-uppercase characters.
42    //
43 #define  TOLOWER(c)  (isupper(c) ? tolower(c) : c)
44
45    // Use this to shut the compiler up about NULL strings
46 #define  NULLSTR  (char *)NULL
47
48 // ******************************************************** insertion operators
49
50   // If you are using <stdio.h> then you need this stuff!
51   // If you are using <iostream.h> then #ifdef this stuff out
52   //
53
54
55 #ifdef  USE_STDIO
56
57    // Implement just enough of ostream to get this file to compile
58    //
59
60 static const char endl = '\n' ;
61
62 class  ostream {
63 public:
64    ostream(FILE * fileptr) : fp(fileptr) {}
65
66    ostream &
67    operator<<(char ch);
68
69    ostream &
70    operator<<(const char * str);
71
72    ostream &
73    write(const char * buf, unsigned bufsize);
74
75 private:
76    FILE * fp;
77 } ;
78
79 ostream &
80 ostream::operator<<(char ch) {
81    fputc(ch, fp);
82    return *this;
83 }
84
85 ostream &
86 ostream::operator<<(const char * str) {
87    fputs(str, fp);
88    return *this;
89 }
90
91 ostream &
92 ostream::write(const char * buf, unsigned ) {
93    fputs(buf, fp);
94    return *this;
95 }
96
97 static  ostream  cerr(stderr);
98 static  ostream  cout(stdout);
99
100 #endif  /* USE_STDIO */
101
102 // ************************************************************** OptIter
103
104 OptIter::~OptIter(void) {}
105
106 const char *
107 OptIter::operator()(void)  {
108    const char * elt = curr();
109    (void) next();
110    return  elt;
111 }
112
113 // ************************************************************** OptIterRwd
114
115 OptIterRwd::OptIterRwd(void) {}
116
117 OptIterRwd::~OptIterRwd(void) {}
118
119 // ************************************************************** OptArgvIter
120
121 OptArgvIter::~OptArgvIter(void) {}
122
123 const char *
124 OptArgvIter::curr(void) {
125    return ((ndx == ac) || (av[ndx] == NULL)) ? NULLSTR : av[ndx];
126 }
127
128 void
129 OptArgvIter::next(void) {
130    if ((ndx != ac) && av[ndx]) ++ndx;
131 }
132
133 const char *
134 OptArgvIter::operator()(void) {
135    return ((ndx == ac) || (av[ndx] == NULL)) ? NULLSTR : av[ndx++];
136 }
137
138 void
139 OptArgvIter::rewind(void) { ndx = 0; }
140
141 // ************************************************************** OptStrTokIter
142
143 static const char WHITESPACE[] = " \t\n\r\v\f" ;
144 const char * OptStrTokIter::default_delims = WHITESPACE ;
145
146 OptStrTokIter::OptStrTokIter(const char * tokens, const char * delimiters)
147    : len(unsigned(strlen(tokens))), str(tokens), seps(delimiters),
148      cur(NULLSTR), tokstr(NULLSTR)
149 {
150    if (seps == NULL)  seps = default_delims;
151    tokstr = new char[len + 1];
152    (void) ::strcpy(tokstr, str);
153    cur = ::strtok(tokstr, seps);
154 }
155
156
157 OptStrTokIter::~OptStrTokIter(void) { delete [] tokstr; }
158
159 const char *
160 OptStrTokIter::curr(void) { return cur; }
161
162 void
163 OptStrTokIter::next(void) { if (cur) cur = ::strtok(NULL, seps); }
164
165 const char *
166 OptStrTokIter::operator()(void) {
167    const char * elt = cur;
168    if (cur) cur = ::strtok(NULL, seps);
169    return  elt;
170 }
171
172 void
173 OptStrTokIter::rewind(void) {
174    (void) ::strcpy(tokstr, str);
175    cur = ::strtok(tokstr, seps);
176 }
177
178 // ************************************************************* OptIstreamIter
179
180 #ifdef vms
181    enum { c_COMMENT = '!' } ;
182 #else
183    enum { c_COMMENT = '#' } ;
184 #endif
185
186 const unsigned  OptIstreamIter::MAX_LINE_LEN = 1024 ;
187
188    // Constructor
189 OptIstreamIter::OptIstreamIter(istream & input) : is(input), tok_iter(NULL)
190 {
191 #ifdef  USE_STDIO
192    fprintf(stderr, "%s: Can't use OptIstreamIter class:\n",
193                    "OptIstreamIter::OptIstreamIter");
194    fprintf(stderr, "\tOptions(3C++) was compiled with USE_STDIO #defined.\n");
195    exit(-1);
196 #endif  /* USE_STDIO */
197 }
198
199    // Destructor
200 OptIstreamIter::~OptIstreamIter(void) {
201    delete  tok_iter;
202 }
203
204 const char *
205 OptIstreamIter::curr(void) {
206 #ifdef  USE_STDIO
207    return  NULLSTR;
208 #else
209    const char * result = NULLSTR;
210    if (tok_iter)  result = tok_iter->curr();
211    if (result)  return  result;
212    fill();
213    return (! is) ? NULLSTR : tok_iter->curr();
214 #endif  /* USE_STDIO */
215 }
216
217 void
218 OptIstreamIter::next(void) {
219 #ifdef  USE_STDIO
220    return;
221 #else
222    const char * result = NULLSTR;
223    if (tok_iter)  result = tok_iter->operator()();
224    if (result)  return;
225    fill();
226    if (! is) tok_iter->next();
227 #endif  /* USE_STDIO */
228 }
229
230 const char *
231 OptIstreamIter::operator()(void) {
232 #ifdef  USE_STDIO
233    return  NULLSTR;
234 #else
235    const char * result = NULLSTR;
236    if (tok_iter)  result = tok_iter->operator()();
237    if (result)  return  result;
238    fill();
239    return (! is) ? NULLSTR : tok_iter->operator()();
240 #endif  /* USE_STDIO */
241 }
242
243    // What we do is this: for each line of text in the istream, we use
244    // a OptStrTokIter to iterate over each token on the line.
245    //
246    // If the first non-white character on a line is c_COMMENT, then we
247    // consider the line to be a comment and we ignore it.
248    //
249 void
250 OptIstreamIter::fill(void) {
251 #ifdef USE_STDIO
252    return;
253 #else
254    char buf[OptIstreamIter::MAX_LINE_LEN];
255    do {
256       *buf = '\0';
257       is.getline(buf, sizeof(buf));
258       char * ptr = buf;
259       while (isspace(*ptr)) ++ptr;
260       if (*ptr && (*ptr != c_COMMENT)) {
261          delete  tok_iter;
262          tok_iter = new OptStrTokIter(ptr);
263          return;
264       }
265    } while (is);
266 #endif  /* USE_STDIO */
267 }
268
269 // **************************************************** Options class utilities
270
271    // Is this option-char null?
272 inline static int
273 isNullOpt(char optchar) {
274    return  ((! optchar) || isspace(optchar) || (! isprint(optchar)));
275 }
276    
277    // Check for explicit "end-of-options"
278 inline static int
279 isEndOpts(const char * token) {
280    return ((token == NULL) || (! ::strcmp(token, "--"))) ;
281 }
282
283    // See if an argument is an option
284 inline static int
285 isOption(unsigned  flags, const char * arg) {
286    return  (((*arg != '\0') || (arg[1] != '\0')) &&
287             ((*arg == '-')  || ((flags & Options::PLUS) && (*arg == '+')))) ;
288 }
289
290    // See if we should be parsing only options or if we also need to
291    // parse positional arguments
292 inline static int
293 isOptsOnly(unsigned  flags) {
294    return  (flags & Options::PARSE_POS) ? 0 : 1;
295 }
296
297    // return values for a keyword matching function
298 enum kwdmatch_t { NO_MATCH, PARTIAL_MATCH, EXACT_MATCH } ;
299
300 // ---------------------------------------------------------------------------
301 // ^FUNCTION: kwdmatch - match a keyword
302 //
303 // ^SYNOPSIS:
304 //    static kwdmatch_t kwdmatch(src, attempt, len)
305 //
306 // ^PARAMETERS:
307 //    char * src -- the actual keyword to match
308 //    char * attempt -- the possible keyword to compare against "src"
309 //    int len -- number of character of "attempt" to consider
310 //               (if 0 then we should use all of "attempt")
311 //
312 // ^DESCRIPTION:
313 //    See if "attempt" matches some prefix of "src" (case insensitive).
314 //
315 // ^REQUIREMENTS:
316 //    - attempt should be non-NULL and non-empty
317 //
318 // ^SIDE-EFFECTS:
319 //    None.
320 //
321 // ^RETURN-VALUE:
322 //    An enumeration value of type kwdmatch_t corresponding to whether
323 //    We had an exact match, a partial match, or no match.
324 //
325 // ^ALGORITHM:
326 //    Trivial
327 // ^^-------------------------------------------------------------------------
328 static kwdmatch_t
329 kwdmatch(const char * src, const char * attempt, int len =0) {
330    int  i;
331
332    if (src == attempt)  return  EXACT_MATCH ;
333    if ((src == NULL) || (attempt == NULL))  return  NO_MATCH ;
334    if ((! *src) && (! *attempt))  return  EXACT_MATCH ;
335    if ((! *src) || (! *attempt))  return  NO_MATCH ;
336
337    for (i = 0 ; ((i < len) || (len == 0)) &&
338                 (attempt[i]) && (attempt[i] != ' ') ; i++) {
339       if (TOLOWER(src[i]) != TOLOWER(attempt[i]))  return  NO_MATCH ;
340    }
341
342    return  (src[i]) ? PARTIAL_MATCH : EXACT_MATCH ;
343 }
344
345 // **************************************************************** OptionSpec
346
347    // Class that represents an option-specification
348    //    *NOTE*:: Assumes that the char-ptr given to the constructor points
349    //             to storage that will NOT be modified and whose lifetime will
350    //             be as least as long as the OptionSpec object we construct.
351    //
352 class OptionSpec {
353 public:
354    OptionSpec(const char * decl =NULLSTR)
355       : hidden(0), spec(decl)
356    {
357       if (spec == NULL)  spec = NULL_spec;
358       CheckHidden();
359    }
360
361    OptionSpec(const OptionSpec & cp) : hidden(cp.hidden), spec(cp.spec) {}
362
363    // NOTE: use default destructor!
364
365       // Assign to another OptionSpec
366    OptionSpec &
367    operator=(const OptionSpec & cp) {
368       if (this != &cp) {
369          spec = cp.spec;
370          hidden = cp.hidden;
371       }
372       return *this;
373    }
374
375       // Assign to a string
376    OptionSpec &
377    operator=(const char * decl) {
378       if (spec != decl) {
379          spec = decl;
380          hidden = 0;
381          CheckHidden();
382       }
383       return *this;
384    }
385
386       // Convert to char-ptr by returning the original declaration-string
387    operator const char*() { return  isHiddenOpt() ? (spec - 1) : spec; }
388
389       // Is this option NULL?
390    int
391    isNULL(void) const { return ((spec == NULL) || (spec == NULL_spec)); }
392
393       // Is this options incorrectly specified?
394    int
395    isSyntaxError(const char * name) const;
396
397       // See if this is a Hidden option
398    int
399    isHiddenOpt(void) const { return  hidden; }
400
401       // Get the corresponding option-character
402    char
403    OptChar(void) const { return  *spec; }
404
405       // Get the corresponding long-option string
406    const char *
407    LongOpt(void) const {
408        return  (spec[1] && spec[2] && (! isspace(spec[2]))) ? (spec + 2) : NULLSTR;
409    }
410
411       // Does this option require an argument?
412    int
413    isValRequired(void) const {
414       return  ((spec[1] == ':') || (spec[1] == '+'));
415    }
416
417       // Does this option take an optional argument?
418    int
419    isValOptional(void) const {
420       return  ((spec[1] == '?') || (spec[1] == '*'));
421    }
422
423       // Does this option take no arguments?
424    int
425    isNoArg(void) const {
426       return  ((spec[1] == '|') || (! spec[1]));
427    }
428
429       // Can this option take more than one argument?
430    int
431    isList(void) const {
432       return  ((spec[1] == '+') || (spec[1] == '*'));
433    }
434
435       // Does this option take any arguments?
436    int
437    isValTaken(void) const {
438       return  (isValRequired() || isValOptional()) ;
439    }
440
441       // Format this option in the given buffer
442    unsigned
443    Format(char * buf, unsigned optctrls) const;
444
445 private:
446    void
447    CheckHidden(void) {
448       if ((! hidden) && (*spec == '-')) {
449          ++hidden;
450          ++spec;
451       }
452    }
453
454    unsigned     hidden : 1;  // hidden-flag
455    const char * spec;        // string specification
456
457    static const char NULL_spec[];
458 } ;
459
460 const char OptionSpec::NULL_spec[] = "\0\0\0" ;
461
462 int
463 OptionSpec::isSyntaxError(const char * name) const {
464    int  error = 0;
465    if ((! spec) || (! *spec)) {
466       cerr << name << ": empty option specifier." << endl;
467       cerr << "\tmust be at least 1 character long." << endl;
468       ++error;
469    } else if (spec[1] && (strchr("|?:*+", spec[1]) == NULL)) {
470       cerr << name << ": bad option specifier \"" << spec << "\"." << endl;
471       cerr << "\t2nd character must be in the set \"|?:*+\"." << endl;
472       ++error;
473    }
474    return  error;
475 }
476
477 // ---------------------------------------------------------------------------
478 // ^FUNCTION: OptionSpec::Format - format an option-spec for a usage message
479 //
480 // ^SYNOPSIS:
481 //    unsigned OptionSpec::Format(buf, optctrls) const
482 //
483 // ^PARAMETERS:
484 //    char * buf -- where to print the formatted option
485 //    unsigned  optctrls -- option-parsing configuration flags
486 //
487 // ^DESCRIPTION:
488 //    Self-explanatory.
489 //
490 // ^REQUIREMENTS:
491 //    - buf must be large enough to hold the result
492 //
493 // ^SIDE-EFFECTS:
494 //    - writes to buf.
495 //
496 // ^RETURN-VALUE:
497 //    Number of characters written to buf.
498 //
499 // ^ALGORITHM:
500 //    Follow along in the source - it's not hard but it is tedious!
501 // ^^-------------------------------------------------------------------------
502 unsigned
503 OptionSpec::Format(char * buf, unsigned optctrls) const {
504 #ifdef NO_USAGE
505    return  (*buf = '\0');
506 #else
507    static  char default_value[] = "<value>";
508    if (isHiddenOpt())  return (unsigned)(*buf = '\0');
509    char optchar = OptChar();
510    const char * longopt = LongOpt();
511    char * p = buf ;
512
513    const char * value = NULLSTR;
514    int    longopt_len = 0;
515    int    value_len = 0;
516
517    if (longopt) {
518       value = ::strchr(longopt, ' ');
519       longopt_len = (value) ? (value - longopt) : ::strlen(longopt);
520    } else {
521       value = ::strchr(spec + 1, ' ');
522    }
523    while (value && (*value == ' '))  ++value;
524    if (value && *value) {
525       value_len = ::strlen(value);
526    } else {
527       value = default_value;
528       value_len = sizeof(default_value) - 1;
529    }
530
531    if ((optctrls & Options::SHORT_ONLY) &&
532        ((! isNullOpt(optchar)) || (optctrls & Options::NOGUESSING))) {
533       longopt = NULLSTR;
534    }
535    if ((optctrls & Options::LONG_ONLY) &&
536        (longopt || (optctrls & Options::NOGUESSING))) {
537       optchar = '\0';
538    }
539    if (isNullOpt(optchar) && (longopt == NULL)) {
540       *buf = '\0';
541       return  0;
542    }
543
544    *(p++) = '[';
545
546    // print the single character option
547    if (! isNullOpt(optchar)) {
548       *(p++) = '-';
549       *(p++) = optchar;
550    }
551
552    if ((! isNullOpt(optchar)) && (longopt))  *(p++) = '|';
553
554    // print the long option
555    if (longopt) {
556       *(p++) = '-';
557       if (! (optctrls & (Options::LONG_ONLY | Options::SHORT_ONLY))) {
558          *(p++) = '-';
559       }
560       strncpy(p, longopt, longopt_len);
561       p += longopt_len;
562    }
563
564    // print any argument the option takes
565    if (isValTaken()) {
566       *(p++) = ' ' ;
567       if (isValOptional())  *(p++) = '[' ;
568       strcpy(p, value);
569       p += value_len;
570       if (isList()) {
571          strcpy(p, " ...");
572          p += 4;
573       }
574       if (isValOptional())  *(p++) = ']' ;
575    }
576
577    *(p++) = ']';
578    *p = '\0';
579
580    return  (unsigned) strlen(buf);
581 #endif  /* USE_STDIO */
582 }
583
584 // ******************************************************************* Options
585
586 #if (defined(MSWIN) || defined(OS2) || defined(MSDOS))
587 # define DIR_SEP_CHAR '\\'
588 #else
589 # define DIR_SEP_CHAR '/'
590 #endif
591
592 Options::Options(const char * name, const char * const optv[])
593    : cmdname(name), optvec(optv), explicit_end(0), optctrls(DEFAULT),
594      nextchar(NULLSTR), listopt(NULLSTR)
595 {
596    const char * basename = ::strrchr(cmdname, DIR_SEP_CHAR);
597    if (basename)  cmdname = basename + 1;
598    check_syntax();
599 }
600
601 Options::~Options(void) {}
602
603    // Make sure each option-specifier has correct syntax.
604    //
605    // If there is even one invalid specifier, then exit ungracefully!
606    //
607 void
608 Options::check_syntax(void) const {
609    int  errors = 0;
610    if ((optvec == NULL) || (! *optvec))  return;
611
612    for (const char * const * optv = optvec ; *optv ; optv++) {
613       OptionSpec  optspec = *optv;
614       errors += optspec.isSyntaxError(cmdname);
615    }
616    if (errors)  exit(127);
617 }
618
619 // ---------------------------------------------------------------------------
620 // ^FUNCTION: Options::match_opt - match an option
621 //
622 // ^SYNOPSIS:
623 //    const char * match_opt(opt, int  ignore_case) const
624 //
625 // ^PARAMETERS:
626 //    char opt -- the option-character to match
627 //    int  ignore_case -- should we ignore character-case?
628 //
629 // ^DESCRIPTION:
630 //    See if "opt" is found in "optvec"
631 //
632 // ^REQUIREMENTS:
633 //    - optvec should be non-NULL and terminated by a NULL pointer.
634 //
635 // ^SIDE-EFFECTS:
636 //    None.
637 //
638 // ^RETURN-VALUE:
639 //    NULL if no match is found,
640 //    otherwise a pointer to the matching option-spec.
641 //
642 // ^ALGORITHM:
643 //    foreach option-spec
644 //       - see if "opt" is a match, if so return option-spec
645 //    end-for
646 // ^^-------------------------------------------------------------------------
647 const char *
648 Options::match_opt(char opt, int ignore_case) const {
649    if ((optvec == NULL) || (! *optvec))  return  NULLSTR;
650
651    for (const char * const * optv = optvec ; *optv ; optv++) {
652       OptionSpec  optspec = *optv;
653       char optchar = optspec.OptChar();
654       if (isNullOpt(optchar))  continue;
655       if (opt == optchar) {
656          return  optspec;
657       } else if (ignore_case && (TOLOWER(opt) == TOLOWER(optchar))) {
658          return  optspec;
659       }
660    }
661
662    return  NULLSTR;  // not found
663 }
664
665 // ---------------------------------------------------------------------------
666 // ^FUNCTION: Options::match_longopt - match a long-option
667 //
668 // ^SYNOPSIS:
669 //   const char * Options::match_longopt(opt, len, ambiguous)
670 //
671 // ^PARAMETERS:
672 //    char * opt -- the long-option to match
673 //    int len -- the number of character of "opt" to match
674 //    int & ambiguous -- set by this routine before returning.
675 //
676 // ^DESCRIPTION:
677 //    Try to match "opt" against some unique prefix of a long-option
678 //    (case insensitive).
679 //
680 // ^REQUIREMENTS:
681 //    - optvec should be non-NULL and terminated by a NULL pointer.
682 //
683 // ^SIDE-EFFECTS:
684 //    - *ambiguous is set to '1' if "opt" matches >1 long-option
685 //      (otherwise it is set to 0).
686 //
687 // ^RETURN-VALUE:
688 //    NULL if no match is found,
689 //    otherwise a pointer to the matching option-spec.
690 //
691 // ^ALGORITHM:
692 //    ambiguous is FALSE
693 //    foreach option-spec
694 //       if we have an EXACT-MATCH, return the option-spec
695 //       if we have a partial-match then
696 //          if we already had a previous partial match then
697 //             set ambiguous = TRUE and return NULL
698 //          else
699 //             remember this options spec and continue matching
700 //          end-if
701 //       end-if
702 //    end-for
703 //    if we had exactly 1 partial match return it, else return NULL
704 // ^^-------------------------------------------------------------------------
705 const char *
706 Options::match_longopt(const char * opt, int  len, int & ambiguous) const {
707    kwdmatch_t  result;
708    const char * matched = NULLSTR ;
709
710    ambiguous = 0;
711    if ((optvec == NULL) || (! *optvec))  return  NULLSTR;
712
713    for (const char * const * optv = optvec ; *optv ; optv++) {
714       OptionSpec  optspec = *optv;
715       const char * longopt = optspec.LongOpt();
716       if (longopt == NULL)  continue;
717       result = kwdmatch(longopt, opt, len);
718       if (result == EXACT_MATCH) {
719          return  optspec;
720       } else if (result == PARTIAL_MATCH) {
721          if (matched) {
722             ++ambiguous;
723             return  NULLSTR;
724          } else {
725             matched = optspec;
726          }
727       }
728    }//for
729
730    return  matched;
731 }
732
733 // ---------------------------------------------------------------------------
734 // ^FUNCTION: Options::parse_opt - parse an option
735 //
736 // ^SYNOPSIS:
737 //    int Options::parse_opt(iter, optarg)
738 //
739 // ^PARAMETERS:
740 //    OptIter & iter -- option iterator
741 //    const char * & optarg -- where to store any option-argument
742 //
743 // ^DESCRIPTION:
744 //    Parse the next option in iter (advancing as necessary).
745 //    Make sure we update the nextchar pointer along the way. Any option
746 //    we find should be returned and optarg should point to its argument.
747 //
748 // ^REQUIREMENTS:
749 //    - nextchar must point to the prospective option character
750 //
751 // ^SIDE-EFFECTS:
752 //    - iter is advanced when an argument completely parsed
753 //    - optarg is modified to point to any option argument
754 //    - if Options::QUIET is not set, error messages are printed on cerr
755 //
756 // ^RETURN-VALUE:
757 //    'c' if the -c option was matched (optarg points to its argument)
758 //    BADCHAR if the option is invalid (optarg points to the bad
759 //                                                   option-character).
760 //
761 // ^ALGORITHM:
762 //    It gets complicated -- follow the comments in the source.
763 // ^^-------------------------------------------------------------------------
764 int
765 Options::parse_opt(OptIter & iter, const char * & optarg) {
766    listopt = NULLSTR;  // reset the list pointer
767
768    if ((optvec == NULL) || (! *optvec))  return  Options::ENDOPTS;
769
770       // Try to match a known option
771    OptionSpec optspec = match_opt(*(nextchar++), (optctrls & Options::ANYCASE));
772
773       // Check for an unknown option
774    if (optspec.isNULL()) {
775       // See if this was a long-option in disguise
776       if (! (optctrls & Options::NOGUESSING)) {
777          unsigned  save_ctrls = optctrls;
778          const char * save_nextchar = nextchar;
779          nextchar -= 1;
780          optctrls |= (Options::QUIET | Options::NOGUESSING);
781          int  optchar = parse_longopt(iter, optarg);
782          optctrls = save_ctrls;
783          if (optchar > 0) {
784             return  optchar;
785          } else {
786             nextchar = save_nextchar;
787          }
788       }
789       if (! (optctrls & Options::QUIET)) {
790          cerr << cmdname << ": unknown option -"
791               << *(nextchar - 1) << "." << endl ;
792       }
793       optarg = (nextchar - 1);  // record the bad option in optarg
794       return  Options::BADCHAR;
795    }
796
797       // If no argument is taken, then leave now
798    if (optspec.isNoArg()) {
799       optarg = NULLSTR;
800       return  optspec.OptChar();
801    }
802
803       // Check for argument in this arg
804    if (*nextchar) {
805       optarg = nextchar; // the argument is right here
806       nextchar = NULLSTR;   // we've exhausted this arg
807       if (optspec.isList())  listopt = optspec ;  // save the list-spec
808       return  optspec.OptChar();
809    }
810
811       // Check for argument in next arg
812    const char * nextarg = iter.curr();
813    if ((nextarg != NULL)  &&
814        (optspec.isValRequired() || (! isOption(optctrls, nextarg)))) {
815       optarg = nextarg;    // the argument is here
816       iter.next();         // end of arg - advance
817       if (optspec.isList())  listopt = optspec ;  // save the list-spec
818       return  optspec.OptChar();
819    }
820
821      // No argument given - if its required, thats an error
822    optarg = NULLSTR;
823    if (optspec.isValRequired() &&  !(optctrls & Options::QUIET)) {
824       cerr << cmdname << ": argument required for -" << optspec.OptChar()
825            << " option." << endl ;
826    }
827    return  optspec.OptChar();
828 }
829
830 // ---------------------------------------------------------------------------
831 // ^FUNCTION: Options::parse_longopt - parse a long-option
832 //
833 // ^SYNOPSIS:
834 //    int Options::parse_longopt(iter, optarg)
835 //
836 // ^PARAMETERS:
837 //    OptIter & iter -- option iterator
838 //    const char * & optarg -- where to store any option-argument
839 //
840 // ^DESCRIPTION:
841 //    Parse the next long-option in iter (advancing as necessary).
842 //    Make sure we update the nextchar pointer along the way. Any option
843 //    we find should be returned and optarg should point to its argument.
844 //
845 // ^REQUIREMENTS:
846 //    - nextchar must point to the prospective option character
847 //
848 // ^SIDE-EFFECTS:
849 //    - iter is advanced when an argument completely parsed
850 //    - optarg is modified to point to any option argument
851 //    - if Options::QUIET is not set, error messages are printed on cerr
852 //
853 // ^RETURN-VALUE:
854 //    'c' if the the long-option corresponding to the -c option was matched
855 //         (optarg points to its argument)
856 //    BADKWD if the option is invalid (optarg points to the bad long-option
857 //                                                                     name).
858 //
859 // ^ALGORITHM:
860 //    It gets complicated -- follow the comments in the source.
861 // ^^-------------------------------------------------------------------------
862 int
863 Options::parse_longopt(OptIter & iter, const char * & optarg) {
864    int  len = 0, ambiguous = 0;
865
866    listopt = NULLSTR ;  // reset the list-spec
867
868    if ((optvec == NULL) || (! *optvec))  return  Options::ENDOPTS;
869
870       // if a value is supplied in this argv element, get it now
871    const char * val = strpbrk(nextchar, ":=") ;
872    if (val) {
873       len = val - nextchar ;
874       ++val ;
875    }
876
877       // Try to match a known long-option
878    OptionSpec  optspec = match_longopt(nextchar, len, ambiguous);
879
880       // Check for an unknown long-option
881    if (optspec.isNULL()) {
882       // See if this was a short-option in disguise
883       if ((! ambiguous) && (! (optctrls & Options::NOGUESSING))) {
884          unsigned  save_ctrls = optctrls;
885          const char * save_nextchar = nextchar;
886          optctrls |= (Options::QUIET | Options::NOGUESSING);
887          int  optchar = parse_opt(iter, optarg);
888          optctrls = save_ctrls;
889          if (optchar > 0) {
890             return  optchar;
891          } else {
892             nextchar = save_nextchar;
893          }
894       }
895       if (! (optctrls & Options::QUIET)) {
896          cerr << cmdname << ": " << ((ambiguous) ? "ambiguous" : "unknown")
897               << " option "
898               << ((optctrls & Options::LONG_ONLY) ? "-" : "--")
899               << nextchar << "." << endl ;
900       }
901       optarg = nextchar;  // record the bad option in optarg
902       nextchar = NULLSTR;    // we've exhausted this argument
903       return  (ambiguous) ? Options::AMBIGUOUS : Options::BADKWD;
904    }
905
906       // If no argument is taken, then leave now
907    if (optspec.isNoArg()) {
908       if ((val) && ! (optctrls & Options::QUIET)) {
909          cerr << cmdname << ": option "
910               << ((optctrls & Options::LONG_ONLY) ? "-" : "--")
911               << optspec.LongOpt() << " does NOT take an argument." << endl ;
912       }
913       optarg = val;     // record the unexpected argument
914       nextchar = NULLSTR;  // we've exhausted this argument
915       return  optspec.OptChar();
916    }
917
918       // Check for argument in this arg
919    if (val) {
920       optarg = val;      // the argument is right here
921       nextchar = NULLSTR;   // we exhausted the rest of this arg
922       if (optspec.isList())  listopt = optspec ;  // save the list-spec
923       return  optspec.OptChar();
924    }
925
926       // Check for argument in next arg
927    const char * nextarg = iter.curr();  // find the next argument to parse
928    if ((nextarg != NULL)  &&
929        (optspec.isValRequired() || (! isOption(optctrls, nextarg)))) {
930       optarg = nextarg;        // the argument is right here
931       iter.next();             // end of arg - advance
932       nextchar = NULLSTR;         // we exhausted the rest of this arg
933       if (optspec.isList())  listopt = optspec ;  // save the list-spec
934       return  optspec.OptChar();
935    }
936
937      // No argument given - if its required, thats an error
938    optarg = NULLSTR;
939    if (optspec.isValRequired() &&  !(optctrls & Options::QUIET)) {
940       const char * longopt = optspec.LongOpt();
941       const char * spc = ::strchr(longopt, ' ');
942       int  longopt_len;
943       if (spc) {
944          longopt_len = spc - longopt;
945       } else {
946          longopt_len = ::strlen(longopt);
947       }
948       cerr << cmdname << ": argument required for "
949            << ((optctrls & Options::LONG_ONLY) ? "-" : "--");
950       cerr.write(longopt, longopt_len) << " option." << endl ;
951    }
952    nextchar = NULLSTR;           // we exhausted the rest of this arg
953    return  optspec.OptChar();
954 }
955
956 // ---------------------------------------------------------------------------
957 // ^FUNCTION: Options::usage - print usage
958 //
959 // ^SYNOPSIS:
960 //    void Options::usage(os, positionals)
961 //
962 // ^PARAMETERS:
963 //    ostream & os -- where to print the usage
964 //    char * positionals -- command-line syntax for any positional args
965 //
966 // ^DESCRIPTION:
967 //    Print command-usage (using either option or long-option syntax) on os.
968 //
969 // ^REQUIREMENTS:
970 //    os should correspond to an open output file.
971 //
972 // ^SIDE-EFFECTS:
973 //    Prints on os
974 //
975 // ^RETURN-VALUE:
976 //    None.
977 //
978 // ^ALGORITHM:
979 //    Print usage on os, wrapping long lines where necessary.
980 // ^^-------------------------------------------------------------------------
981 void
982 Options::usage(ostream & os, const char * positionals) const {
983 #ifdef NO_USAGE
984    return;
985 #else
986    const char * const * optv = optvec;
987    unsigned  cols = 79;
988    int  first, nloop;
989    char  buf[256] ;
990
991    if ((optv == NULL) || (! *optv))  return;
992
993       // print first portion "usage: progname"
994    os << "usage: " << cmdname ;
995    unsigned  ll = strlen(cmdname) + 7;
996
997       // save the current length so we know how much space to skip for
998       // subsequent lines.
999       //
1000    unsigned  margin = ll + 1;
1001
1002       // print the options and the positional arguments
1003    for (nloop = 0, first = 1 ; !nloop ; optv++, first = 0) {
1004       unsigned  len;
1005       OptionSpec   optspec = *optv;
1006
1007          // figure out how wide this parameter is (for printing)
1008       if (! *optv) {
1009          len = strlen(positionals);
1010          ++nloop;  // terminate this loop
1011       } else {
1012          if (optspec.isHiddenOpt())  continue;
1013          len = optspec.Format(buf, optctrls);
1014       }
1015
1016       //  Will this fit?
1017       if ((ll + len + 1) > (cols - first)) {
1018          os << '\n' ;  // No - start a new line;
1019 #ifdef USE_STDIO
1020          for (int _i_ = 0; _i_ < margin; ++_i_)  os << " ";
1021 #else
1022          os.width(margin); os << "" ;
1023 #endif
1024          ll = margin;
1025       } else {
1026          os << ' ' ;  // Yes - just throw in a space
1027          ++ll;
1028       }
1029       ll += len;
1030       os << ((nloop) ? positionals : buf) ;
1031    }// for each ad
1032
1033    os << endl ;
1034 #endif  /* NO_USAGE */
1035 }
1036
1037
1038 // ---------------------------------------------------------------------------
1039 // ^FUNCTION: Options::operator() - get options from the command-line
1040 //
1041 // ^SYNOPSIS:
1042 //   int Options::operator()(iter, optarg)
1043 //
1044 // ^PARAMETERS:
1045 //    OptIter & iter -- option iterator
1046 //    const char * & optarg -- where to store any option-argument
1047 //
1048 // ^DESCRIPTION:
1049 //    Parse the next option in iter (advancing as necessary).
1050 //    Make sure we update the nextchar pointer along the way. Any option
1051 //    we find should be returned and optarg should point to its argument.
1052 //
1053 // ^REQUIREMENTS:
1054 //    None.
1055 //
1056 // ^SIDE-EFFECTS:
1057 //    - iter is advanced when an argument is completely parsed
1058 //    - optarg is modified to point to any option argument
1059 //    - if Options::QUIET is not set, error messages are printed on cerr
1060 //
1061 // ^RETURN-VALUE:
1062 //     0 if all options have been parsed.
1063 //    'c' if the the option or long-option corresponding to the -c option was
1064 //         matched (optarg points to its argument).
1065 //    BADCHAR if the option is invalid (optarg points to the bad option char).
1066 //    BADKWD if the option is invalid (optarg points to the bad long-opt name).
1067 //    AMBIGUOUS if an ambiguous keyword name was given (optarg points to the
1068 //         ambiguous keyword name).
1069 //    POSITIONAL if PARSE_POS was set and the current argument is a positional
1070 //         parameter (in which case optarg points to the positional argument).
1071 //
1072 // ^ALGORITHM:
1073 //    It gets complicated -- follow the comments in the source.
1074 // ^^-------------------------------------------------------------------------
1075 int
1076 Options::operator()(OptIter & iter, const char * & optarg) {
1077    int parse_opts_only = isOptsOnly(optctrls);
1078    if (parse_opts_only)  explicit_end = 0;
1079
1080       // See if we have an option left over from before ...
1081    if ((nextchar) && *nextchar) {
1082       return  parse_opt(iter, optarg);
1083    }
1084
1085       // Check for end-of-options ...
1086    const char * arg = NULLSTR;
1087    int get_next_arg = 0;
1088    do {
1089       arg = iter.curr();
1090       get_next_arg = 0;
1091       if (arg == NULL) {
1092          listopt = NULLSTR;
1093          return  Options::ENDOPTS;
1094       } else if ((! explicit_end) && isEndOpts(arg)) {
1095          iter.next();   // advance past end-of-options arg
1096          listopt = NULLSTR;
1097          explicit_end = 1;
1098          if (parse_opts_only)  return  Options::ENDOPTS;
1099          get_next_arg = 1;  // make sure we look at the next argument.
1100       }
1101    } while (get_next_arg);
1102
1103       // Do we have a positional arg?
1104    if ( explicit_end || (! isOption(optctrls, arg)) ) {
1105       if (parse_opts_only) {
1106          return  Options::ENDOPTS;
1107       } else {
1108          optarg = arg;  // set optarg to the positional argument
1109          iter.next();   // advance iterator to the next argument
1110          return  Options::POSITIONAL;
1111       }
1112    }
1113
1114    iter.next();  // pass the argument that arg already points to
1115
1116       // See if we have a long option ...
1117    if (! (optctrls & Options::SHORT_ONLY)) {
1118       if ((*arg == '-') && (arg[1] == '-')) {
1119          nextchar = arg + 2;
1120          return  parse_longopt(iter, optarg);
1121       } else if ((optctrls & Options::PLUS) && (*arg == '+')) {
1122          nextchar = arg + 1;
1123          return  parse_longopt(iter, optarg);
1124       }
1125    }
1126    if (*arg == '-') {
1127       nextchar = arg + 1;
1128       if (optctrls & Options::LONG_ONLY) {
1129          return  parse_longopt(iter, optarg);
1130       } else {
1131          return  parse_opt(iter, optarg);
1132       }
1133    }
1134
1135       // If we get here - it is because we have a list value
1136    OptionSpec  optspec = listopt;
1137    optarg = arg ;        // record the list value
1138    return  optspec.OptChar() ;
1139 }
1140