home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 1 / FFMCD01.bin / bbs / libdisks / d700t799 / disk713.lha / Free / Source / getopt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-19  |  7.2 KB  |  251 lines

  1. /****************************************************************************
  2.  * getopt():    Return the next user option on each iteration. 
  3.  *        This is a clone of the usual UNIX getopt() function.
  4.  *        If you have never used a getopt() before, you'll have to
  5.  *          read about it on any UNIX machine or other C system that
  6.  *          documents it.
  7.  *
  8.  * Author:    Daniel J. Barrett, barrett@cs.umass.edu.
  9.  * Date:    December 17, 1991
  10.  * Version:    1.1b.
  11.  *
  12.  * License:    This code is placed in the Public Domain.
  13.  *        Give it away to anybody for free!
  14.  *        Use it for any purpose you like!
  15.  *
  16.  *        If you use this code in a program, please give me credit
  17.  *        for my work.  Thanks!
  18.  *
  19.  * Why I wrote it:
  20.  *
  21.  *        Because every other getopt() function I have ever seen
  22.  *         had source code that was difficult to understand.
  23.  *        I wrote this code to be very modular and readable.
  24.  *        I hope you find it instructive and/or helpful.
  25.  *
  26.  * REVISION HISTORY:
  27.  *
  28.  *    Version:    1.1b
  29.  *    Date:        December 17, 1991.
  30.  *    Comments:    Minor change of NULL to '\0' in 1 spot.
  31.  *
  32.  *    Version:    1.1
  33.  *    Date:        February 20, 1991.
  34.  *    Comments:    Bug fix in Pass().  Forgot to check that the
  35.  *            current argument is non-empty and starts with
  36.  *            a DASH.
  37.  *
  38.  *            Got rid of the unnecessary "g_" at the beginning
  39.  *            of each function name.  Since they're static, we
  40.  *            don't have to worry about duplication of names
  41.  *            by the calling program.
  42.  *
  43.  *    Version:    1.0
  44.  *    Date:        April 12, 1990.
  45.  *    Comments:    First released version.
  46.  *
  47.  ****************************************************************************/
  48.  
  49. #ifndef __STDIO_H    /* If we haven't already included stdio.h, do it. */
  50. #include <stdio.h>    /* Maybe someday I'll eliminate this. */
  51. #endif
  52.  
  53. /************************************************************************
  54. * Some constants.
  55. ************************************************************************/
  56.  
  57. #define    DASH        '-'    /* This preceeds an option. */
  58. #define    ARG_COMING    ':'    /* In the option string, this indicates that
  59.                  * that the option requires an argument. */
  60. #define    UNKNOWN_OPT    '?'    /* The char returned for unknown option. */
  61.  
  62. /************************************************************************
  63. * Internal error codes.
  64. ************************************************************************/
  65.  
  66. #define    ERROR_BAD_OPTION    1
  67. #define    ERROR_MISSING_ARGUMENT    2
  68.  
  69. /************************************************************************
  70. * Mnemonic macros.
  71. ************************************************************************/
  72.  
  73.  
  74.  
  75. /************************************************************************
  76. * ANSI function prototypes.
  77. ************************************************************************/
  78.  
  79. int        getopt(int argc, char *argv[], char *optString);
  80. static int    NextOption(char *argv[], char *optString);
  81. static int    RealOption(char *argv[], char *str, int *skip, int *ind,
  82.                  int opt);
  83. static void    HandleArgument(char *argv[], int *optind, int *skip);
  84. static void    Error(int err, int c);
  85. static void    Pass(char *argv[], int *optind, int *optsSkipped);
  86.  
  87. extern char    *index();
  88.  
  89. /************************************************************************
  90. * Global variables.  You must declare these externs in your program
  91. * if you want to see their values!
  92. ************************************************************************/
  93.     
  94. char    *optarg    = NULL;    /* This will point to a required argument, if any. */
  95. int    optind    = 1;    /* The index of the next argument in argv. */
  96. int    opterr    = 1;    /* 1 == print internal error messages.  0 else. */
  97. int    optopt;        /* The actual option letter that was found. */
  98.  
  99.  
  100. int getopt(int argc, char *argv[], char *optString)
  101. {
  102.     optarg = NULL;
  103.     if (optind < argc)        /* More arguments to check. */
  104.         return(NextOption(argv, optString));
  105.     else                /* We're done. */
  106.         return(EOF);
  107. }
  108.  
  109.  
  110. /* If the current argument does not begin with DASH, it is not an option.
  111.  * Return EOF.
  112.  * If we have ONLY a DASH, and nothing after it... return EOF as well.
  113.  * If we have a DASH followed immediately by another DASH, this is the
  114.  * special "--" option that means "no more options follow."  Return EOF.
  115.  * Otherwise, we have an actual option or list of options.  Process it. */
  116.     
  117. static int NextOption(char *argv[], char *optString)
  118. {
  119.     static int optsSkipped = 0;    /* In a single argv[i]. */
  120.     
  121.     if ((argv[optind][0] == DASH)
  122.     &&  ((optopt = argv[optind][1+optsSkipped]) != '\0'))
  123.     {
  124.         if (optopt == DASH)
  125.         {
  126.             optind++;
  127.             return(EOF);
  128.         }
  129.         else
  130.             return(RealOption(argv, optString, &optsSkipped,
  131.                         &optind, optopt));
  132.     }
  133.     else
  134.         return(EOF);
  135. }
  136.  
  137.  
  138. /* At this point, we know that argv[optind] is an option or list of
  139.  * options.  If this is a list of options, *optsSkipped tells us how
  140.  * many of those options have ALREADY been parsed on previous calls
  141.  * to getopt().
  142.  * If the option is not legal (not in optString), complain and return
  143.  * UNKNOWN_OPT.
  144.  * If the option requires no argument, just return the option letter.
  145.  * If the option requires an argument, call HandleArgument and return
  146.  * the option letter. */
  147.     
  148. static int RealOption(char *argv[], char *optString, int *optsSkipped,
  149.             int *optind, int optopt)
  150. {
  151.     char *where;
  152.  
  153.     (*optsSkipped)++;
  154.     if (where = index(optString, optopt))
  155.     {
  156.         if (*(where+1) == ARG_COMING)
  157.             HandleArgument(argv, optind, optsSkipped);
  158.  
  159.         Pass(argv, optind, optsSkipped);
  160.         return(optopt);
  161.     }
  162.     else
  163.     {
  164.         Error(ERROR_BAD_OPTION, optopt);
  165.         Pass(argv, optind, optsSkipped);
  166.         return(UNKNOWN_OPT);
  167.     }
  168. }
  169.  
  170.  
  171. /* We have an option in argv[optind] that requires an argument.  If there
  172.  * is no whitespace after the option letter itself, take the rest of
  173.  * argv[optind] to be the argument.
  174.  * If there IS whitespace after the option letter, take argv[optind+1] to
  175.  * be the argument.
  176.  * Otherwise, if there is NO argument, complain! */
  177.  
  178. static void HandleArgument(char *argv[], int *optind, int *optsSkipped)
  179. {
  180.     if (argv[*optind][1+(*optsSkipped)])
  181.         optarg = argv[*optind] + 1 + (*optsSkipped);
  182.     else if (argv[(*optind)+1])
  183.     {
  184.         optarg = argv[(*optind)+1];
  185.         (*optind)++;
  186.     }
  187.     else
  188.         Error(ERROR_MISSING_ARGUMENT, optopt);
  189.  
  190.     (*optsSkipped) = 0;
  191.     (*optind)++;
  192. }
  193.  
  194.  
  195. /* Print an appropriate error message. */
  196.  
  197. static void Error(int err, int c)
  198. {
  199.     static char *optmsg = "Illegal option.\n";
  200.     static char *argmsg = "An argument is required, but missing.\n";
  201.  
  202.     if (opterr)
  203.     {
  204.         if (err == ERROR_BAD_OPTION)
  205.             fprintf(stderr, "-%c: %s", c, optmsg);
  206.         else if (err == ERROR_MISSING_ARGUMENT)
  207.             fprintf(stderr, "-%c: %s", c, argmsg);
  208.  
  209.         else    /* Sanity check! */
  210.             fprintf(stderr, "-%c: an unknown error occurred\n",
  211.                 c);
  212.     }
  213. }
  214.  
  215.  
  216. /* We have reached the end of argv[optind]... there are no more options
  217.  * in it to parse.  Skip to the next item in argv. */
  218.  
  219. static void Pass(char *argv[], int *optind, int *optsSkipped)
  220. {
  221.     if (argv[*optind]
  222.     &&  (argv[*optind][0] == DASH)
  223.     &&  (argv[*optind][1+(*optsSkipped)] == '\0'))
  224.     {
  225.         (*optind)++;
  226.         (*optsSkipped) = 0;
  227.     }
  228. }
  229.  
  230. /***************************************************************************
  231. * A test program.  Compile this file with -DTESTME as an option.
  232. ***************************************************************************/
  233.  
  234. #ifdef TESTME
  235. main(int argc, char *argv[])
  236. {
  237.     char c;
  238.  
  239.     while ((c = getopt(argc, argv, "a:b:cde")) != EOF)
  240.         {
  241.         printf("OPTION %c", c);
  242.         if ((c == 'a') || (c == 'b'))
  243.             printf(", %s\n", optarg);
  244.         else
  245.             printf("\n");
  246.         printf("argc=%d, optind=%d\n", argc, optind);
  247.     }
  248.     exit(0);
  249. }
  250. #endif
  251.