home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume31 / options / part02 < prev    next >
Encoding:
Text File  |  1992-07-26  |  16.7 KB  |  560 lines

  1. Newsgroups: comp.sources.misc
  2. From: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
  3. Subject:  v31i046:  options - C++ library for parsing Unix-style command-lines, Part02/02
  4. Message-ID: <1992Jul27.015253.28370@sparky.imd.sterling.com>
  5. X-Md4-Signature: f4a5779bc3968a6f186478842907a7c9
  6. Date: Mon, 27 Jul 1992 01:52:53 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
  10. Posting-number: Volume 31, Issue 46
  11. Archive-name: options/part02
  12. Environment: C++
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then feed it
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  19. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  20. # Contents:  Makefile options.h
  21. # Wrapped by kent@sparky on Sun Jul 26 20:47:44 1992
  22. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  23. echo If this archive is complete, you will see the following message:
  24. echo '          "shar: End of archive 2 (of 2)."'
  25. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'Makefile'\"
  27. else
  28.   echo shar: Extracting \"'Makefile'\" \(1464 characters\)
  29.   sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  30. X###
  31. X# operating-system dependent stuff
  32. X###
  33. X.UNIVERSE=att
  34. X
  35. X###
  36. X# target directories
  37. X#
  38. X#    NOTE: if you change INCDIR and LIBDIR then dont forget to change
  39. X#          their corresponding strings at the top of options.3!
  40. X###
  41. XLOCAL=/usr/local
  42. XINCDIR=${LOCAL}/include
  43. XLIBDIR=${LOCAL}/lib
  44. XMAN3DIR=/usr/man/local_man/man3
  45. X
  46. X###
  47. X# compilation options
  48. X###
  49. XCC=CC
  50. XCPLC=CC
  51. XINCLUDES=-I.
  52. X# OPT=-O
  53. XOPT=-g
  54. XTEST_DEFS=
  55. XUSR_DEFS=
  56. XDEFINES=${OS_DEFS} ${USR_DEFS} ${TEST_DEFS}
  57. XOPTIONS=
  58. XCFLAGS=${INCLUDES} ${DEFINES} ${OPT} ${OPTIONS}
  59. XCPLFLAGS=${OPT} ${INCLUDES} ${DEFINES} ${OPTIONS}
  60. X
  61. X###
  62. X# C++ Rules
  63. X###
  64. X.SUFFIXES : .C
  65. X.C.o : 
  66. X    ${CPLC} ${CPLFLAGS} -c $<
  67. X
  68. X###
  69. X# Source files
  70. X###
  71. XLIBHDRS=options.h
  72. XLIBSRCS=options.C
  73. XLIBTESTS=testopts.C
  74. X
  75. XSRCS=${LIBHDRS} ${LIBSRCS} ${LIBTESTS}
  76. XOBJS=options.o
  77. XLIBRARY=liboptions.a
  78. XDOCS=options.3
  79. X
  80. X
  81. X###
  82. X# target dependencies
  83. X###
  84. Xall: library test
  85. X
  86. Xinstall: library
  87. X    rm -f ${INCDIR}/options.h ${LIBDIR}/${LIBRARY}
  88. X    cp options.h ${INCDIR}/options.h
  89. X    cp ${LIBRARY} ${LIBDIR}/${LIBRARY}
  90. X
  91. Xinstallman:
  92. X    rm -f ${MAN3DIR}/options.3
  93. X    cp options.3 ${MAN3DIR}/options.3
  94. X
  95. Xlibrary: ${LIBRARY}
  96. X
  97. X${LIBRARY}: ${OBJS}
  98. X    ar -r $@ ${OBJS}
  99. X    ranlib $@
  100. X
  101. Xtest: testopts
  102. X
  103. Xtestopts: testopts.o ${LIBRARY}
  104. X    ${CPLC} -o $@ testopts.o ${LIBRARY}
  105. X
  106. X###
  107. X# maintenance dependencies
  108. X###
  109. Xclean:
  110. X    rm -f *.o core .exrc
  111. X
  112. Xclobber: clean
  113. X    rm -f tags testopts ${LIBRARY}
  114. X    
  115. Xshar:
  116. X    shar README ${SRCS} ${DOCS} Makefile >SHAR
  117. X
  118. X###
  119. X# object dependencies
  120. X###
  121. Xoptions.o: options.h
  122. X
  123. Xtestopts.o: options.h
  124. X
  125. END_OF_FILE
  126.   if test 1464 -ne `wc -c <'Makefile'`; then
  127.     echo shar: \"'Makefile'\" unpacked with wrong size!
  128.   fi
  129.   # end of 'Makefile'
  130. fi
  131. if test -f 'options.h' -a "${1}" != "-c" ; then 
  132.   echo shar: Will not clobber existing file \"'options.h'\"
  133. else
  134.   echo shar: Extracting \"'options.h'\" \(12980 characters\)
  135.   sed "s/^X//" >'options.h' <<'END_OF_FILE'
  136. X// ****************************************************************************
  137. X// ^FILE: options.h - option parsing classes
  138. X//
  139. X// ^DESCRIPTION:
  140. X//    This file defines classes used to parse command-line options.
  141. X//    Options may be parsed from an array of strings, or from any structure
  142. X//    for which a corresponding option-iterator exists.
  143. X//
  144. X// ^HISTORY:
  145. X//    03/06/92  Brad Appleton   <brad@ssd.csd.harris.com>   Created
  146. X// ^^**************************************************************************
  147. X
  148. X#ifndef _options_h
  149. X#define _options_h
  150. X
  151. Xclass  ostream;
  152. X
  153. X// Abstract class to iterate through options/arguments
  154. X//
  155. Xclass OptIter {
  156. Xpublic:
  157. X   OptIter(void) {}
  158. X   virtual ~OptIter(void);
  159. X
  160. X      // curr() returns the current item in the iterator without
  161. X      // advancing on to the next item. If we are at the end of items
  162. X      // then NULL is returned.
  163. X   virtual const char *
  164. X   curr(void) = 0;
  165. X
  166. X      // next() advances to the next item.
  167. X   virtual void
  168. X   next(void) = 0;
  169. X
  170. X      // operator() returns the current item in the iterator and then
  171. X      // advances on to the next item. If we are at the end of items
  172. X      // then NULL is returned.
  173. X   virtual const char *
  174. X   operator()(void);
  175. X} ;
  176. X
  177. X// Abstract class for a rewindable OptIter
  178. X//
  179. Xclass OptIterRwd : public OptIter {
  180. Xpublic:
  181. X   OptIterRwd(void);
  182. X
  183. X   virtual ~OptIterRwd(void);
  184. X
  185. X   virtual const char *
  186. X   curr(void) = 0;
  187. X
  188. X   virtual void
  189. X   next(void) = 0;
  190. X
  191. X   virtual const char *
  192. X   operator()(void) = 0;
  193. X
  194. X      // rewind() resets the "current-element" to the first one in the "list"
  195. X   virtual void
  196. X   rewind(void) = 0;
  197. X} ;
  198. X
  199. X// Class to iterate through an array of tokens. The array may be terminated
  200. X// by NULL or a count containing the number of tokens may be given.
  201. X//
  202. Xclass OptArgvIter : public OptIterRwd {
  203. Xprivate:
  204. X   int            ndx;   // index of current arg
  205. X   int            ac;    // arg count
  206. X   const char * const * av;  // arg vector
  207. X
  208. Xpublic:
  209. X   OptArgvIter(const char * const argv[])
  210. X      : av(argv), ac(-1), ndx(0) {}
  211. X
  212. X   OptArgvIter(int argc, const char * const argv[])
  213. X      : av(argv), ac(argc), ndx(0) {}
  214. X
  215. X   virtual
  216. X   ~OptArgvIter(void);
  217. X
  218. X   virtual const char *
  219. X   curr(void);
  220. X
  221. X   virtual void
  222. X   next(void);
  223. X
  224. X   virtual const char *
  225. X   operator()(void);
  226. X
  227. X   virtual void
  228. X   rewind(void);
  229. X
  230. X      // index returns the current index to use for argv[]
  231. X   int index(void)  { return  ndx; }
  232. X} ;
  233. X
  234. X
  235. X// Class to iterate through a string containing delimiter-separated tokens
  236. X//
  237. Xclass OptStrTokIter : public OptIterRwd {
  238. Xprivate:
  239. X   unsigned     len;        // length of token-string
  240. X   const char * str;        // the token-string
  241. X   const char * seps;       // delimiter-set (separator-characters)
  242. X   const char * cur;        // current token
  243. X   char       * tokstr;     // our copy of the token-string
  244. X
  245. X   static const char * default_delims;  // default delimiters = whitespace
  246. X
  247. Xpublic:
  248. X   OptStrTokIter(const char * tokens, const char * delimiters =0);
  249. X
  250. X   virtual
  251. X   ~OptStrTokIter(void);
  252. X
  253. X   virtual const char *
  254. X   curr(void);
  255. X
  256. X   virtual void
  257. X   next(void);
  258. X
  259. X   virtual const char *
  260. X   operator()(void);
  261. X
  262. X   virtual void
  263. X   rewind(void);
  264. X
  265. X      // delimiters() with NO arguments returns the current set of delimiters,
  266. X      // If an argument is given then it is used as the new set of delimiters.
  267. X   const char *
  268. X   delimiters(void)  { return  seps; }
  269. X
  270. X   void
  271. X   delimiters(const char * delims) {
  272. X      seps = (delims) ? delims : default_delims ;
  273. X   }
  274. X} ;
  275. X
  276. X
  277. X// Now we are ready to define a class to declare and parse command-options
  278. X//
  279. X//
  280. X// CLASS
  281. X// =====
  282. X// Options  -- parse command-line options
  283. X//
  284. X// SYNOPSIS
  285. X// ========
  286. X//   #include <options.h>
  287. X//
  288. X//   Options opts(cmdname, optv);
  289. X//   char cmdname[], *optv[];
  290. X//
  291. X// DESCRIPTION
  292. X// ===========
  293. X// The Options constructor expects a command-name (usually argv[0]) and
  294. X// a pointer to an array of strings.  The last element in this array MUST
  295. X// be NULL. Each non-NULL string in the array must have the following format:
  296. X//
  297. X//   The 1st character must be the option-name ('c' for a -c option).
  298. X//
  299. X//   The 2nd character must be one of '|', '?', ':', '*', or '+'.
  300. X//      '|' -- indicates that the option takes NO argument;
  301. X//      '?' -- indicates that the option takes an OPTIONAL argument;
  302. X//      ':' -- indicates that the option takes a REQUIRED argument;
  303. X//      '*' -- indicates that the option takes 0 or more arguments;
  304. X//      '+' -- indicates that the option takes 1 or more arguments;
  305. X//
  306. X//   The remainder of the string must be the long-option name.
  307. X//
  308. X//   If desired, the long-option name may be followed by one or more
  309. X//   spaces and then by the name of the option value. This name will
  310. X//   be used when printing usage messages. If the option-value-name
  311. X//   is not given then the string "<value>" will be used in usage
  312. X//   messages.
  313. X//
  314. X//   One may use a space to indicate that a particular option does not
  315. X//   have a corresponding long-option.  For example, "c: " (or "c:")
  316. X//   means the -c option takes a value & has NO corresponding long-option.
  317. X//
  318. X//   To specify a long-option that has no corresponding single-character
  319. X//   option is a bit trickier: Options::operator() still needs an "option-
  320. X//   character" to return when that option is matched. One may use a whitespace
  321. X//   character or a non-printable character as the single-character option
  322. X//   in such a case. (hence " |hello" would only match "--hello").
  323. X//
  324. X//   EXCEPTIONS TO THE ABOVE:
  325. X//   ------------------------ 
  326. X//   If the 2nd character of the string is '\0' then it is assumed
  327. X//   that there is no corresponding long-option and that the option
  328. X//   takes no argument (hence "f", and "f| " are equivalent).
  329. X//
  330. X//   Examples:
  331. X//      const char * optv[] = {
  332. X//          "c:count   <number>",
  333. X//          "s?str     <string>",
  334. X//          "x",
  335. X//          " |hello",
  336. X//          "g+groups  <newsgroup>",
  337. X//          NULL
  338. X//      } ;
  339. X//
  340. X//      optv[] now corresponds to the following:
  341. X//
  342. X//            usage: cmdname [-c|--count <number>] [-s|--str [<string>]]
  343. X//                           [-x] [--hello] [-g|--groups <newsgroup> ...]
  344. X//
  345. X// Long-option names are matched case-insensitive and only a unique prefix
  346. X// of the name needs to be specified.
  347. X//
  348. X// Option-name characters are case-sensitive!
  349. X//
  350. X// CAVEAT
  351. X// ======
  352. X// Because of the way in which multi-valued options and options with optional
  353. X// values are handled, it is NOT possible to supply a value to an option in
  354. X// a separate argument (different argv[] element) if the value is OPTIONAL
  355. X// and begins with a '-'. What this means is that if an option "-s" takes an
  356. X// optional value value and you wish to supply a value of "-foo" then you must
  357. X// specify this on the command-line as "-s-foo" instead of "-s -foo" because
  358. X// "-s -foo" will be considered to be two separate sets of options.
  359. X//
  360. X// A multi-valued option is terminated by another option or by the end-of
  361. X// options. The following are all equivalent (if "-l" is a multi-valued
  362. X// option and "-x" is an option that takes no value):
  363. X//
  364. X//    cmdname -x -l item1 item2 item3 -- arg1 arg2 arg3
  365. X//    cmdname -x -litem1 -litem2 -litem3 -- arg1 arg2 arg3
  366. X//    cmdname -l item1 item2 item3 -x arg1 arg2 arg3
  367. X//
  368. X//
  369. X// EXAMPLE
  370. X// =======
  371. X//    #include <options.h>
  372. X//
  373. X//    static const char * optv[] = {
  374. X//       "H|help",
  375. X//       "c:count   <number>",
  376. X//       "s?str     <string>",
  377. X//       "x",
  378. X//       " |hello",
  379. X//       "g+groups  <newsgroup>",
  380. X//       NULL
  381. X//    } ;
  382. X//
  383. X//    main(int argc, char * argv[]) {
  384. X//       int  optchar;
  385. X//       const char * optarg;
  386. X//       const char * str = "default_string";
  387. X//       int  count = 0, xflag = 0, hello = 0;
  388. X//       int  errors = 0, ngroups = 0;
  389. X//    
  390. X//       Options  opts(*argv, optv);
  391. X//       OptArgvIter  iter(--argc, ++argv);
  392. X//    
  393. X//       while( optchar = opts(iter, optarg) ) {
  394. X//          switch (optchar) {
  395. X//          case 'H' :
  396. X//             opts.usage(cout, "files ...");
  397. X//             exit(0);
  398. X//             break;
  399. X//          case 'g' :
  400. X//             ++ngroups; break;  // the groupname is in "optarg"
  401. X//          case 's' :
  402. X//             str = optarg; break;
  403. X//          case 'x' :
  404. X//             ++xflag; break;
  405. X//          case ' ' :
  406. X//             ++hello; break;
  407. X//          case 'c' :
  408. X//             if (optarg == NULL)  ++errors;
  409. X//             else  count = (int) atol(optarg);
  410. X//             break;
  411. X//          default :  ++errors; break;
  412. X//          } //switch
  413. X//       }
  414. X//    
  415. X//       if (errors || (iter.index() == argc)) {
  416. X//          if (! errors) {
  417. X//             cerr << opts.name() << ": no filenames given." << endl ;
  418. X//          }
  419. X//          opts.usage(cerr, "files ...");
  420. X//          exit(1);
  421. X//       }
  422. X//    
  423. X//       cout << "xflag=" << ((xflag) ? "ON"  : "OFF") << endl
  424. X//            << "hello=" << ((hello) ? "YES" : "NO") << endl
  425. X//            << "count=" << count << endl
  426. X//            << "str=\"" << ((str) ? str : "No value given!") << "\"" << endl
  427. X//            << "ngroups=" << ngroups << endl ;
  428. X//    
  429. X//       if (iter.index() < argc) {
  430. X//          cout << "files=" ;
  431. X//          for (int i = iter.index() ; i < argc ; i++) {
  432. X//             cout << "\"" << argv[i] << "\" " ;
  433. X//          }
  434. X//          cout << endl ;
  435. X//       }
  436. X//    }
  437. X//
  438. Xclass Options {
  439. Xprivate:
  440. X   unsigned       explicit_end : 1;  // were we terminated because of "--"?
  441. X   unsigned       optctrls : 7;  // control settings (a set of OptCtrl masks)
  442. X   const char  * const * optvec; // vector of option-specifications (last=NULL)
  443. X   const char   * nextchar;      // next option-character to process
  444. X   const char   * listopt;       // last list-option we matched
  445. X   const char   * cmdname;       // name of the command
  446. X
  447. X   int
  448. X   parse_opt(OptIter & iter, const char * & optarg);
  449. X
  450. X   int
  451. X   parse_longopt(OptIter & iter, const char * & optarg);
  452. X
  453. X   unsigned
  454. X   fmt_opt(const char * optspec, char * buf) const;
  455. X
  456. Xpublic:
  457. X   enum OptCtrl {
  458. X      DEFAULT    = 0x00,  // Default setting
  459. X      ANYCASE    = 0x01,  // Ignore case when matching short-options
  460. X      QUIET      = 0x02,  // Dont print error messages
  461. X      PLUS       = 0x04,  // Allow "+" as a long-option prefix
  462. X      SHORT_ONLY = 0x08,  // Dont accept long-options
  463. X      LONG_ONLY  = 0x10,  // Dont accept short-options
  464. X                            // (also allows "-" as a long-option prefix).
  465. X      NOGUESSING = 0x20,  // Normally, when we see a short (long) option
  466. X                            // on the command line that doesnt match any
  467. X                            // known short (long) options, then we try to
  468. X                            // "guess" by seeing if it will match any known
  469. X                            // long (short) option. Setting this mask prevents
  470. X                            // this "guessing" from occurring.
  471. X   } ;
  472. X
  473. X      // Error return values for operator()
  474. X      //
  475. X   enum OptRC {
  476. X      ENDOPTS    =  0,
  477. X      BADCHAR    = -1,
  478. X      BADKWD     = -2,
  479. X      AMBIGUOUS  = -3,
  480. X   } ;
  481. X
  482. X   Options(const char * name, const char * const optv[]);
  483. X
  484. X   virtual
  485. X   ~Options(void);
  486. X
  487. X      // name() returns the command name
  488. X   const char *
  489. X   name(void) const { return  cmdname; }
  490. X
  491. X      // ctrls() (with no arguments) returns the existing control settings
  492. X   unsigned
  493. X   ctrls(void) const { return  optctrls; }
  494. X
  495. X      // ctrls() (with 1 argument) sets new control settings
  496. X   void
  497. X   ctrls(unsigned newctrls) { optctrls = newctrls; }
  498. X
  499. X      // usage() prints options usage (followed by any positional arguments
  500. X      // listed in the parameter "positionals") on the given outstream
  501. X   void
  502. X   usage(ostream & os, const char * positionals) const ;
  503. X
  504. X      // operator() iterates through the arguments as necessary (using the
  505. X      // given iterator) and returns the character value of the option
  506. X      // (or long-option) that it matched. If the option has a value
  507. X      // then the value given may be found in optarg (otherwise optarg
  508. X      // will be NULL).
  509. X      //
  510. X      // 0 is returned upon end-of-options. At this point, "iter" may
  511. X      // be used to process any remaining positional parameters.
  512. X      //
  513. X      // If an invalid option is found then BADCHAR is returned and *optarg
  514. X      // is the unrecognized option character.
  515. X      //
  516. X      // If an invalid long-option is found then BADKWD is returned and optarg
  517. X      // points to the bad long-option.
  518. X      //
  519. X      // If an ambiguous long-option is found then AMBIGUOUS is returned and
  520. X      // optarg points to the ambiguous long-option.
  521. X      //
  522. X      // Unless Options::QUIET is used, missing option-arguments and
  523. X      // invalid options (and the like) will automatically cause error
  524. X      // messages to be issued to cerr.
  525. X   int
  526. X   operator()(OptIter & iter, const char * & optarg) ;
  527. X
  528. X      // Call this member function after operator() has returned 0
  529. X      // if you want to know whether or not options were explicitly
  530. X      // terminated because "--" appeared on the command-line.
  531. X      //
  532. X   int
  533. X   explicit_endopts() const { return  explicit_end; }
  534. X} ;
  535. X
  536. X#endif /* _options_h */
  537. END_OF_FILE
  538.   if test 12980 -ne `wc -c <'options.h'`; then
  539.     echo shar: \"'options.h'\" unpacked with wrong size!
  540.   fi
  541.   # end of 'options.h'
  542. fi
  543. echo shar: End of archive 2 \(of 2\).
  544. cp /dev/null ark2isdone
  545. MISSING=""
  546. for I in 1 2 ; do
  547.     if test ! -f ark${I}isdone ; then
  548.     MISSING="${MISSING} ${I}"
  549.     fi
  550. done
  551. if test "${MISSING}" = "" ; then
  552.     echo You have unpacked both archives.
  553.     rm -f ark[1-9]isdone
  554. else
  555.     echo You still must unpack the following archives:
  556.     echo "        " ${MISSING}
  557. fi
  558. exit 0
  559. exit 0 # Just in case...
  560.