home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume41 / options / patch03 next >
Encoding:
Internet Message Format  |  1994-03-06  |  54.5 KB

  1. From: brad@amber.ssd.csd.harris.com (Brad Appleton)
  2. Newsgroups: comp.sources.misc
  3. Subject: v41i160:  options - C++ library for parsing Unix-style command-lines, Patch03
  4. Date: 6 Mar 1994 22:50:03 -0600
  5. Organization: Harris Computer Systems
  6. Sender: root@sparky.sterling.com
  7. Approved: kent@sparky.sterling.com
  8. Message-ID: <2lebpr$h5g@sparky.sterling.com>
  9. Reply-To: brad@travis.csd.harris.com
  10. X-Md4-Signature: 3902fa663d240ab2147df673807b5601
  11.  
  12. Submitted-by: brad@amber.ssd.csd.harris.com (Brad Appleton)
  13. Posting-number: Volume 41, Issue 160
  14. Archive-name: options/patch03
  15. Environment: C++
  16. Patch-To: options: Volume 31, Issue 45-46
  17.  
  18. This is patch-level 3 of "Options", a C++ library for parsing
  19. Unix-style command-line options. Options understands options and
  20. gnu-long-options and the parsing behavior is somewhat configurable.
  21.  
  22.  To apply this patch:
  23.  --------------------
  24.    0) save this article to a file in your "Options" source directory
  25.  
  26.    1) "cd" to your Options source directory
  27.  
  28.    2) Remove all lines in the sharfile (the file you saved in #0)
  29.       that precede the line that starts with "#! /bin/sh".
  30.  
  31.    3) Run the command "sh sharfile" (or whatever you named your sharfile).
  32.       This will create a file named "PATCH03" in your current directory
  33.  
  34.    4) Run "patch -p0 < PATCH03"
  35.  
  36.  
  37.  Changes in this release:
  38.  ------------------------
  39.  - Added OptionSpec class to options.C
  40.  - Permitted use of stdio instead of iostreams via #ifdef USE_STDIO
  41.  
  42. For those of you who are unfamiliar with "Options", the following
  43. is an excerpt from the README file. You can send e-mail to me at
  44. brad@ssd.csd.harris.com if you want the complete C++ source.
  45.  
  46.  ------------------------------------------------------------------------------
  47.  
  48.  You "declare" your options by declaring an array of strings like so:
  49.  
  50.         const char * optv[] = {
  51.             "c:count <number>",
  52.             "s?str   <string>",
  53.             "x|xmode",
  54.             NULL
  55.         } ;
  56.   
  57.  Note the character (one of ':', '?', '|', '*', or '+') between the short
  58.  and long name of the option. It specifies the option type:
  59.  
  60.         '|' -- indicates that the option takes NO argument;
  61.         '?' -- indicates that the option takes an OPTIONAL argument;
  62.         ':' -- indicates that the option takes a REQUIRED argument;
  63.         '*' -- indicates that the option takes 0 or more arguments;
  64.         '+' -- indicates that the option takes 1 or more arguments;
  65.  
  66.  Using the above example, optv[] now corresponds to the following:
  67.  
  68.         progname [-c <number>] [-s [<string>]] [-x]
  69.  
  70.  Using long-options, optv corresponds to the following ("-" or "+" may
  71.  be used instead of "--" as the prefix):
  72.   
  73.         progname [--count <number>] [--str [<string>]] [--xmode]
  74.  
  75.  Now you can iterate over your options like so:
  76.  
  77.       #include <stdlib.h>
  78.       #include <options.h>
  79.  
  80.       main(int argc, char *argv[]) {
  81.          Options  opts(*argv, optv);
  82.          OptArgvIter  iter(--argc, ++argv);
  83.          const char *optarg, *str = NULL;
  84.          int  errors = 0, xflag = 0, count = 1;
  85.       
  86.          while( char optchar = opts(iter, optarg) ) {
  87.             switch (optchar) {
  88.             case 's' :
  89.                str = optarg; break;
  90.             case 'x' :
  91.                ++xflag; break;
  92.             case 'c' :
  93.                if (optarg == NULL)  ++errors;
  94.                else  count = (int) atol(optarg);
  95.                break;
  96.             default :  ++errors; break;
  97.             } //switch
  98.          }
  99.          ...  // process the rest of the arguments in "iter"
  100.       }
  101.  
  102. ------------------------------------------------------------------------------
  103. #! /bin/sh
  104. # This is a shell archive.  Remove anything before this line, then unpack
  105. # it by saving it into a file and typing "sh file".  To overwrite existing
  106. # files, type "sh file -c".  You can also feed this as standard input via
  107. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  108. # will see the following message at the end:
  109. #        "End of shell archive."
  110. # Contents:  PATCH03
  111. # Wrapped by brad@amber on Fri Feb 11 17:30:41 1994
  112. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  113. if test -f 'PATCH03' -a "${1}" != "-c" ; then 
  114.   echo shar: Will not clobber existing file \"'PATCH03'\"
  115. else
  116. echo shar: Extracting \"'PATCH03'\" \(49743 characters\)
  117. sed "s/^X//" >'PATCH03' <<'END_OF_FILE'
  118. X*** README.OLD    Fri Feb 11 17:30:08 1994
  119. X--- README    Wed Feb 09 09:21:44 1994
  120. X***************
  121. X*** 158,160 ****
  122. X--- 158,165 ----
  123. X   10/08/93        Brad Appleton        <brad@ssd.csd.harris.com>
  124. X   -----------------------------------------------------------------------------
  125. X   - Added "hidden" options
  126. X+ 
  127. X+  02/08/94        Brad Appleton        <brad@ssd.csd.harris.com>
  128. X+  -----------------------------------------------------------------------------
  129. X+  - Added OptionSpec class to options.C
  130. X+  - Permitted use of stdio instead of iostreams via #ifdef USE_STDIO
  131. X*** options.3.OLD    Fri Feb 11 17:30:10 1994
  132. X--- options.3    Fri Feb 11 16:59:40 1994
  133. X***************
  134. X*** 145,156 ****
  135. X  public:
  136. X     static const unsigned  MAX_LINE_LEN ;
  137. X  
  138. X- #ifdef vms
  139. X-    enum { c_COMMENT = '!' } ;
  140. X- #else
  141. X-    enum { c_COMMENT = '#' } ;
  142. X- #endif
  143. X- 
  144. X     OptIstreamIter(istream & input);
  145. X  
  146. X     virtual
  147. X--- 145,150 ----
  148. X*** options.C.OLD    Fri Feb 11 17:30:13 1994
  149. X--- options.C    Fri Feb 11 17:27:33 1994
  150. X***************
  151. X*** 9,18 ****
  152. X  //
  153. X  //    10/08/93    Brad Appleton    <brad@ssd.csd.harris.com>
  154. X  //    - Added "hidden" options
  155. X  // ^^**************************************************************************
  156. X  
  157. X  #include <stdlib.h>
  158. X- #include <iostream.h>
  159. X  #include <ctype.h>
  160. X  #include <string.h>
  161. X  
  162. X--- 9,27 ----
  163. X  //
  164. X  //    10/08/93    Brad Appleton    <brad@ssd.csd.harris.com>
  165. X  //    - Added "hidden" options
  166. X+ //
  167. X+ //    02/08/94    Brad Appleton    <brad@ssd.csd.harris.com>
  168. X+ //    - Added "OptionSpec" class
  169. X+ //    - Permitted use of stdio instead of iostreams via #ifdef USE_STDIO
  170. X  // ^^**************************************************************************
  171. X  
  172. X+ #ifdef USE_STDIO
  173. X+ # include <stdio.h>
  174. X+ #else
  175. X+ # include <iostream.h>
  176. X+ #endif
  177. X+ 
  178. X  #include <stdlib.h>
  179. X  #include <ctype.h>
  180. X  #include <string.h>
  181. X  
  182. X***************
  183. X*** 22,28 ****
  184. X     void  exit(int);
  185. X  }
  186. X  
  187. X! static const char ident[] = "@(#)Options  1.02" ;
  188. X  
  189. X     // I need a portable version of "tolower" that does NOT modify
  190. X     // non-uppercase characters.
  191. X--- 31,37 ----
  192. X     void  exit(int);
  193. X  }
  194. X  
  195. X! static const char ident[] = "@(#)Options  1.03" ;
  196. X  
  197. X     // I need a portable version of "tolower" that does NOT modify
  198. X     // non-uppercase characters.
  199. X***************
  200. X*** 29,34 ****
  201. X--- 38,86 ----
  202. X     //
  203. X  #define  TOLOWER(c)  (isupper(c) ? tolower(c) : c)
  204. X  
  205. X+ // ******************************************************** insertion operators
  206. X+ 
  207. X+   // If you are using <stdio.h> then you need this stuff!
  208. X+   // If you are using <iostream.h> then #ifdef this stuff out
  209. X+   //
  210. X+ 
  211. X+ 
  212. X+ #ifdef  USE_STDIO
  213. X+ 
  214. X+ static const char endl = '\n' ;
  215. X+ 
  216. X+ class  OutFILE {
  217. X+ public:
  218. X+    OutFILE(FILE * fileptr) : fp(fileptr) {}
  219. X+ 
  220. X+    OutFILE &
  221. X+    operator<<(char ch);
  222. X+ 
  223. X+    OutFILE &
  224. X+    operator<<(const char * str);
  225. X+ 
  226. X+ private:
  227. X+    FILE * fp;
  228. X+ } ;
  229. X+ 
  230. X+ OutFILE &
  231. X+ OutFILE::operator<<(char ch) {
  232. X+    fputc(ch, fp);
  233. X+    return *this;
  234. X+ }
  235. X+ 
  236. X+ OutFILE &
  237. X+ OutFILE::operator<<(const char * str) {
  238. X+    fputs(str, fp);
  239. X+    return *this;
  240. X+ }
  241. X+ 
  242. X+ 
  243. X+ static  OutFILE  cerr(stderr);
  244. X+ static  OutFILE  cout(stdout);
  245. X+ 
  246. X+ #endif  /* USE_STDIO */
  247. X+ 
  248. X  // ************************************************************** OptIter
  249. X  
  250. X  OptIter::~OptIter(void) {}
  251. X***************
  252. X*** 107,112 ****
  253. X--- 159,170 ----
  254. X  
  255. X  // ************************************************************* OptIstreamIter
  256. X  
  257. X+ #ifdef vms
  258. X+    enum { c_COMMENT = '!' } ;
  259. X+ #else
  260. X+    enum { c_COMMENT = '#' } ;
  261. X+ #endif
  262. X+ 
  263. X  const unsigned  OptIstreamIter::MAX_LINE_LEN = 1024 ;
  264. X  
  265. X     // Constructor
  266. X***************
  267. X*** 115,122 ****
  268. X  }
  269. X  
  270. X     // Destructor
  271. X! OptIstreamIter::~OptIstreamIter(void)
  272. X! {
  273. X     delete  tok_iter;
  274. X  }
  275. X  
  276. X--- 173,179 ----
  277. X  }
  278. X  
  279. X     // Destructor
  280. X! OptIstreamIter::~OptIstreamIter(void) {
  281. X     delete  tok_iter;
  282. X  }
  283. X  
  284. X***************
  285. X*** 139,146 ****
  286. X  }
  287. X  
  288. X  const char *
  289. X! OptIstreamIter::operator()(void)
  290. X! {
  291. X     const char * result = NULL;
  292. X     if (tok_iter)  result = tok_iter->operator()();
  293. X     if (result)  return  result;
  294. X--- 196,202 ----
  295. X  }
  296. X  
  297. X  const char *
  298. X! OptIstreamIter::operator()(void) {
  299. X     const char * result = NULL;
  300. X     if (tok_iter)  result = tok_iter->operator()();
  301. X     if (result)  return  result;
  302. X***************
  303. X*** 162,168 ****
  304. X        is.getline(buf, sizeof(buf));
  305. X        char * ptr = buf;
  306. X        while (isspace(*ptr)) ++ptr;
  307. X!       if (*ptr && (*ptr != OptIstreamIter::c_COMMENT)) {
  308. X           delete  tok_iter;
  309. X           tok_iter = new OptStrTokIter(ptr);
  310. X           return;
  311. X--- 218,224 ----
  312. X        is.getline(buf, sizeof(buf));
  313. X        char * ptr = buf;
  314. X        while (isspace(*ptr)) ++ptr;
  315. X!       if (*ptr && (*ptr != c_COMMENT)) {
  316. X           delete  tok_iter;
  317. X           tok_iter = new OptStrTokIter(ptr);
  318. X           return;
  319. X***************
  320. X*** 170,372 ****
  321. X     } while (is);
  322. X  }
  323. X  
  324. X! // ******************************************************************* Options
  325. X  
  326. X!    // See if an opt-spec is a Hidden option
  327. X  inline static int
  328. X! isHiddenOpt(const char * optspec) { return  (*optspec == '-'); }
  329. X  
  330. X  // ---------------------------------------------------------------------------
  331. X! // ^FUNCTION: verify - verify the syntax of each option-spec
  332. X  //
  333. X  // ^SYNOPSIS:
  334. X! //    static void verify(name, optv[])
  335. X  //
  336. X  // ^PARAMETERS:
  337. X! //    const char * name - name of this command
  338. X! //    const char * const optv[] - the vector of option-specs to inspect.
  339. X  //
  340. X  // ^DESCRIPTION:
  341. X! //    All we have to do is iterate through the option vector and make sure
  342. X! //    That each option-spec is of the proper format.
  343. X  //
  344. X  // ^REQUIREMENTS:
  345. X! //    - optv[] should be non-NULL and terminated by a NULL pointer.
  346. X  //
  347. X  // ^SIDE-EFFECTS:
  348. X! //    If an invalid option-spec is found, prints a message on cerr and
  349. X! //    exits with a status of 127.
  350. X  //
  351. X  // ^RETURN-VALUE:
  352. X! //    None.
  353. X  //
  354. X  // ^ALGORITHM:
  355. X! //    For each option-spec
  356. X! //       - ensure (length > 0)
  357. X! //       - verify the the second character is one of "|?:*+"
  358. X! //    end-for
  359. X  // ^^-------------------------------------------------------------------------
  360. X! static void
  361. X! verify(const char * name, const char * const optv[])
  362. X! {
  363. X!    int errors = 0;
  364. X!    if ((optv == NULL) || (! *optv))  return;
  365. X  
  366. X!    const char * cp = *optv;
  367. X!    while (cp = *(optv++)) {
  368. X!       if (isHiddenOpt(cp))  ++cp;
  369. X!       if (! *cp) {
  370. X!          cerr << name << ": invalid option spec \"" << cp << "\"." << endl ;
  371. X!          cerr << "\tmust be at least 1 character long." << endl ;
  372. X!          ++errors;
  373. X!       } else if (cp[1] && (strchr("|?:*+", cp[1]) == NULL)) {
  374. X!          cerr << name << ": invalid option spec \"" << cp << "\"." << endl ;
  375. X!          cerr << "\t2nd character must be in the set \"|?:*+\"." << endl ;
  376. X!          ++errors;
  377. X!       }
  378. X!    }/*while*/
  379. X  
  380. X!    if (errors)  exit(127);
  381. X! }
  382. X  
  383. X! Options::Options(const char * name, const char * const optv[])
  384. X!    : cmdname(name), optvec(optv), explicit_end(0), optctrls(DEFAULT),
  385. X!      nextchar(NULL), listopt(NULL)
  386. X! {
  387. X!    const char * basename = ::strrchr(cmdname, '/');
  388. X!    if (basename)  cmdname = basename + 1;
  389. X!    verify(name, optv);
  390. X  }
  391. X  
  392. X! Options::~Options(void) {}
  393. X  
  394. X!    // return values for a keyword matching function
  395. X! enum kwdmatch_t { NO_MATCH, PARTIAL_MATCH, EXACT_MATCH } ;
  396. X  
  397. X!    // Get the option-char of an option-spec.
  398. X! inline static char
  399. X! OptChar(const char * optspec) { return  *optspec; }
  400. X  
  401. X!    // Get the long-option of an option-spec.
  402. X! inline static const char *
  403. X! LongOpt(const char * optspec) {
  404. X!     return  ((optspec)[1] && (optspec)[2] &&
  405. X!              (! isspace((optspec)[2]))) ? ((optspec) + 2) : NULL ;
  406. X! }
  407. X  
  408. X!    // Is the option-char null?
  409. X! inline static int
  410. X! isNullOpt(char optchar) {
  411. X!    return  ((! optchar) || isspace(optchar) || (! isprint(optchar))) ;
  412. X! }
  413. X  
  414. X!    // Does this option require an argument?
  415. X! inline static int
  416. X! isRequired(const char * optspec) {
  417. X!    return  (((optspec)[1] == ':') || ((optspec)[1] == '+')) ;
  418. X! }
  419. X  
  420. X!    // Does this option take an optional argument?
  421. X! inline static int
  422. X! isOptional(const char * optspec) {
  423. X!    return  (((optspec)[1] == '?') || ((optspec)[1] == '*')) ;
  424. X! }
  425. X  
  426. X!    // Does this option take no arguments?
  427. X! inline static int
  428. X! isNoArg(const char * optspec) {
  429. X!    return  (((optspec)[1] == '|') || (! (optspec)[1])) ;
  430. X! }
  431. X  
  432. X!    // Can this option take more than one argument?
  433. X! inline static int
  434. X! isList(const char * optspec) {
  435. X!    return  (((optspec)[1] == '+') || ((optspec)[1] == '*')) ;
  436. X! }
  437. X  
  438. X!    // Does this option take any arguments?
  439. X! inline static int
  440. X! isValTaken(const char * optspec) {
  441. X!    return  (isRequired(optspec) || isOptional(optspec)) ;
  442. X! }
  443. X  
  444. X!    // Check for explicit "end-of-options"
  445. X! inline static int
  446. X! isEndOpts(const char * token)
  447. X! {
  448. X!    return ((token == NULL) || (! strcmp(token, "--"))) ;
  449. X! }
  450. X  
  451. X!    // See if an argument is an option
  452. X! inline static int
  453. X! isOption(unsigned  flags, const char * arg)
  454. X! {
  455. X!    return  (((*arg != '\0') || (arg[1] != '\0')) &&
  456. X!             ((*arg == '-')  || ((flags & Options::PLUS) && (*arg == '+')))) ;
  457. X  }
  458. X  
  459. X  // ---------------------------------------------------------------------------
  460. X! // ^FUNCTION: kwdmatch - match a keyword
  461. X  //
  462. X  // ^SYNOPSIS:
  463. X! //    static kwdmatch_t kwdmatch(src, attempt, len)
  464. X  //
  465. X  // ^PARAMETERS:
  466. X! //    char * src -- the actual keyword to match
  467. X! //    char * attempt -- the possible keyword to compare against "src"
  468. X! //    int len -- number of character of "attempt" to consider
  469. X! //               (if 0 then we should use all of "attempt")
  470. X  //
  471. X  // ^DESCRIPTION:
  472. X! //    See if "attempt" matches some prefix of "src" (case insensitive).
  473. X  //
  474. X  // ^REQUIREMENTS:
  475. X! //    - attempt should be non-NULL and non-empty
  476. X  //
  477. X  // ^SIDE-EFFECTS:
  478. X! //    None.
  479. X  //
  480. X  // ^RETURN-VALUE:
  481. X! //    An enumeration value of type kwdmatch_t corresponding to whether
  482. X! //    We had an exact match, a partial match, or no match.
  483. X  //
  484. X  // ^ALGORITHM:
  485. X! //    Trivial
  486. X  // ^^-------------------------------------------------------------------------
  487. X! static kwdmatch_t
  488. X! kwdmatch(const char * src, const char * attempt, int len =0)
  489. X! {
  490. X!    int  i;
  491. X  
  492. X!    if (src == attempt)  return  EXACT_MATCH ;
  493. X!    if ((src == NULL) || (attempt == NULL))  return  NO_MATCH ;
  494. X!    if ((! *src) && (! *attempt))  return  EXACT_MATCH ;
  495. X!    if ((! *src) || (! *attempt))  return  NO_MATCH ;
  496. X  
  497. X!    for (i = 0 ; ((i < len) || (len == 0)) &&
  498. X!                 (attempt[i]) && (attempt[i] != ' ') ; i++) {
  499. X!       if (TOLOWER(src[i]) != TOLOWER(attempt[i]))  return  NO_MATCH ;
  500. X     }
  501. X  
  502. X!    return  (src[i]) ? PARTIAL_MATCH : EXACT_MATCH ;
  503. X  }
  504. X  
  505. X  // ---------------------------------------------------------------------------
  506. X! // ^FUNCTION: match_opt - match an option
  507. X  //
  508. X  // ^SYNOPSIS:
  509. X! //    static const char * match_opt(optv, opt)
  510. X  //
  511. X  // ^PARAMETERS:
  512. X- //    char * optv[] -- vector of option-specifications
  513. X  //    char opt -- the option-character to match
  514. X  //    int  ignore_case -- should we ignore character-case?
  515. X  //
  516. X  // ^DESCRIPTION:
  517. X! //    See if "opt" is found in "optv"
  518. X  //
  519. X  // ^REQUIREMENTS:
  520. X! //    - optv should be non-NULL and terminated by a NULL pointer.
  521. X  //
  522. X  // ^SIDE-EFFECTS:
  523. X  //    None.
  524. X--- 226,571 ----
  525. X     } while (is);
  526. X  }
  527. X  
  528. X! // **************************************************** Options class utilities
  529. X  
  530. X!    // Is this option-char null?
  531. X  inline static int
  532. X! isNullOpt(char optchar) {
  533. X!    return  ((! optchar) || isspace(optchar) || (! isprint(optchar)));
  534. X! }
  535. X!    
  536. X!    // Check for explicit "end-of-options"
  537. X! inline static int
  538. X! isEndOpts(const char * token) {
  539. X!    return ((token == NULL) || (! ::strcmp(token, "--"))) ;
  540. X! }
  541. X  
  542. X+    // See if an argument is an option
  543. X+ inline static int
  544. X+ isOption(unsigned  flags, const char * arg) {
  545. X+    return  (((*arg != '\0') || (arg[1] != '\0')) &&
  546. X+             ((*arg == '-')  || ((flags & Options::PLUS) && (*arg == '+')))) ;
  547. X+ }
  548. X+ 
  549. X+    // return values for a keyword matching function
  550. X+ enum kwdmatch_t { NO_MATCH, PARTIAL_MATCH, EXACT_MATCH } ;
  551. X+ 
  552. X  // ---------------------------------------------------------------------------
  553. X! // ^FUNCTION: kwdmatch - match a keyword
  554. X  //
  555. X  // ^SYNOPSIS:
  556. X! //    static kwdmatch_t kwdmatch(src, attempt, len)
  557. X  //
  558. X  // ^PARAMETERS:
  559. X! //    char * src -- the actual keyword to match
  560. X! //    char * attempt -- the possible keyword to compare against "src"
  561. X! //    int len -- number of character of "attempt" to consider
  562. X! //               (if 0 then we should use all of "attempt")
  563. X  //
  564. X  // ^DESCRIPTION:
  565. X! //    See if "attempt" matches some prefix of "src" (case insensitive).
  566. X  //
  567. X  // ^REQUIREMENTS:
  568. X! //    - attempt should be non-NULL and non-empty
  569. X  //
  570. X  // ^SIDE-EFFECTS:
  571. X! //    None.
  572. X  //
  573. X  // ^RETURN-VALUE:
  574. X! //    An enumeration value of type kwdmatch_t corresponding to whether
  575. X! //    We had an exact match, a partial match, or no match.
  576. X  //
  577. X  // ^ALGORITHM:
  578. X! //    Trivial
  579. X  // ^^-------------------------------------------------------------------------
  580. X! static kwdmatch_t
  581. X! kwdmatch(const char * src, const char * attempt, int len =0) {
  582. X!    int  i;
  583. X  
  584. X!    if (src == attempt)  return  EXACT_MATCH ;
  585. X!    if ((src == NULL) || (attempt == NULL))  return  NO_MATCH ;
  586. X!    if ((! *src) && (! *attempt))  return  EXACT_MATCH ;
  587. X!    if ((! *src) || (! *attempt))  return  NO_MATCH ;
  588. X  
  589. X!    for (i = 0 ; ((i < len) || (len == 0)) &&
  590. X!                 (attempt[i]) && (attempt[i] != ' ') ; i++) {
  591. X!       if (TOLOWER(src[i]) != TOLOWER(attempt[i]))  return  NO_MATCH ;
  592. X!    }
  593. X  
  594. X!    return  (src[i]) ? PARTIAL_MATCH : EXACT_MATCH ;
  595. X  }
  596. X  
  597. X! // **************************************************************** OptionSpec
  598. X  
  599. X!    // Class that represents an option-specification
  600. X!    //    *NOTE*:: Assumes that the char-ptr given to the constructor points
  601. X!    //             to storage that will NOT be modified and whose lifetime will
  602. X!    //             be as least as long as the OptionSpec object we construct.
  603. X!    //
  604. X! class OptionSpec {
  605. X! public:
  606. X!    OptionSpec(const char * decl =NULL)
  607. X!       : hidden(0), spec(decl) { CheckHidden(); }
  608. X  
  609. X!    OptionSpec(const OptionSpec & cp) : hidden(cp.hidden), spec(cp.spec) {}
  610. X  
  611. X!    // NOTE: use default destructor!
  612. X  
  613. X!       // Assign to another OptionSpec
  614. X!    OptionSpec &
  615. X!    operator=(const OptionSpec & cp) {
  616. X!       if (this != &cp) {
  617. X!          spec = cp.spec;
  618. X!          hidden = cp.hidden;
  619. X!       }
  620. X!       return *this;
  621. X!    }
  622. X  
  623. X!       // Assign to a string
  624. X!    OptionSpec &
  625. X!    operator=(const char * decl) {
  626. X!       if (spec != decl) {
  627. X!          spec = decl;
  628. X!          hidden = 0;
  629. X!          CheckHidden();
  630. X!       }
  631. X!       return *this;
  632. X!    }
  633. X  
  634. X!       // Convert to char-ptr by returning the original declaration-string
  635. X!    operator const char*() { return  isHiddenOpt() ? (spec - 1) : spec; }
  636. X  
  637. X!       // Is this option NULL?
  638. X!    int
  639. X!    isNULL(void) const { return (spec == NULL); }
  640. X  
  641. X!       // Is this options incorrectly specified?
  642. X!    int
  643. X!    isSyntaxError(const char * name) const;
  644. X  
  645. X!       // See if this is a Hidden option
  646. X!    int
  647. X!    isHiddenOpt(void) const { return  hidden; }
  648. X  
  649. X!       // Get the corresponding option-character
  650. X!    char
  651. X!    OptChar(void) const { return  *spec; }
  652. X  
  653. X!       // Get the corresponding long-option string
  654. X!    const char *
  655. X!    LongOpt(void) const {
  656. X!        return  (spec[1] && spec[2] && (! isspace(spec[2]))) ? (spec + 2) : NULL;
  657. X!    }
  658. X! 
  659. X!       // Does this option require an argument?
  660. X!    int
  661. X!    isValRequired(void) const {
  662. X!       return  ((spec[1] == ':') || (spec[1] == '+'));
  663. X!    }
  664. X! 
  665. X!       // Does this option take an optional argument?
  666. X!    int
  667. X!    isValOptional(void) const {
  668. X!       return  ((spec[1] == '?') || (spec[1] == '*'));
  669. X!    }
  670. X! 
  671. X!       // Does this option take no arguments?
  672. X!    int
  673. X!    isNoArg(void) const {
  674. X!       return  ((spec[1] == '|') || (! spec[1]));
  675. X!    }
  676. X! 
  677. X!       // Can this option take more than one argument?
  678. X!    int
  679. X!    isList(void) const {
  680. X!       return  ((spec[1] == '+') || (spec[1] == '*'));
  681. X!    }
  682. X! 
  683. X!       // Does this option take any arguments?
  684. X!    int
  685. X!    isValTaken(void) const {
  686. X!       return  (isValRequired() || isValOptional()) ;
  687. X!    }
  688. X! 
  689. X!       // Format this option in the given buffer
  690. X!    unsigned
  691. X!    Format(char * buf, unsigned optctrls) const;
  692. X! 
  693. X! private:
  694. X!    void
  695. X!    CheckHidden(void) {
  696. X!       if ((! hidden) && (*spec == '-')) {
  697. X!          ++hidden;
  698. X!          ++spec;
  699. X!       }
  700. X!    }
  701. X! 
  702. X!    unsigned     hidden : 1;  // hidden-flag
  703. X!    const char * spec;        // string specification
  704. X! } ;
  705. X! 
  706. X! int
  707. X! OptionSpec::isSyntaxError(const char * name) const {
  708. X!    int  error = 0;
  709. X!    if ((! spec) || (! *spec)) {
  710. X!       cerr << name << ": empty option specifier." << endl;
  711. X!       cerr << "\tmust be at least 1 character long." << endl;
  712. X!       ++error;
  713. X!    } else if (spec[1] && (strchr("|?:*+", spec[1]) == NULL)) {
  714. X!       cerr << name << ": bad option specifier \"" << spec << "\"." << endl;
  715. X!       cerr << "\t2nd character must be in the set \"|?:*+\"." << endl;
  716. X!       ++error;
  717. X!    }
  718. X!    return  error;
  719. X  }
  720. X  
  721. X  // ---------------------------------------------------------------------------
  722. X! // ^FUNCTION: OptionSpec::Format - format an option-spec for a usage message
  723. X  //
  724. X  // ^SYNOPSIS:
  725. X! //    unsigned OptionSpec::Format(buf, optctrls) const
  726. X  //
  727. X  // ^PARAMETERS:
  728. X! //    char * buf -- where to print the formatted option
  729. X! //    unsigned  optctrls -- option-parsing configuration flags
  730. X  //
  731. X  // ^DESCRIPTION:
  732. X! //    Self-explanatory.
  733. X  //
  734. X  // ^REQUIREMENTS:
  735. X! //    - buf must be large enough to hold the result
  736. X  //
  737. X  // ^SIDE-EFFECTS:
  738. X! //    - writes to buf.
  739. X  //
  740. X  // ^RETURN-VALUE:
  741. X! //    Number of characters written to buf.
  742. X  //
  743. X  // ^ALGORITHM:
  744. X! //    Follow along in the source - it's not hard but it is tedious!
  745. X  // ^^-------------------------------------------------------------------------
  746. X! unsigned
  747. X! OptionSpec::Format(char * buf, unsigned optctrls) const {
  748. X!    static  char default_value[] = "<value>";
  749. X!    if (isHiddenOpt())  return (unsigned)(*buf = '\0');
  750. X!    char optchar = OptChar();
  751. X!    const char * longopt = LongOpt();
  752. X!    char * p = buf ;
  753. X  
  754. X!    const char * value = NULL;
  755. X!    int    longopt_len = 0;
  756. X!    int    value_len = 0;
  757. X  
  758. X!    if (longopt) {
  759. X!       value = ::strchr(longopt, ' ');
  760. X!       longopt_len = (value) ? (value - longopt) : ::strlen(longopt);
  761. X!    } else {
  762. X!       value = ::strchr(spec + 1, ' ');
  763. X     }
  764. X+    while (value && (*value == ' '))  ++value;
  765. X+    if (value && *value) {
  766. X+       value_len = ::strlen(value);
  767. X+    } else {
  768. X+       value = default_value;
  769. X+       value_len = sizeof(default_value) - 1;
  770. X+    }
  771. X  
  772. X!    if ((optctrls & Options::SHORT_ONLY) &&
  773. X!        ((! isNullOpt(optchar)) || (optctrls & Options::NOGUESSING))) {
  774. X!       longopt = NULL;
  775. X!    }
  776. X!    if ((optctrls & Options::LONG_ONLY) &&
  777. X!        (longopt || (optctrls & Options::NOGUESSING))) {
  778. X!       optchar = '\0';
  779. X!    }
  780. X!    if (isNullOpt(optchar) && (longopt == NULL)) {
  781. X!       *buf = '\0';
  782. X!       return  0;
  783. X!    }
  784. X! 
  785. X!    *(p++) = '[';
  786. X! 
  787. X!    // print the single character option
  788. X!    if (! isNullOpt(optchar)) {
  789. X!       *(p++) = '-';
  790. X!       *(p++) = optchar;
  791. X!    }
  792. X! 
  793. X!    if ((! isNullOpt(optchar)) && (longopt))  *(p++) = '|';
  794. X! 
  795. X!    // print the long option
  796. X!    if (longopt) {
  797. X!       *(p++) = '-';
  798. X!       if (! (optctrls & (Options::LONG_ONLY | Options::SHORT_ONLY))) {
  799. X!          *(p++) = '-';
  800. X!       }
  801. X!       strncpy(p, longopt, longopt_len);
  802. X!       p += longopt_len;
  803. X!    }
  804. X! 
  805. X!    // print any argument the option takes
  806. X!    if (isValTaken()) {
  807. X!       *(p++) = ' ' ;
  808. X!       if (isValOptional())  *(p++) = '[' ;
  809. X!       strcpy(p, value);
  810. X!       p += value_len;
  811. X!       if (isList()) {
  812. X!          strcpy(p, " ...");
  813. X!          p += 4;
  814. X!       }
  815. X!       if (isValOptional())  *(p++) = ']' ;
  816. X!    }
  817. X! 
  818. X!    *(p++) = ']';
  819. X!    *p = '\0';
  820. X! 
  821. X!    return  (unsigned) strlen(buf);
  822. X  }
  823. X  
  824. X+ // ******************************************************************* Options
  825. X+ 
  826. X+ Options::Options(const char * name, const char * const optv[])
  827. X+    : cmdname(name), optvec(optv), explicit_end(0), optctrls(DEFAULT),
  828. X+      nextchar(NULL), listopt(NULL)
  829. X+ {
  830. X+    const char * basename = ::strrchr(cmdname, '/');
  831. X+    if (basename)  cmdname = basename + 1;
  832. X+    check_syntax();
  833. X+ }
  834. X+ 
  835. X+ Options::~Options(void) {}
  836. X+ 
  837. X+    // Make sure each option-specifier has correct syntax.
  838. X+    //
  839. X+    // If there is even one invalid specifier, then exit ungracefully!
  840. X+    //
  841. X+ void
  842. X+ Options::check_syntax(void) const {
  843. X+    int  errors = 0;
  844. X+    if ((optvec == NULL) || (! *optvec))  return;
  845. X+ 
  846. X+    for (const char * const * optv = optvec ; *optv ; optv++) {
  847. X+       OptionSpec  optspec = *optv;
  848. X+       errors += optspec.isSyntaxError(cmdname);
  849. X+    }
  850. X+    if (errors)  exit(127);
  851. X+ }
  852. X+ 
  853. X  // ---------------------------------------------------------------------------
  854. X! // ^FUNCTION: Options::match_opt - match an option
  855. X  //
  856. X  // ^SYNOPSIS:
  857. X! //    const char * match_opt(opt, int  ignore_case) const
  858. X  //
  859. X  // ^PARAMETERS:
  860. X  //    char opt -- the option-character to match
  861. X  //    int  ignore_case -- should we ignore character-case?
  862. X  //
  863. X  // ^DESCRIPTION:
  864. X! //    See if "opt" is found in "optvec"
  865. X  //
  866. X  // ^REQUIREMENTS:
  867. X! //    - optvec should be non-NULL and terminated by a NULL pointer.
  868. X  //
  869. X  // ^SIDE-EFFECTS:
  870. X  //    None.
  871. X***************
  872. X*** 380,398 ****
  873. X  //       - see if "opt" is a match, if so return option-spec
  874. X  //    end-for
  875. X  // ^^-------------------------------------------------------------------------
  876. X! static const char *
  877. X! match_opt(const char * const optv[], char opt, int ignore_case =0)
  878. X! {
  879. X!    if ((optv == NULL) || (! *optv))  return  NULL;
  880. X  
  881. X!    for (const char * optspec = *optv; optspec ; optspec =  *(++optv)) {
  882. X!       if (isHiddenOpt(optspec))  ++optspec;
  883. X!       char optchar = OptChar(optspec);
  884. X        if (isNullOpt(optchar))  continue;
  885. X        if (opt == optchar) {
  886. X!          return optspec;
  887. X        } else if (ignore_case && (TOLOWER(opt) == TOLOWER(optchar))) {
  888. X!          return optspec;
  889. X        }
  890. X     }
  891. X  
  892. X--- 579,596 ----
  893. X  //       - see if "opt" is a match, if so return option-spec
  894. X  //    end-for
  895. X  // ^^-------------------------------------------------------------------------
  896. X! const char *
  897. X! Options::match_opt(char opt, int ignore_case) const {
  898. X!    if ((optvec == NULL) || (! *optvec))  return  NULL;
  899. X  
  900. X!    for (const char * const * optv = optvec ; *optv ; optv++) {
  901. X!       OptionSpec  optspec = *optv;
  902. X!       char optchar = optspec.OptChar();
  903. X        if (isNullOpt(optchar))  continue;
  904. X        if (opt == optchar) {
  905. X!          return  optspec;
  906. X        } else if (ignore_case && (TOLOWER(opt) == TOLOWER(optchar))) {
  907. X!          return  optspec;
  908. X        }
  909. X     }
  910. X  
  911. X***************
  912. X*** 400,412 ****
  913. X  }
  914. X  
  915. X  // ---------------------------------------------------------------------------
  916. X! // ^FUNCTION: match_longopt - match a long-option
  917. X  //
  918. X  // ^SYNOPSIS:
  919. X! //   static const char * match_longopt(optv, opt, len, ambiguous)
  920. X  //
  921. X  // ^PARAMETERS:
  922. X- //    char * optv[] -- the vector of option-specs
  923. X  //    char * opt -- the long-option to match
  924. X  //    int len -- the number of character of "opt" to match
  925. X  //    int & ambiguous -- set by this routine before returning.
  926. X--- 598,609 ----
  927. X  }
  928. X  
  929. X  // ---------------------------------------------------------------------------
  930. X! // ^FUNCTION: Options::match_longopt - match a long-option
  931. X  //
  932. X  // ^SYNOPSIS:
  933. X! //   const char * Options::match_longopt(opt, len, ambiguous)
  934. X  //
  935. X  // ^PARAMETERS:
  936. X  //    char * opt -- the long-option to match
  937. X  //    int len -- the number of character of "opt" to match
  938. X  //    int & ambiguous -- set by this routine before returning.
  939. X***************
  940. X*** 431,438 ****
  941. X  //    foreach option-spec
  942. X  //       if we have an EXACT-MATCH, return the option-spec
  943. X  //       if we have a partial-match then
  944. X! //          if we already had a previous partial match then 
  945. X! //             set ambiguous = TRUE and retrun NULL
  946. X  //          else
  947. X  //             remember this options spec and continue matching
  948. X  //          end-if
  949. X--- 628,635 ----
  950. X  //    foreach option-spec
  951. X  //       if we have an EXACT-MATCH, return the option-spec
  952. X  //       if we have a partial-match then
  953. X! //          if we already had a previous partial match then
  954. X! //             set ambiguous = TRUE and return NULL
  955. X  //          else
  956. X  //             remember this options spec and continue matching
  957. X  //          end-if
  958. X***************
  959. X*** 440,460 ****
  960. X  //    end-for
  961. X  //    if we had exactly 1 partial match return it, else return NULL
  962. X  // ^^-------------------------------------------------------------------------
  963. X! static const char *
  964. X! match_longopt(const char * const optv[],
  965. X!               const char       * opt,
  966. X!               int                len,
  967. X!               int              & ambiguous)
  968. X! {
  969. X     kwdmatch_t  result;
  970. X     const char * matched = NULL ;
  971. X  
  972. X     ambiguous = 0;
  973. X!    if ((optv == NULL) || (! *optv))  return  NULL;
  974. X  
  975. X!    for (const char * optspec = *optv; optspec ; optspec =  *(++optv)) {
  976. X!       if (isHiddenOpt(optspec))  ++optspec;
  977. X!       const char * longopt = LongOpt(optspec);
  978. X        if (longopt == NULL)  continue;
  979. X        result = kwdmatch(longopt, opt, len);
  980. X        if (result == EXACT_MATCH) {
  981. X--- 637,653 ----
  982. X  //    end-for
  983. X  //    if we had exactly 1 partial match return it, else return NULL
  984. X  // ^^-------------------------------------------------------------------------
  985. X! const char *
  986. X! Options::match_longopt(const char * opt, int  len, int & ambiguous) const {
  987. X     kwdmatch_t  result;
  988. X     const char * matched = NULL ;
  989. X  
  990. X     ambiguous = 0;
  991. X!    if ((optvec == NULL) || (! *optvec))  return  NULL;
  992. X  
  993. X!    for (const char * const * optv = optvec ; *optv ; optv++) {
  994. X!       OptionSpec  optspec = *optv;
  995. X!       const char * longopt = optspec.LongOpt();
  996. X        if (longopt == NULL)  continue;
  997. X        result = kwdmatch(longopt, opt, len);
  998. X        if (result == EXACT_MATCH) {
  999. X***************
  1000. X*** 467,473 ****
  1001. X              matched = optspec;
  1002. X           }
  1003. X        }
  1004. X!    }/*for*/
  1005. X  
  1006. X     return  matched;
  1007. X  }
  1008. X--- 660,666 ----
  1009. X              matched = optspec;
  1010. X           }
  1011. X        }
  1012. X!    }//for
  1013. X  
  1014. X     return  matched;
  1015. X  }
  1016. X***************
  1017. X*** 503,525 ****
  1018. X  //    It gets complicated -- follow the comments in the source.
  1019. X  // ^^-------------------------------------------------------------------------
  1020. X  int
  1021. X! Options::parse_opt(OptIter & iter, const char * & optarg)
  1022. X! {
  1023. X     listopt = NULL;  // reset the list pointer
  1024. X  
  1025. X     if ((optvec == NULL) || (! *optvec))  return  Options::ENDOPTS;
  1026. X  
  1027. X        // Try to match a known option
  1028. X!    const char * optspec = match_opt(optvec, *(nextchar++));
  1029. X  
  1030. X        // Check for an unknown option
  1031. X!    if (optspec == NULL) {
  1032. X        // See if this was a long-option in disguise
  1033. X!       if (! (optctrls & NOGUESSING)) {
  1034. X           unsigned  save_ctrls = optctrls;
  1035. X           const char * save_nextchar = nextchar;
  1036. X           nextchar -= 1;
  1037. X!          optctrls |= (QUIET | NOGUESSING);
  1038. X           int  optchar = parse_longopt(iter, optarg);
  1039. X           optctrls = save_ctrls;
  1040. X           if (optchar > 0) {
  1041. X--- 696,717 ----
  1042. X  //    It gets complicated -- follow the comments in the source.
  1043. X  // ^^-------------------------------------------------------------------------
  1044. X  int
  1045. X! Options::parse_opt(OptIter & iter, const char * & optarg) {
  1046. X     listopt = NULL;  // reset the list pointer
  1047. X  
  1048. X     if ((optvec == NULL) || (! *optvec))  return  Options::ENDOPTS;
  1049. X  
  1050. X        // Try to match a known option
  1051. X!    OptionSpec optspec = match_opt(*(nextchar++), (optctrls & Options::ANYCASE));
  1052. X  
  1053. X        // Check for an unknown option
  1054. X!    if (optspec.isNULL()) {
  1055. X        // See if this was a long-option in disguise
  1056. X!       if (! (optctrls & Options::NOGUESSING)) {
  1057. X           unsigned  save_ctrls = optctrls;
  1058. X           const char * save_nextchar = nextchar;
  1059. X           nextchar -= 1;
  1060. X!          optctrls |= (Options::QUIET | Options::NOGUESSING);
  1061. X           int  optchar = parse_longopt(iter, optarg);
  1062. X           optctrls = save_ctrls;
  1063. X           if (optchar > 0) {
  1064. X***************
  1065. X*** 528,545 ****
  1066. X              nextchar = save_nextchar;
  1067. X           }
  1068. X        }
  1069. X!       if (! (optctrls & QUIET)) {
  1070. X           cerr << cmdname << ": unknown option -"
  1071. X                << *(nextchar - 1) << "." << endl ;
  1072. X        }
  1073. X        optarg = (nextchar - 1);  // record the bad option in optarg
  1074. X!       return  BADCHAR;
  1075. X     }
  1076. X  
  1077. X        // If no argument is taken, then leave now
  1078. X!    if (isNoArg(optspec)) {
  1079. X        optarg = NULL;
  1080. X!       return  OptChar(optspec);
  1081. X     }
  1082. X  
  1083. X        // Check for argument in this arg
  1084. X--- 720,737 ----
  1085. X              nextchar = save_nextchar;
  1086. X           }
  1087. X        }
  1088. X!       if (! (optctrls & Options::QUIET)) {
  1089. X           cerr << cmdname << ": unknown option -"
  1090. X                << *(nextchar - 1) << "." << endl ;
  1091. X        }
  1092. X        optarg = (nextchar - 1);  // record the bad option in optarg
  1093. X!       return  Options::BADCHAR;
  1094. X     }
  1095. X  
  1096. X        // If no argument is taken, then leave now
  1097. X!    if (optspec.isNoArg()) {
  1098. X        optarg = NULL;
  1099. X!       return  optspec.OptChar();
  1100. X     }
  1101. X  
  1102. X        // Check for argument in this arg
  1103. X***************
  1104. X*** 546,572 ****
  1105. X     if (*nextchar) {
  1106. X        optarg = nextchar; // the argument is right here
  1107. X        nextchar = NULL;   // we've exhausted this arg
  1108. X!       if (isList(optspec))  listopt = optspec ;  // save the list-spec
  1109. X!       return  OptChar(optspec);
  1110. X     }
  1111. X  
  1112. X        // Check for argument in next arg
  1113. X     const char * nextarg = iter.curr();
  1114. X     if ((nextarg != NULL)  &&
  1115. X!        (isRequired(optspec) || (! isOption(optctrls, nextarg)))) {
  1116. X        optarg = nextarg;    // the argument is here
  1117. X        iter.next();         // end of arg - advance
  1118. X!       if (isList(optspec))  listopt = optspec ;  // save the list-spec
  1119. X!       return  OptChar(optspec);
  1120. X     }
  1121. X  
  1122. X       // No argument given - if its required, thats an error
  1123. X     optarg = NULL;
  1124. X!    if (isRequired(optspec) &&  !(optctrls & QUIET)) {
  1125. X!       cerr << cmdname << ": argument required for -" << OptChar(optspec)
  1126. X             << " option." << endl ;
  1127. X     }
  1128. X!    return  OptChar(optspec);
  1129. X  }
  1130. X  
  1131. X  // ---------------------------------------------------------------------------
  1132. X--- 738,764 ----
  1133. X     if (*nextchar) {
  1134. X        optarg = nextchar; // the argument is right here
  1135. X        nextchar = NULL;   // we've exhausted this arg
  1136. X!       if (optspec.isList())  listopt = optspec ;  // save the list-spec
  1137. X!       return  optspec.OptChar();
  1138. X     }
  1139. X  
  1140. X        // Check for argument in next arg
  1141. X     const char * nextarg = iter.curr();
  1142. X     if ((nextarg != NULL)  &&
  1143. X!        (optspec.isValRequired() || (! isOption(optctrls, nextarg)))) {
  1144. X        optarg = nextarg;    // the argument is here
  1145. X        iter.next();         // end of arg - advance
  1146. X!       if (optspec.isList())  listopt = optspec ;  // save the list-spec
  1147. X!       return  optspec.OptChar();
  1148. X     }
  1149. X  
  1150. X       // No argument given - if its required, thats an error
  1151. X     optarg = NULL;
  1152. X!    if (optspec.isValRequired() &&  !(optctrls & Options::QUIET)) {
  1153. X!       cerr << cmdname << ": argument required for -" << optspec.OptChar()
  1154. X             << " option." << endl ;
  1155. X     }
  1156. X!    return  optspec.OptChar();
  1157. X  }
  1158. X  
  1159. X  // ---------------------------------------------------------------------------
  1160. X***************
  1161. X*** 601,608 ****
  1162. X  //    It gets complicated -- follow the comments in the source.
  1163. X  // ^^-------------------------------------------------------------------------
  1164. X  int
  1165. X! Options::parse_longopt(OptIter & iter, const char * & optarg)
  1166. X! {
  1167. X     int  len = 0, ambiguous = 0;
  1168. X  
  1169. X     listopt = NULL ;  // reset the list-spec
  1170. X--- 793,799 ----
  1171. X  //    It gets complicated -- follow the comments in the source.
  1172. X  // ^^-------------------------------------------------------------------------
  1173. X  int
  1174. X! Options::parse_longopt(OptIter & iter, const char * & optarg) {
  1175. X     int  len = 0, ambiguous = 0;
  1176. X  
  1177. X     listopt = NULL ;  // reset the list-spec
  1178. X***************
  1179. X*** 617,631 ****
  1180. X     }
  1181. X  
  1182. X        // Try to match a known long-option
  1183. X!    const char * optspec = match_longopt(optvec, nextchar, len, ambiguous);
  1184. X  
  1185. X        // Check for an unknown long-option
  1186. X!    if (optspec == NULL) {
  1187. X        // See if this was a short-option in disguise
  1188. X!       if ((! ambiguous) && (! (optctrls & NOGUESSING))) {
  1189. X           unsigned  save_ctrls = optctrls;
  1190. X           const char * save_nextchar = nextchar;
  1191. X!          optctrls |= (QUIET | NOGUESSING);
  1192. X           int  optchar = parse_opt(iter, optarg);
  1193. X           optctrls = save_ctrls;
  1194. X           if (optchar > 0) {
  1195. X--- 808,822 ----
  1196. X     }
  1197. X  
  1198. X        // Try to match a known long-option
  1199. X!    OptionSpec  optspec = match_longopt(nextchar, len, ambiguous);
  1200. X  
  1201. X        // Check for an unknown long-option
  1202. X!    if (optspec.isNULL()) {
  1203. X        // See if this was a short-option in disguise
  1204. X!       if ((! ambiguous) && (! (optctrls & Options::NOGUESSING))) {
  1205. X           unsigned  save_ctrls = optctrls;
  1206. X           const char * save_nextchar = nextchar;
  1207. X!          optctrls |= (Options::QUIET | Options::NOGUESSING);
  1208. X           int  optchar = parse_opt(iter, optarg);
  1209. X           optctrls = save_ctrls;
  1210. X           if (optchar > 0) {
  1211. X***************
  1212. X*** 634,660 ****
  1213. X              nextchar = save_nextchar;
  1214. X           }
  1215. X        }
  1216. X!       if (! (optctrls & QUIET)) {
  1217. X           cerr << cmdname << ": " << ((ambiguous) ? "ambiguous" : "unknown")
  1218. X                << " option "
  1219. X!               << ((optctrls & LONG_ONLY) ? "-" : "--")
  1220. X                << nextchar << "." << endl ;
  1221. X        }
  1222. X        optarg = nextchar;  // record the bad option in optarg
  1223. X        nextchar = NULL;    // we've exhausted this argument
  1224. X!       return  (ambiguous) ? AMBIGUOUS : BADKWD;
  1225. X     }
  1226. X  
  1227. X        // If no argument is taken, then leave now
  1228. X!    if (isNoArg(optspec)) {
  1229. X!       if ((val) && ! (optctrls & QUIET)) {
  1230. X           cerr << cmdname << ": option "
  1231. X!               << ((optctrls & LONG_ONLY) ? "-" : "--")
  1232. X!               << LongOpt(optspec) << " does NOT take an argument." << endl ;
  1233. X        }
  1234. X        optarg = val;     // record the unexpected argument
  1235. X        nextchar = NULL;  // we've exhausted this argument
  1236. X!       return  OptChar(optspec);
  1237. X     }
  1238. X  
  1239. X        // Check for argument in this arg
  1240. X--- 825,851 ----
  1241. X              nextchar = save_nextchar;
  1242. X           }
  1243. X        }
  1244. X!       if (! (optctrls & Options::QUIET)) {
  1245. X           cerr << cmdname << ": " << ((ambiguous) ? "ambiguous" : "unknown")
  1246. X                << " option "
  1247. X!               << ((optctrls & Options::LONG_ONLY) ? "-" : "--")
  1248. X                << nextchar << "." << endl ;
  1249. X        }
  1250. X        optarg = nextchar;  // record the bad option in optarg
  1251. X        nextchar = NULL;    // we've exhausted this argument
  1252. X!       return  (ambiguous) ? Options::AMBIGUOUS : Options::BADKWD;
  1253. X     }
  1254. X  
  1255. X        // If no argument is taken, then leave now
  1256. X!    if (optspec.isNoArg()) {
  1257. X!       if ((val) && ! (optctrls & Options::QUIET)) {
  1258. X           cerr << cmdname << ": option "
  1259. X!               << ((optctrls & Options::LONG_ONLY) ? "-" : "--")
  1260. X!               << optspec.LongOpt() << " does NOT take an argument." << endl ;
  1261. X        }
  1262. X        optarg = val;     // record the unexpected argument
  1263. X        nextchar = NULL;  // we've exhausted this argument
  1264. X!       return  optspec.OptChar();
  1265. X     }
  1266. X  
  1267. X        // Check for argument in this arg
  1268. X***************
  1269. X*** 661,685 ****
  1270. X     if (val) {
  1271. X        optarg = val;      // the argument is right here
  1272. X        nextchar = NULL;   // we exhausted the rest of this arg
  1273. X!       if (isList(optspec))  listopt = optspec ;  // save the list-spec
  1274. X!       return  OptChar(optspec);
  1275. X     }
  1276. X  
  1277. X        // Check for argument in next arg
  1278. X     const char * nextarg = iter.curr();  // find the next argument to parse
  1279. X     if ((nextarg != NULL)  &&
  1280. X!        (isRequired(optspec) || (! isOption(optctrls, nextarg)))) {
  1281. X        optarg = nextarg;        // the argument is right here
  1282. X        iter.next();             // end of arg - advance
  1283. X        nextchar = NULL;         // we exhausted the rest of this arg
  1284. X!       if (isList(optspec))  listopt = optspec ;  // save the list-spec
  1285. X!       return  OptChar(optspec);
  1286. X     }
  1287. X  
  1288. X       // No argument given - if its required, thats an error
  1289. X     optarg = NULL;
  1290. X!    if (isRequired(optspec) &&  !(optctrls & QUIET)) {
  1291. X!       const char * longopt = LongOpt(optspec);
  1292. X        const char * spc = ::strchr(longopt, ' ');
  1293. X        int  longopt_len;
  1294. X        if (spc) {
  1295. X--- 852,876 ----
  1296. X     if (val) {
  1297. X        optarg = val;      // the argument is right here
  1298. X        nextchar = NULL;   // we exhausted the rest of this arg
  1299. X!       if (optspec.isList())  listopt = optspec ;  // save the list-spec
  1300. X!       return  optspec.OptChar();
  1301. X     }
  1302. X  
  1303. X        // Check for argument in next arg
  1304. X     const char * nextarg = iter.curr();  // find the next argument to parse
  1305. X     if ((nextarg != NULL)  &&
  1306. X!        (optspec.isValRequired() || (! isOption(optctrls, nextarg)))) {
  1307. X        optarg = nextarg;        // the argument is right here
  1308. X        iter.next();             // end of arg - advance
  1309. X        nextchar = NULL;         // we exhausted the rest of this arg
  1310. X!       if (optspec.isList())  listopt = optspec ;  // save the list-spec
  1311. X!       return  optspec.OptChar();
  1312. X     }
  1313. X  
  1314. X       // No argument given - if its required, thats an error
  1315. X     optarg = NULL;
  1316. X!    if (optspec.isValRequired() &&  !(optctrls & Options::QUIET)) {
  1317. X!       const char * longopt = optspec.LongOpt();
  1318. X        const char * spc = ::strchr(longopt, ' ');
  1319. X        int  longopt_len;
  1320. X        if (spc) {
  1321. X***************
  1322. X*** 688,805 ****
  1323. X           longopt_len = ::strlen(longopt);
  1324. X        }
  1325. X        cerr << cmdname << ": argument required for "
  1326. X!            << ((optctrls & LONG_ONLY) ? "-" : "--");
  1327. X        cerr.write(longopt, longopt_len) << " option." << endl ;
  1328. X     }
  1329. X     nextchar = NULL;           // we exhausted the rest of this arg
  1330. X!    return  OptChar(optspec);
  1331. X  }
  1332. X  
  1333. X  // ---------------------------------------------------------------------------
  1334. X- // ^FUNCTION: Options::fmt_opt - format an option-spec for a usage message
  1335. X- //
  1336. X- // ^SYNOPSIS:
  1337. X- //    unsigned Options::fmt_opt(optspec, buf)
  1338. X- //
  1339. X- // ^PARAMETERS:
  1340. X- //    char * optspec -- the option-specification
  1341. X- //    char * buf -- where to print the formatted option
  1342. X- //
  1343. X- // ^DESCRIPTION:
  1344. X- //    Self-explanatory.
  1345. X- //
  1346. X- // ^REQUIREMENTS:
  1347. X- //    - optspec must be a valid option-spec.
  1348. X- //    - buf must be large enough to hold the result
  1349. X- //
  1350. X- // ^SIDE-EFFECTS:
  1351. X- //    - writes to buf.
  1352. X- //
  1353. X- // ^RETURN-VALUE:
  1354. X- //    Number of characters written to buf.
  1355. X- //
  1356. X- // ^ALGORITHM:
  1357. X- //    Trivial.
  1358. X- // ^^-------------------------------------------------------------------------
  1359. X- unsigned
  1360. X- Options::fmt_opt(const char * optspec, char * buf) const
  1361. X- {
  1362. X-    static  char default_value[] = "<value>";
  1363. X-    if (isHiddenOpt(optspec))  return (unsigned)(*buf = '\0');
  1364. X-    char optchar = OptChar(optspec);
  1365. X-    const char * longopt = LongOpt(optspec);
  1366. X-    char * p = buf ;
  1367. X- 
  1368. X-    const char * value = NULL;
  1369. X-    int    longopt_len = 0;
  1370. X-    int    value_len = 0;
  1371. X- 
  1372. X-    if (longopt) {
  1373. X-       value = ::strchr(longopt, ' ');
  1374. X-       longopt_len = (value) ? (value - longopt) : ::strlen(longopt);
  1375. X-    } else {
  1376. X-       value = ::strchr(optspec + 1, ' ');
  1377. X-    }
  1378. X-    while (value && (*value == ' '))  ++value;
  1379. X-    if (value && *value) {
  1380. X-       value_len = ::strlen(value);
  1381. X-    } else {
  1382. X-       value = default_value;
  1383. X-       value_len = sizeof(default_value) - 1;
  1384. X-    }
  1385. X-    
  1386. X-    if ((optctrls & SHORT_ONLY) &&
  1387. X-        ((! isNullOpt(optchar)) || (optctrls & NOGUESSING))) {
  1388. X-       longopt = NULL;
  1389. X-    }
  1390. X-    if ((optctrls & LONG_ONLY) && (longopt || (optctrls & NOGUESSING))) {
  1391. X-       optchar = '\0';
  1392. X-    }
  1393. X-    if (isNullOpt(optchar) && (longopt == NULL)) {
  1394. X-       *buf = '\0';
  1395. X-       return  0;
  1396. X-    }
  1397. X- 
  1398. X-    *(p++) = '[';
  1399. X- 
  1400. X-    // print the single character option
  1401. X-    if (! isNullOpt(optchar)) {
  1402. X-       *(p++) = '-';
  1403. X-       *(p++) = optchar;
  1404. X-    }
  1405. X- 
  1406. X-    if ((! isNullOpt(optchar)) && (longopt))  *(p++) = '|';
  1407. X- 
  1408. X-    // print the long option
  1409. X-    if (longopt) {
  1410. X-       *(p++) = '-';
  1411. X-       if (! (optctrls & (LONG_ONLY | SHORT_ONLY))) {
  1412. X-          *(p++) = '-';
  1413. X-       }
  1414. X-       strncpy(p, longopt, longopt_len);
  1415. X-       p += longopt_len;
  1416. X-    }
  1417. X- 
  1418. X-    // print any argument the option takes
  1419. X-    if (isValTaken(optspec)) {
  1420. X-       *(p++) = ' ' ;
  1421. X-       if (isOptional(optspec))  *(p++) = '[' ;
  1422. X-       strcpy(p, value);
  1423. X-       p += value_len;
  1424. X-       if (isList(optspec)) {
  1425. X-          strcpy(p, " ...");
  1426. X-          p += 4;
  1427. X-       }
  1428. X-       if (isOptional(optspec))  *(p++) = ']' ;
  1429. X-    }
  1430. X- 
  1431. X-    *(p++) = ']';
  1432. X-    *p = '\0';
  1433. X- 
  1434. X-    return  (unsigned) strlen(buf);
  1435. X- }
  1436. X- 
  1437. X- // ---------------------------------------------------------------------------
  1438. X  // ^FUNCTION: Options::usage - print usage
  1439. X  //
  1440. X  // ^SYNOPSIS:
  1441. X--- 879,892 ----
  1442. X           longopt_len = ::strlen(longopt);
  1443. X        }
  1444. X        cerr << cmdname << ": argument required for "
  1445. X!            << ((optctrls & Options::LONG_ONLY) ? "-" : "--");
  1446. X        cerr.write(longopt, longopt_len) << " option." << endl ;
  1447. X     }
  1448. X     nextchar = NULL;           // we exhausted the rest of this arg
  1449. X!    return  optspec.OptChar();
  1450. X  }
  1451. X  
  1452. X  // ---------------------------------------------------------------------------
  1453. X  // ^FUNCTION: Options::usage - print usage
  1454. X  //
  1455. X  // ^SYNOPSIS:
  1456. X***************
  1457. X*** 825,832 ****
  1458. X  //    Print usage on os, wrapping long lines where necessary.
  1459. X  // ^^-------------------------------------------------------------------------
  1460. X  void
  1461. X! Options::usage(ostream & os, const char * positionals) const
  1462. X! {
  1463. X     const char * const * optv = optvec;
  1464. X     unsigned  cols = 79;
  1465. X     int  first, nloop;
  1466. X--- 912,918 ----
  1467. X  //    Print usage on os, wrapping long lines where necessary.
  1468. X  // ^^-------------------------------------------------------------------------
  1469. X  void
  1470. X! Options::usage(ostream & os, const char * positionals) const {
  1471. X     const char * const * optv = optvec;
  1472. X     unsigned  cols = 79;
  1473. X     int  first, nloop;
  1474. X***************
  1475. X*** 846,851 ****
  1476. X--- 932,938 ----
  1477. X        // print the options and the positional arguments
  1478. X     for (nloop = 0, first = 1 ; !nloop ; optv++, first = 0) {
  1479. X        unsigned  len;
  1480. X+       OptionSpec   optspec = *optv;
  1481. X  
  1482. X           // figure out how wide this parameter is (for printing)
  1483. X        if (! *optv) {
  1484. X***************
  1485. X*** 852,859 ****
  1486. X           len = strlen(positionals);
  1487. X           ++nloop;  // terminate this loop
  1488. X        } else {
  1489. X!          if (isHiddenOpt(*optv))  continue;
  1490. X!          len = fmt_opt(*optv, buf);
  1491. X        }
  1492. X  
  1493. X        //  Will this fit?
  1494. X--- 939,946 ----
  1495. X           len = strlen(positionals);
  1496. X           ++nloop;  // terminate this loop
  1497. X        } else {
  1498. X!          if (optspec.isHiddenOpt())  continue;
  1499. X!          len = optspec.Format(buf, optctrls);
  1500. X        }
  1501. X  
  1502. X        //  Will this fit?
  1503. X***************
  1504. X*** 908,915 ****
  1505. X  //    It gets complicated -- follow the comments in the source.
  1506. X  // ^^-------------------------------------------------------------------------
  1507. X  int
  1508. X! Options::operator()(OptIter & iter, const char * & optarg)
  1509. X! {
  1510. X     explicit_end = 0;
  1511. X  
  1512. X        // See if we have an option left over from before ...
  1513. X--- 995,1001 ----
  1514. X  //    It gets complicated -- follow the comments in the source.
  1515. X  // ^^-------------------------------------------------------------------------
  1516. X  int
  1517. X! Options::operator()(OptIter & iter, const char * & optarg) {
  1518. X     explicit_end = 0;
  1519. X  
  1520. X        // See if we have an option left over from before ...
  1521. X***************
  1522. X*** 921,941 ****
  1523. X     const char * arg = iter.curr();
  1524. X     if (arg == NULL) {
  1525. X        listopt = NULL;
  1526. X!       return  ENDOPTS;
  1527. X     } else if (isEndOpts(arg)) {
  1528. X        iter.next();   // advance past end-of-options arg
  1529. X        listopt = NULL;
  1530. X        explicit_end = 1;
  1531. X!       return  ENDOPTS;
  1532. X     }
  1533. X  
  1534. X        // Do we have a positional arg?
  1535. X     if (! listopt) {
  1536. X        if ((! *arg) || (! arg[1])) {
  1537. X!          return  ENDOPTS;
  1538. X        } else if ((*arg != '-') &&
  1539. X!                  ((! (optctrls & PLUS)) || (*arg != '+'))) {
  1540. X!          return  ENDOPTS;
  1541. X        }
  1542. X     }
  1543. X  
  1544. X--- 1007,1027 ----
  1545. X     const char * arg = iter.curr();
  1546. X     if (arg == NULL) {
  1547. X        listopt = NULL;
  1548. X!       return  Options::ENDOPTS;
  1549. X     } else if (isEndOpts(arg)) {
  1550. X        iter.next();   // advance past end-of-options arg
  1551. X        listopt = NULL;
  1552. X        explicit_end = 1;
  1553. X!       return  Options::ENDOPTS;
  1554. X     }
  1555. X  
  1556. X        // Do we have a positional arg?
  1557. X     if (! listopt) {
  1558. X        if ((! *arg) || (! arg[1])) {
  1559. X!          return  Options::ENDOPTS;
  1560. X        } else if ((*arg != '-') &&
  1561. X!                  ((! (optctrls & Options::PLUS)) || (*arg != '+'))) {
  1562. X!          return  Options::ENDOPTS;
  1563. X        }
  1564. X     }
  1565. X  
  1566. X***************
  1567. X*** 942,952 ****
  1568. X     iter.next();  // pass the argument that arg already points to
  1569. X  
  1570. X        // See if we have a long option ...
  1571. X!    if (! (optctrls & SHORT_ONLY)) {
  1572. X        if ((*arg == '-') && (arg[1] == '-')) {
  1573. X           nextchar = arg + 2;
  1574. X           return  parse_longopt(iter, optarg);
  1575. X!       } else if ((optctrls & PLUS) && (*arg == '+')) {
  1576. X           nextchar = arg + 1;
  1577. X           return  parse_longopt(iter, optarg);
  1578. X        }
  1579. X--- 1028,1038 ----
  1580. X     iter.next();  // pass the argument that arg already points to
  1581. X  
  1582. X        // See if we have a long option ...
  1583. X!    if (! (optctrls & Options::SHORT_ONLY)) {
  1584. X        if ((*arg == '-') && (arg[1] == '-')) {
  1585. X           nextchar = arg + 2;
  1586. X           return  parse_longopt(iter, optarg);
  1587. X!       } else if ((optctrls & Options::PLUS) && (*arg == '+')) {
  1588. X           nextchar = arg + 1;
  1589. X           return  parse_longopt(iter, optarg);
  1590. X        }
  1591. X***************
  1592. X*** 953,959 ****
  1593. X     }
  1594. X     if (*arg == '-') {
  1595. X        nextchar = arg + 1;
  1596. X!       if (optctrls & LONG_ONLY) {
  1597. X           return  parse_longopt(iter, optarg);
  1598. X        } else {
  1599. X           return  parse_opt(iter, optarg);
  1600. X--- 1039,1045 ----
  1601. X     }
  1602. X     if (*arg == '-') {
  1603. X        nextchar = arg + 1;
  1604. X!       if (optctrls & Options::LONG_ONLY) {
  1605. X           return  parse_longopt(iter, optarg);
  1606. X        } else {
  1607. X           return  parse_opt(iter, optarg);
  1608. X***************
  1609. X*** 961,967 ****
  1610. X     }
  1611. X  
  1612. X        // If we get here - it is because we have a list value
  1613. X     optarg = arg ;        // record the list value
  1614. X!    return  OptChar(listopt) ;
  1615. X  }
  1616. X  
  1617. X--- 1047,1054 ----
  1618. X     }
  1619. X  
  1620. X        // If we get here - it is because we have a list value
  1621. X+    OptionSpec  optspec = listopt;
  1622. X     optarg = arg ;        // record the list value
  1623. X!    return  optspec.OptChar() ;
  1624. X  }
  1625. X  
  1626. X*** options.h.OLD    Fri Feb 11 17:30:16 1994
  1627. X--- options.h    Fri Feb 11 17:27:01 1994
  1628. X***************
  1629. X*** 169,180 ****
  1630. X  public:
  1631. X     static const unsigned  MAX_LINE_LEN ;
  1632. X  
  1633. X- #ifdef vms
  1634. X-    enum { c_COMMENT = '!' } ;
  1635. X- #else
  1636. X-    enum { c_COMMENT = '#' } ;
  1637. X- #endif
  1638. X- 
  1639. X     OptIstreamIter(istream & input);
  1640. X  
  1641. X     virtual
  1642. X--- 169,174 ----
  1643. X***************
  1644. X*** 371,384 ****
  1645. X     const char   * listopt;       // last list-option we matched
  1646. X     const char   * cmdname;       // name of the command
  1647. X  
  1648. X     int
  1649. X     parse_opt(OptIter & iter, const char * & optarg);
  1650. X  
  1651. X     int
  1652. X     parse_longopt(OptIter & iter, const char * & optarg);
  1653. X- 
  1654. X-    unsigned
  1655. X-    fmt_opt(const char * optspec, char * buf) const;
  1656. X  
  1657. X  public:
  1658. X     enum OptCtrl {
  1659. X--- 365,384 ----
  1660. X     const char   * listopt;       // last list-option we matched
  1661. X     const char   * cmdname;       // name of the command
  1662. X  
  1663. X+    void
  1664. X+    check_syntax(void) const;
  1665. X+ 
  1666. X+    const char *
  1667. X+    match_opt(char opt, int ignore_case =0) const;
  1668. X+ 
  1669. X+    const char *
  1670. X+    match_longopt(const char * opt, int  len, int & ambiguous) const;
  1671. X+ 
  1672. X     int
  1673. X     parse_opt(OptIter & iter, const char * & optarg);
  1674. X  
  1675. X     int
  1676. X     parse_longopt(OptIter & iter, const char * & optarg);
  1677. X  
  1678. X  public:
  1679. X     enum OptCtrl {
  1680. X*** testopts.C.OLD    Fri Feb 11 17:30:19 1994
  1681. X--- testopts.C    Tue Feb 08 19:07:24 1994
  1682. X***************
  1683. X*** 32,48 ****
  1684. X  setflags(const char * flags_str, Options & opts) {
  1685. X     if (flags_str && *flags_str) {
  1686. X        unsigned  flags = opts.ctrls();
  1687. X!       if (::strchr(flags_str, '+'))  flags |= Options::PLUS;
  1688. X!       if (::strchr(flags_str, 'A'))  flags |= Options::ANYCASE;
  1689. X!       if (::strchr(flags_str, 'a'))  flags |= Options::ANYCASE;
  1690. X!       if (::strchr(flags_str, 'L'))  flags |= Options::LONG_ONLY;
  1691. X!       if (::strchr(flags_str, 'l'))  flags |= Options::LONG_ONLY;
  1692. X!       if (::strchr(flags_str, 'S'))  flags |= Options::SHORT_ONLY;
  1693. X!       if (::strchr(flags_str, 's'))  flags |= Options::SHORT_ONLY;
  1694. X!       if (::strchr(flags_str, 'Q'))  flags |= Options::QUIET;
  1695. X!       if (::strchr(flags_str, 'q'))  flags |= Options::QUIET;
  1696. X!       if (::strchr(flags_str, 'n'))  flags |= Options::NOGUESSING;
  1697. X!       if (::strchr(flags_str, 'N'))  flags |= Options::NOGUESSING;
  1698. X        opts.ctrls(flags);
  1699. X     }
  1700. X  }
  1701. X--- 32,61 ----
  1702. X  setflags(const char * flags_str, Options & opts) {
  1703. X     if (flags_str && *flags_str) {
  1704. X        unsigned  flags = opts.ctrls();
  1705. X!       for (const char * p = flags_str; *p; p++) {
  1706. X!          switch (*p) {
  1707. X!             case '+' :
  1708. X!                flags |= Options::PLUS;
  1709. X!                break;
  1710. X!             case 'A' : case 'a' :
  1711. X!                flags |= Options::ANYCASE;
  1712. X!                break;
  1713. X!             case 'L' : case 'l' :
  1714. X!                flags |= Options::LONG_ONLY;
  1715. X!                break;
  1716. X!             case 'S' : case 's' :
  1717. X!                flags |= Options::SHORT_ONLY;
  1718. X!                break;
  1719. X!             case 'Q' : case 'q' :
  1720. X!                flags |= Options::QUIET;
  1721. X!                break;
  1722. X!             case 'N' : case 'n' :
  1723. X!                flags |= Options::NOGUESSING;
  1724. X!                break;
  1725. X!             default  :
  1726. X!                break;
  1727. X!          }
  1728. X!       }
  1729. X        opts.ctrls(flags);
  1730. X     }
  1731. X  }
  1732. END_OF_FILE
  1733. if test 49743 -ne `wc -c <'PATCH03'`; then
  1734.     echo shar: \"'PATCH03'\" unpacked with wrong size!
  1735. fi
  1736. # end of 'PATCH03'
  1737. fi
  1738. echo shar: End of shell archive.
  1739. exit 0
  1740.  
  1741. exit 0 # Just in case...
  1742.