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