home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / EFFO / forum7.lzh / RICO / C / LIBSOURCE / EGETOPT / egetopt.c < prev    next >
Text File  |  2009-11-06  |  7KB  |  277 lines

  1. /*
  2.  * egetopt.c -- Extended 'getopt'.
  3.  *
  4.  * A while back, a public-domain version of getopt() was posted to the
  5.  * net.  A bit later, a gentleman by the name of Keith Bostic made some
  6.  * enhancements and reposted it.
  7.  *
  8.  * In recent weeks (i.e., early-to-mid 1988) there's been some
  9.  * heated discussion in comp.lang.c about the merits and drawbacks
  10.  * of getopt(), especially with regard to its handling of '?'.
  11.  *
  12.  * In light of this, I have taken Mr. Bostic's public-domain getopt()
  13.  * and have made some changes that I hope will be considered to be
  14.  * improvements.  I call this routine 'egetopt' ("Extended getopt").
  15.  * The default behavior of this routine is the same as that of getopt(),
  16.  * but it has some optional features that make it more useful.  These
  17.  * options are controlled by the settings of some global variables.
  18.  * By not setting any of these extra global variables, you will have
  19.  * the same functionality as getopt(), which should satisfy those
  20.  * purists who believe getopt() is perfect and can never be improved.
  21.  * If, on the other hand, you are someone who isn't satisfied with the
  22.  * status quo, egetopt() may very well give you the added capabilities
  23.  * you want.
  24.  *
  25.  * Look at the enclosed README file for a description of egetopt()'s
  26.  * new features.
  27.  *
  28.  * The code was originally posted to the net as getopt.c by ...
  29.  *
  30.  *    Keith Bostic
  31.  *    ARPA: keith@seismo 
  32.  *    UUCP: seismo!keith
  33.  *
  34.  * Current version: added enhancements and comments, reformatted code.
  35.  *
  36.  *    Lloyd Zusman
  37.  *    Master Byte Software
  38.  *    Los Gatos, California
  39.  *    Internet:    ljz@fx.com
  40.  *    UUCP:        ...!ames!fxgrp!ljz
  41.  *
  42.  *        May, 1988
  43.  */
  44.  
  45. /*
  46.  * If you want, include stdio.h or something where EOF and NULL are defined.
  47.  * However, egetopt() is written so as not to need stdio.h, which should
  48.  * make it significantly smaller on some systems.
  49.  */
  50.  
  51. #ifndef EOF
  52. # define EOF        (-1)
  53. #endif /* ! EOF */
  54.  
  55. #ifndef NULL
  56. # define NULL        (char *)0
  57. #endif /* ! NULL */
  58.  
  59. /*
  60.  * None of these constants are referenced in the executable portion of
  61.  * the code ... their sole purpose is to initialize global variables.
  62.  */
  63. #define BADCH        (int)'?'
  64. #define NEEDSEP        (int)':'
  65. #define MAYBESEP    (int)'\0'
  66. #define ERRFD        2
  67. #define EMSG        ""
  68. #define START        "-"
  69.  
  70. /*
  71.  * Here are all the pertinent global variables.
  72.  */
  73. int opterr = 1;        /* if true, output error message */
  74. int optind = 1;        /* index into parent argv vector */
  75. int optopt;        /* character checked for validity */
  76. int optbad = BADCH;    /* character returned on error */
  77. int optchar = 0;    /* character that begins returned option */
  78. int optneed = NEEDSEP;    /* flag for mandatory argument */
  79. int optmaybe = MAYBESEP;/* flag for optional argument */
  80. int opterrfd = ERRFD;    /* file descriptor for error text */
  81. char *optarg;        /* argument associated with option */
  82. char *optstart = START;    /* list of characters that start options */
  83.  
  84.  
  85. /*
  86.  * Macros.
  87.  */
  88.  
  89. /*
  90.  * Conditionally print out an error message and return (depends on the
  91.  * setting of 'opterr' and 'opterrfd').  Note that this version of
  92.  * TELL() doesn't require the existence of stdio.h.
  93.  */
  94. #define TELL(S)    { \
  95.     if (opterr && opterrfd >= 0) { \
  96.         char option = optopt; \
  97.         write(opterrfd, *nargv, strlen(*nargv)); \
  98.         write(opterrfd, (S), strlen(S)); \
  99.         write(opterrfd, &option, 1); \
  100.         write(opterrfd, "\n", 1); \
  101.     } \
  102.     return (optbad); \
  103. }
  104.  
  105. /*
  106.  * This works similarly to index() and strchr().  I include it so that you
  107.  * don't need to be concerned as to which one your system has.
  108.  */
  109. static char *
  110. _sindex(string, ch)
  111. char *string;
  112. int ch;
  113. {
  114.     if (string != NULL) {
  115.         for (; *string != '\0'; ++string) {
  116.             if (*string == (char)ch) {
  117.                 return (string);
  118.             }
  119.         }
  120.     }
  121.  
  122.     return (NULL);
  123. }
  124.  
  125. /*
  126.  * Here it is:
  127.  */
  128. int
  129. egetopt(nargc, nargv, ostr)
  130. int nargc;
  131. char **nargv;
  132. char *ostr;
  133. {
  134.     static char *place = EMSG;    /* option letter processing */
  135.     register char *oli;        /* option letter list index */
  136.     register char *osi = NULL;    /* option start list index */
  137.  
  138.     if (nargv == (char **)NULL) {
  139.         return (EOF);
  140.     }
  141.  
  142.     if (nargc <= optind || nargv[optind] == NULL) {
  143.         return (EOF);
  144.     }
  145.  
  146.     if (place == NULL) {
  147.         place = EMSG;
  148.     }
  149.  
  150.     /*
  151.      * Update scanning pointer.
  152.      */
  153.     if (*place == '\0') {
  154.         place = nargv[optind];
  155.         if (place == NULL) {
  156.             return (EOF);
  157.         }
  158.         osi = _sindex(optstart, *place);
  159.         if (osi != NULL) {
  160.             optchar = (int)*osi;
  161.         }
  162.         if (optind >= nargc || osi == NULL || *++place == '\0') {
  163.                 return (EOF);
  164.         }
  165.  
  166.         /*
  167.          * Two adjacent, identical flag characters were found.
  168.          * This takes care of "--", for example.
  169.          */
  170.         if (*place == place[-1]) {
  171.             ++optind;
  172.             return (EOF);
  173.         }
  174.     }
  175.  
  176.     /*
  177.      * If the option is a separator or the option isn't in the list,
  178.      * we've got an error.
  179.      */
  180.     optopt = (int)*place++;
  181.     oli = _sindex(ostr, optopt);
  182.     if (optopt == optneed || optopt == optmaybe || oli == NULL) {
  183.         /*
  184.          * If we're at the end of the current argument, bump the
  185.          * argument index.
  186.          */
  187.         if (*place == '\0') {
  188.             ++optind;
  189.         }
  190.         TELL(": illegal option -- ");    /* byebye */
  191.     }
  192.  
  193.     /*
  194.      * If there is no argument indicator, then we don't even try to
  195.      * return an argument.
  196.      */
  197.     ++oli;
  198.     if (*oli == '\0' || (*oli != optneed && *oli != optmaybe)) {
  199.         /*
  200.          * If we're at the end of the current argument, bump the
  201.          * argument index.
  202.          */
  203.         if (*place == '\0') {
  204.             ++optind;
  205.         }
  206.         optarg = NULL;
  207.     }
  208.     /*
  209.      * If we're here, there's an argument indicator.  It's handled
  210.      * differently depending on whether it's a mandatory or an
  211.      * optional argument.
  212.      */
  213.     else {
  214.         /*
  215.          * If there's no white space, use the rest of the
  216.          * string as the argument.  In this case, it doesn't
  217.          * matter if the argument is mandatory or optional.
  218.          */
  219.         if (*place != '\0') {
  220.             optarg = place;
  221.         }
  222.         /*
  223.          * If we're here, there's whitespace after the option.
  224.          *
  225.          * Is it a mandatory argument?  If so, return the
  226.          * next command-line argument if there is one.
  227.          */
  228.         else if (*oli == optneed) {
  229.             /*
  230.              * If we're at the end of the argument list, there
  231.              * isn't an argument and hence we have an error.
  232.              * Otherwise, make 'optarg' point to the argument.
  233.              */
  234.             if (nargc <= ++optind) {
  235.                 place = EMSG;
  236.                 TELL(": option requires an argument -- ");
  237.             }
  238.             else {
  239.                 optarg = nargv[optind];
  240.             }
  241.         }
  242.         /*
  243.          * If we're here it must have been an optional argument.
  244.          */
  245.         else {
  246.             if (nargc <= ++optind) {
  247.                 place = EMSG;
  248.                 optarg = NULL;
  249.             }
  250.             else {
  251.                 optarg = nargv[optind];
  252.                 if (optarg == NULL) {
  253.                     place = EMSG;
  254.                 }
  255.                 /*
  256.                  * If the next item begins with a flag
  257.                  * character, we treat it like a new
  258.                  * argument.  This is accomplished by
  259.                  * decrementing 'optind' and returning
  260.                  * a null argument.
  261.                  */
  262.                 else if (_sindex(optstart, *optarg) != NULL) {
  263.                     --optind;
  264.                     optarg = NULL;
  265.                 }
  266.             }
  267.         }
  268.         place = EMSG;
  269.         ++optind;
  270.     }
  271.  
  272.     /*
  273.      * Return option letter.
  274.      */
  275.     return (optopt);
  276. }
  277.