home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 300-399 / ff388.lzh / Free / getopt.c < prev    next >
C/C++ Source or Header  |  1990-10-23  |  6KB  |  200 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 Barrett, barrett@cs.jhu.edu.
  9.  * Date:    April 12, 1990.
  10.  * Version:    1.0.
  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.  ****************************************************************************/
  27.  
  28. #ifndef __STDIO_H    /* If we haven't already included stdio.h, do it. */
  29. #include <stdio.h>    /* Maybe someday I'll eliminate this. */
  30. #endif
  31.  
  32. /************************************************************************
  33. * Some constants.
  34. ************************************************************************/
  35.  
  36. #define    DASH        '-'    /* This preceeds an option. */
  37. #define    ARG_COMING    ':'    /* In the option string, this indicates that
  38.                  * that the option requires an argument. */
  39. #define    UNKNOWN_OPT    '?'    /* The char returned for unknown option. */
  40.  
  41. /************************************************************************
  42. * Internal error codes.
  43. ************************************************************************/
  44.  
  45. #define    ERROR_BAD_OPTION    1
  46. #define    ERROR_MISSING_ARGUMENT    2
  47.  
  48. /************************************************************************
  49. * ANSI function prototypes.
  50. ************************************************************************/
  51.  
  52. int        getopt(int argc, char *argv[], char *optString);
  53. static int    g_NextOption(char *argv[], char *optString);
  54. static int    g_RealOption(char *argv[], char *str, int *skip, int *ind,
  55.                  int opt);
  56. static void    g_HandleArgument(char *argv[], int *optind, int *skip);
  57. static void    g_Error(int err, int c);
  58. static void    g_Pass(char *argv[], int *optind, int *optsSkipped);
  59.  
  60. extern char    *index();
  61.  
  62. /************************************************************************
  63. * Global variables.  You must declare these externs in your program
  64. * if you want to see their values!
  65. ************************************************************************/
  66.     
  67. char    *optarg    = NULL;    /* This will point to a required argument, if any. */
  68. int    optind    = 1;    /* The index of the next argument in argv. */
  69. int    opterr    = 1;    /* 1 == print internal error messages.  0 else. */
  70. int    optopt;        /* The actual option letter that was found. */
  71.  
  72.  
  73. int getopt(int argc, char *argv[], char *optString)
  74. {
  75.     optarg = NULL;
  76.     if (optind < argc)        /* More arguments to check. */
  77.         return(g_NextOption(argv, optString));
  78.     else                /* We're done. */
  79.         return(EOF);
  80. }
  81.  
  82.  
  83. /* If the current argument does not begin with DASH, it is not an option.
  84.  * Return EOF.
  85.  * If we have ONLY a DASH, and nothing after it... return EOF as well.
  86.  * If we have a DASH followed immediately by another DASH, this is the
  87.  * special "--" option that means "no more options follow."  Return EOF.
  88.  * Otherwise, we have an actual option or list of options.  Process it. */
  89.     
  90. static int g_NextOption(char *argv[], char *optString)
  91. {
  92.     static int optsSkipped = 0;    /* In a single argv[i]. */
  93.     
  94.     if ((argv[optind][0] == DASH)
  95.     &&  ((optopt = argv[optind][1+optsSkipped]) != '\0'))
  96.     {
  97.         if (optopt == DASH)
  98.         {
  99.             optind++;
  100.             return(EOF);
  101.         }
  102.         else
  103.             return(g_RealOption(argv, optString, &optsSkipped,
  104.                         &optind, optopt));
  105.     }
  106.     else
  107.         return(EOF);
  108. }
  109.  
  110.  
  111. /* At this point, we know that argv[optind] is an option or list of
  112.  * options.  If this is a list of options, *optsSkipped tells us how
  113.  * many of those options have ALREADY been parsed on previous calls
  114.  * to getopt().
  115.  * If the option is not legal (not in optString), complain and return
  116.  * UNKNOWN_OPT.
  117.  * If the option requires no argument, just return the option letter.
  118.  * If the option requires an argument, call g_HandleArgument and return
  119.  * the option letter. */
  120.     
  121. static int g_RealOption(char *argv[], char *optString, int *optsSkipped,
  122.             int *optind, int optopt)
  123. {
  124.     char *where;
  125.  
  126.     (*optsSkipped)++;
  127.     if (where = index(optString, optopt))
  128.     {
  129.         if (*(where+1) == ARG_COMING)
  130.             g_HandleArgument(argv, optind, optsSkipped);
  131.  
  132.         g_Pass(argv, optind, optsSkipped);
  133.         return(optopt);
  134.     }
  135.     else
  136.     {
  137.         g_Error(ERROR_BAD_OPTION, optopt);
  138.         g_Pass(argv, optind, optsSkipped);
  139.         return(UNKNOWN_OPT);
  140.     }
  141. }
  142.  
  143.  
  144. /* We have an option in argv[optind] that requires an argument.  If there
  145.  * is no whitespace after the option letter itself, take the rest of
  146.  * argv[optind] to be the argument.
  147.  * If there IS whitespace after the option letter, take argv[optind+1] to
  148.  * be the argument.
  149.  * Otherwise, if there is NO argument, complain! */
  150.  
  151. static void g_HandleArgument(char *argv[], int *optind, int *optsSkipped)
  152. {
  153.     if (argv[*optind][1+(*optsSkipped)])
  154.         optarg = argv[*optind] + 1 + (*optsSkipped);
  155.     else if (argv[(*optind)+1])
  156.     {
  157.         optarg = argv[(*optind)+1];
  158.         (*optind)++;
  159.     }
  160.     else
  161.         g_Error(ERROR_MISSING_ARGUMENT, optopt);
  162.  
  163.     (*optsSkipped) = 0;
  164.     (*optind)++;
  165. }
  166.  
  167.  
  168. /* Print an appropriate error message. */
  169.  
  170. static void g_Error(int err, int c)
  171. {
  172.     static char *optmsg = "Illegal option.\n";
  173.     static char *argmsg = "An argument is required, but missing.\n";
  174.  
  175.     if (opterr)
  176.     {
  177.         if (err == ERROR_BAD_OPTION)
  178.             fprintf(stderr, "-%c: %s", c, optmsg);
  179.         else if (err == ERROR_MISSING_ARGUMENT)
  180.             fprintf(stderr, "-%c: %s", c, argmsg);
  181.  
  182.         else    /* Sanity check! */
  183.             fprintf(stderr, "-%c: an unknown error occurred\n",
  184.                 c);
  185.     }
  186. }
  187.  
  188.  
  189. /* We have reached the end of argv[optind]... there are no more options
  190.  * in it to parse.  Skip to the next item in argv. */
  191.  
  192. static void g_Pass(char *argv[], int *optind, int *optsSkipped)
  193. {
  194.     if ( !(argv[*optind][1+(*optsSkipped)]) )
  195.     {
  196.         (*optind)++;
  197.         (*optsSkipped) = 0;
  198.     }
  199. }
  200.