1 // ****************************************************************************
2 // ^FILE: options.c - implement the functions defined in <options.h>
5 // 01/16/92 Brad Appleton <bradapp@enteract.com> Created
7 // 03/23/93 Brad Appleton <bradapp@enteract.com>
8 // - Added OptIstreamIter class
10 // 10/08/93 Brad Appleton <bradapp@enteract.com>
11 // - Added "hidden" options
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
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
22 // 07/31/97 Brad Appleton <bradapp@enteract.com>
23 // - Added PARSE_POS control flag and POSITIONAL return value.
24 // ^^**************************************************************************
26 // #include <stdlib.h>
38 static const char ident[] = "@(#)Options 1.05" ;
40 // I need a portable version of "tolower" that does NOT modify
41 // non-uppercase characters.
43 #define TOLOWER(c) (isupper(c) ? tolower(c) : c)
45 // Use this to shut the compiler up about NULL strings
46 #define NULLSTR (char *)NULL
48 // ******************************************************** insertion operators
50 // If you are using <stdio.h> then you need this stuff!
51 // If you are using <iostream.h> then #ifdef this stuff out
57 // Implement just enough of ostream to get this file to compile
60 static const char endl = '\n' ;
64 ostream(FILE * fileptr) : fp(fileptr) {}
70 operator<<(const char * str);
73 write(const char * buf, unsigned bufsize);
80 ostream::operator<<(char ch) {
86 ostream::operator<<(const char * str) {
92 ostream::write(const char * buf, unsigned ) {
97 static ostream cerr(stderr);
98 static ostream cout(stdout);
100 #endif /* USE_STDIO */
102 // ************************************************************** OptIter
104 OptIter::~OptIter(void) {}
107 OptIter::operator()(void) {
108 const char * elt = curr();
113 // ************************************************************** OptIterRwd
115 OptIterRwd::OptIterRwd(void) {}
117 OptIterRwd::~OptIterRwd(void) {}
119 // ************************************************************** OptArgvIter
121 OptArgvIter::~OptArgvIter(void) {}
124 OptArgvIter::curr(void) {
125 return ((ndx == ac) || (av[ndx] == NULL)) ? NULLSTR : av[ndx];
129 OptArgvIter::next(void) {
130 if ((ndx != ac) && av[ndx]) ++ndx;
134 OptArgvIter::operator()(void) {
135 return ((ndx == ac) || (av[ndx] == NULL)) ? NULLSTR : av[ndx++];
139 OptArgvIter::rewind(void) { ndx = 0; }
141 // ************************************************************** OptStrTokIter
143 static const char WHITESPACE[] = " \t\n\r\v\f" ;
144 const char * OptStrTokIter::default_delims = WHITESPACE ;
146 OptStrTokIter::OptStrTokIter(const char * tokens, const char * delimiters)
147 : len(unsigned(strlen(tokens))), str(tokens), seps(delimiters),
148 cur(NULLSTR), tokstr(NULLSTR)
150 if (seps == NULL) seps = default_delims;
151 tokstr = new char[len + 1];
152 (void) ::strcpy(tokstr, str);
153 cur = ::strtok(tokstr, seps);
157 OptStrTokIter::~OptStrTokIter(void) { delete [] tokstr; }
160 OptStrTokIter::curr(void) { return cur; }
163 OptStrTokIter::next(void) { if (cur) cur = ::strtok(NULL, seps); }
166 OptStrTokIter::operator()(void) {
167 const char * elt = cur;
168 if (cur) cur = ::strtok(NULL, seps);
173 OptStrTokIter::rewind(void) {
174 (void) ::strcpy(tokstr, str);
175 cur = ::strtok(tokstr, seps);
178 // ************************************************************* OptIstreamIter
181 enum { c_COMMENT = '!' } ;
183 enum { c_COMMENT = '#' } ;
186 const unsigned OptIstreamIter::MAX_LINE_LEN = 1024 ;
189 OptIstreamIter::OptIstreamIter(istream & input) : is(input), tok_iter(NULL)
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");
196 #endif /* USE_STDIO */
200 OptIstreamIter::~OptIstreamIter(void) {
205 OptIstreamIter::curr(void) {
209 const char * result = NULLSTR;
210 if (tok_iter) result = tok_iter->curr();
211 if (result) return result;
213 return (! is) ? NULLSTR : tok_iter->curr();
214 #endif /* USE_STDIO */
218 OptIstreamIter::next(void) {
222 const char * result = NULLSTR;
223 if (tok_iter) result = tok_iter->operator()();
226 if (! is) tok_iter->next();
227 #endif /* USE_STDIO */
231 OptIstreamIter::operator()(void) {
235 const char * result = NULLSTR;
236 if (tok_iter) result = tok_iter->operator()();
237 if (result) return result;
239 return (! is) ? NULLSTR : tok_iter->operator()();
240 #endif /* USE_STDIO */
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.
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.
250 OptIstreamIter::fill(void) {
254 char buf[OptIstreamIter::MAX_LINE_LEN];
257 is.getline(buf, sizeof(buf));
259 while (isspace(*ptr)) ++ptr;
260 if (*ptr && (*ptr != c_COMMENT)) {
262 tok_iter = new OptStrTokIter(ptr);
266 #endif /* USE_STDIO */
269 // **************************************************** Options class utilities
271 // Is this option-char null?
273 isNullOpt(char optchar) {
274 return ((! optchar) || isspace(optchar) || (! isprint(optchar)));
277 // Check for explicit "end-of-options"
279 isEndOpts(const char * token) {
280 return ((token == NULL) || (! ::strcmp(token, "--"))) ;
283 // See if an argument is an option
285 isOption(unsigned flags, const char * arg) {
286 return (((*arg != '\0') || (arg[1] != '\0')) &&
287 ((*arg == '-') || ((flags & Options::PLUS) && (*arg == '+')))) ;
290 // See if we should be parsing only options or if we also need to
291 // parse positional arguments
293 isOptsOnly(unsigned flags) {
294 return (flags & Options::PARSE_POS) ? 0 : 1;
297 // return values for a keyword matching function
298 enum kwdmatch_t { NO_MATCH, PARTIAL_MATCH, EXACT_MATCH } ;
300 // ---------------------------------------------------------------------------
301 // ^FUNCTION: kwdmatch - match a keyword
304 // static kwdmatch_t kwdmatch(src, attempt, len)
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")
313 // See if "attempt" matches some prefix of "src" (case insensitive).
316 // - attempt should be non-NULL and non-empty
322 // An enumeration value of type kwdmatch_t corresponding to whether
323 // We had an exact match, a partial match, or no match.
327 // ^^-------------------------------------------------------------------------
329 kwdmatch(const char * src, const char * attempt, int len =0) {
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 ;
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 ;
342 return (src[i]) ? PARTIAL_MATCH : EXACT_MATCH ;
345 // **************************************************************** OptionSpec
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.
354 OptionSpec(const char * decl =NULLSTR)
355 : hidden(0), spec(decl)
357 if (spec == NULL) spec = NULL_spec;
361 OptionSpec(const OptionSpec & cp) : hidden(cp.hidden), spec(cp.spec) {}
363 // NOTE: use default destructor!
365 // Assign to another OptionSpec
367 operator=(const OptionSpec & cp) {
375 // Assign to a string
377 operator=(const char * decl) {
386 // Convert to char-ptr by returning the original declaration-string
387 operator const char*() { return isHiddenOpt() ? (spec - 1) : spec; }
389 // Is this option NULL?
391 isNULL(void) const { return ((spec == NULL) || (spec == NULL_spec)); }
393 // Is this options incorrectly specified?
395 isSyntaxError(const char * name) const;
397 // See if this is a Hidden option
399 isHiddenOpt(void) const { return hidden; }
401 // Get the corresponding option-character
403 OptChar(void) const { return *spec; }
405 // Get the corresponding long-option string
407 LongOpt(void) const {
408 return (spec[1] && spec[2] && (! isspace(spec[2]))) ? (spec + 2) : NULLSTR;
411 // Does this option require an argument?
413 isValRequired(void) const {
414 return ((spec[1] == ':') || (spec[1] == '+'));
417 // Does this option take an optional argument?
419 isValOptional(void) const {
420 return ((spec[1] == '?') || (spec[1] == '*'));
423 // Does this option take no arguments?
425 isNoArg(void) const {
426 return ((spec[1] == '|') || (! spec[1]));
429 // Can this option take more than one argument?
432 return ((spec[1] == '+') || (spec[1] == '*'));
435 // Does this option take any arguments?
437 isValTaken(void) const {
438 return (isValRequired() || isValOptional()) ;
441 // Format this option in the given buffer
443 Format(char * buf, unsigned optctrls) const;
448 if ((! hidden) && (*spec == '-')) {
454 unsigned hidden : 1; // hidden-flag
455 const char * spec; // string specification
457 static const char NULL_spec[];
460 const char OptionSpec::NULL_spec[] = "\0\0\0" ;
463 OptionSpec::isSyntaxError(const char * name) const {
465 if ((! spec) || (! *spec)) {
466 cerr << name << ": empty option specifier." << endl;
467 cerr << "\tmust be at least 1 character long." << endl;
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;
477 // ---------------------------------------------------------------------------
478 // ^FUNCTION: OptionSpec::Format - format an option-spec for a usage message
481 // unsigned OptionSpec::Format(buf, optctrls) const
484 // char * buf -- where to print the formatted option
485 // unsigned optctrls -- option-parsing configuration flags
491 // - buf must be large enough to hold the result
497 // Number of characters written to buf.
500 // Follow along in the source - it's not hard but it is tedious!
501 // ^^-------------------------------------------------------------------------
503 OptionSpec::Format(char * buf, unsigned optctrls) const {
505 return (*buf = '\0');
507 static char default_value[] = "<value>";
508 if (isHiddenOpt()) return (unsigned)(*buf = '\0');
509 char optchar = OptChar();
510 const char * longopt = LongOpt();
513 const char * value = NULLSTR;
518 value = ::strchr(longopt, ' ');
519 longopt_len = (value) ? (value - longopt) : ::strlen(longopt);
521 value = ::strchr(spec + 1, ' ');
523 while (value && (*value == ' ')) ++value;
524 if (value && *value) {
525 value_len = ::strlen(value);
527 value = default_value;
528 value_len = sizeof(default_value) - 1;
531 if ((optctrls & Options::SHORT_ONLY) &&
532 ((! isNullOpt(optchar)) || (optctrls & Options::NOGUESSING))) {
535 if ((optctrls & Options::LONG_ONLY) &&
536 (longopt || (optctrls & Options::NOGUESSING))) {
539 if (isNullOpt(optchar) && (longopt == NULL)) {
546 // print the single character option
547 if (! isNullOpt(optchar)) {
552 if ((! isNullOpt(optchar)) && (longopt)) *(p++) = '|';
554 // print the long option
557 if (! (optctrls & (Options::LONG_ONLY | Options::SHORT_ONLY))) {
560 strncpy(p, longopt, longopt_len);
564 // print any argument the option takes
567 if (isValOptional()) *(p++) = '[' ;
574 if (isValOptional()) *(p++) = ']' ;
580 return (unsigned) strlen(buf);
581 #endif /* USE_STDIO */
584 // ******************************************************************* Options
586 #if (defined(MSWIN) || defined(OS2) || defined(MSDOS))
587 # define DIR_SEP_CHAR '\\'
589 # define DIR_SEP_CHAR '/'
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)
596 const char * basename = ::strrchr(cmdname, DIR_SEP_CHAR);
597 if (basename) cmdname = basename + 1;
601 Options::~Options(void) {}
603 // Make sure each option-specifier has correct syntax.
605 // If there is even one invalid specifier, then exit ungracefully!
608 Options::check_syntax(void) const {
610 if ((optvec == NULL) || (! *optvec)) return;
612 for (const char * const * optv = optvec ; *optv ; optv++) {
613 OptionSpec optspec = *optv;
614 errors += optspec.isSyntaxError(cmdname);
616 if (errors) exit(127);
619 // ---------------------------------------------------------------------------
620 // ^FUNCTION: Options::match_opt - match an option
623 // const char * match_opt(opt, int ignore_case) const
626 // char opt -- the option-character to match
627 // int ignore_case -- should we ignore character-case?
630 // See if "opt" is found in "optvec"
633 // - optvec should be non-NULL and terminated by a NULL pointer.
639 // NULL if no match is found,
640 // otherwise a pointer to the matching option-spec.
643 // foreach option-spec
644 // - see if "opt" is a match, if so return option-spec
646 // ^^-------------------------------------------------------------------------
648 Options::match_opt(char opt, int ignore_case) const {
649 if ((optvec == NULL) || (! *optvec)) return NULLSTR;
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) {
657 } else if (ignore_case && (TOLOWER(opt) == TOLOWER(optchar))) {
662 return NULLSTR; // not found
665 // ---------------------------------------------------------------------------
666 // ^FUNCTION: Options::match_longopt - match a long-option
669 // const char * Options::match_longopt(opt, len, ambiguous)
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.
677 // Try to match "opt" against some unique prefix of a long-option
678 // (case insensitive).
681 // - optvec should be non-NULL and terminated by a NULL pointer.
684 // - *ambiguous is set to '1' if "opt" matches >1 long-option
685 // (otherwise it is set to 0).
688 // NULL if no match is found,
689 // otherwise a pointer to the matching option-spec.
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
699 // remember this options spec and continue matching
703 // if we had exactly 1 partial match return it, else return NULL
704 // ^^-------------------------------------------------------------------------
706 Options::match_longopt(const char * opt, int len, int & ambiguous) const {
708 const char * matched = NULLSTR ;
711 if ((optvec == NULL) || (! *optvec)) return NULLSTR;
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) {
720 } else if (result == PARTIAL_MATCH) {
733 // ---------------------------------------------------------------------------
734 // ^FUNCTION: Options::parse_opt - parse an option
737 // int Options::parse_opt(iter, optarg)
740 // OptIter & iter -- option iterator
741 // const char * & optarg -- where to store any option-argument
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.
749 // - nextchar must point to the prospective option character
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
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).
762 // It gets complicated -- follow the comments in the source.
763 // ^^-------------------------------------------------------------------------
765 Options::parse_opt(OptIter & iter, const char * & optarg) {
766 listopt = NULLSTR; // reset the list pointer
768 if ((optvec == NULL) || (! *optvec)) return Options::ENDOPTS;
770 // Try to match a known option
771 OptionSpec optspec = match_opt(*(nextchar++), (optctrls & Options::ANYCASE));
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;
780 optctrls |= (Options::QUIET | Options::NOGUESSING);
781 int optchar = parse_longopt(iter, optarg);
782 optctrls = save_ctrls;
786 nextchar = save_nextchar;
789 if (! (optctrls & Options::QUIET)) {
790 cerr << cmdname << ": unknown option -"
791 << *(nextchar - 1) << "." << endl ;
793 optarg = (nextchar - 1); // record the bad option in optarg
794 return Options::BADCHAR;
797 // If no argument is taken, then leave now
798 if (optspec.isNoArg()) {
800 return optspec.OptChar();
803 // Check for argument in this arg
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();
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();
821 // No argument given - if its required, thats an error
823 if (optspec.isValRequired() && !(optctrls & Options::QUIET)) {
824 cerr << cmdname << ": argument required for -" << optspec.OptChar()
825 << " option." << endl ;
827 return optspec.OptChar();
830 // ---------------------------------------------------------------------------
831 // ^FUNCTION: Options::parse_longopt - parse a long-option
834 // int Options::parse_longopt(iter, optarg)
837 // OptIter & iter -- option iterator
838 // const char * & optarg -- where to store any option-argument
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.
846 // - nextchar must point to the prospective option character
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
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
860 // It gets complicated -- follow the comments in the source.
861 // ^^-------------------------------------------------------------------------
863 Options::parse_longopt(OptIter & iter, const char * & optarg) {
864 int len = 0, ambiguous = 0;
866 listopt = NULLSTR ; // reset the list-spec
868 if ((optvec == NULL) || (! *optvec)) return Options::ENDOPTS;
870 // if a value is supplied in this argv element, get it now
871 const char * val = strpbrk(nextchar, ":=") ;
873 len = val - nextchar ;
877 // Try to match a known long-option
878 OptionSpec optspec = match_longopt(nextchar, len, ambiguous);
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;
892 nextchar = save_nextchar;
895 if (! (optctrls & Options::QUIET)) {
896 cerr << cmdname << ": " << ((ambiguous) ? "ambiguous" : "unknown")
898 << ((optctrls & Options::LONG_ONLY) ? "-" : "--")
899 << nextchar << "." << endl ;
901 optarg = nextchar; // record the bad option in optarg
902 nextchar = NULLSTR; // we've exhausted this argument
903 return (ambiguous) ? Options::AMBIGUOUS : Options::BADKWD;
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 ;
913 optarg = val; // record the unexpected argument
914 nextchar = NULLSTR; // we've exhausted this argument
915 return optspec.OptChar();
918 // Check for argument in this arg
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();
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();
937 // No argument given - if its required, thats an error
939 if (optspec.isValRequired() && !(optctrls & Options::QUIET)) {
940 const char * longopt = optspec.LongOpt();
941 const char * spc = ::strchr(longopt, ' ');
944 longopt_len = spc - longopt;
946 longopt_len = ::strlen(longopt);
948 cerr << cmdname << ": argument required for "
949 << ((optctrls & Options::LONG_ONLY) ? "-" : "--");
950 cerr.write(longopt, longopt_len) << " option." << endl ;
952 nextchar = NULLSTR; // we exhausted the rest of this arg
953 return optspec.OptChar();
956 // ---------------------------------------------------------------------------
957 // ^FUNCTION: Options::usage - print usage
960 // void Options::usage(os, positionals)
963 // ostream & os -- where to print the usage
964 // char * positionals -- command-line syntax for any positional args
967 // Print command-usage (using either option or long-option syntax) on os.
970 // os should correspond to an open output file.
979 // Print usage on os, wrapping long lines where necessary.
980 // ^^-------------------------------------------------------------------------
982 Options::usage(ostream & os, const char * positionals) const {
986 const char * const * optv = optvec;
991 if ((optv == NULL) || (! *optv)) return;
993 // print first portion "usage: progname"
994 os << "usage: " << cmdname ;
995 unsigned ll = strlen(cmdname) + 7;
997 // save the current length so we know how much space to skip for
1000 unsigned margin = ll + 1;
1002 // print the options and the positional arguments
1003 for (nloop = 0, first = 1 ; !nloop ; optv++, first = 0) {
1005 OptionSpec optspec = *optv;
1007 // figure out how wide this parameter is (for printing)
1009 len = strlen(positionals);
1010 ++nloop; // terminate this loop
1012 if (optspec.isHiddenOpt()) continue;
1013 len = optspec.Format(buf, optctrls);
1017 if ((ll + len + 1) > (cols - first)) {
1018 os << '\n' ; // No - start a new line;
1020 for (int _i_ = 0; _i_ < margin; ++_i_) os << " ";
1022 os.width(margin); os << "" ;
1026 os << ' ' ; // Yes - just throw in a space
1030 os << ((nloop) ? positionals : buf) ;
1034 #endif /* NO_USAGE */
1038 // ---------------------------------------------------------------------------
1039 // ^FUNCTION: Options::operator() - get options from the command-line
1042 // int Options::operator()(iter, optarg)
1045 // OptIter & iter -- option iterator
1046 // const char * & optarg -- where to store any option-argument
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.
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
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).
1073 // It gets complicated -- follow the comments in the source.
1074 // ^^-------------------------------------------------------------------------
1076 Options::operator()(OptIter & iter, const char * & optarg) {
1077 int parse_opts_only = isOptsOnly(optctrls);
1078 if (parse_opts_only) explicit_end = 0;
1080 // See if we have an option left over from before ...
1081 if ((nextchar) && *nextchar) {
1082 return parse_opt(iter, optarg);
1085 // Check for end-of-options ...
1086 const char * arg = NULLSTR;
1087 int get_next_arg = 0;
1093 return Options::ENDOPTS;
1094 } else if ((! explicit_end) && isEndOpts(arg)) {
1095 iter.next(); // advance past end-of-options arg
1098 if (parse_opts_only) return Options::ENDOPTS;
1099 get_next_arg = 1; // make sure we look at the next argument.
1101 } while (get_next_arg);
1103 // Do we have a positional arg?
1104 if ( explicit_end || (! isOption(optctrls, arg)) ) {
1105 if (parse_opts_only) {
1106 return Options::ENDOPTS;
1108 optarg = arg; // set optarg to the positional argument
1109 iter.next(); // advance iterator to the next argument
1110 return Options::POSITIONAL;
1114 iter.next(); // pass the argument that arg already points to
1116 // See if we have a long option ...
1117 if (! (optctrls & Options::SHORT_ONLY)) {
1118 if ((*arg == '-') && (arg[1] == '-')) {
1120 return parse_longopt(iter, optarg);
1121 } else if ((optctrls & Options::PLUS) && (*arg == '+')) {
1123 return parse_longopt(iter, optarg);
1128 if (optctrls & Options::LONG_ONLY) {
1129 return parse_longopt(iter, optarg);
1131 return parse_opt(iter, optarg);
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() ;