home *** CD-ROM | disk | FTP | other *** search
/ World of Graphics / WOGRAPH.BIN / 458.GETOPT.C < prev    next >
C/C++ Source or Header  |  1993-02-11  |  12KB  |  358 lines

  1. /****************************************************************************
  2. *
  3. *                   Copyright (C) 1993 Kendall Bennett.
  4. *                            All rights reserved.
  5. *
  6. * Filename:        $RCSfile: getopt.c $
  7. * Version:        $Revision: 1.5 $
  8. *
  9. * Language:        ANSI C
  10. * Environment:    any
  11. *
  12. * Description:    This module contains code to parse the command line,
  13. *                extracting options and parameters in standard System V
  14. *                style.
  15. *
  16. * $Id: getopt.c 1.5 1991/12/31 19:39:55 kjb Exp $
  17. *
  18. * Revision History:
  19. * -----------------
  20. *
  21. * $Log: getopt.c $
  22. * Revision 1.5  1991/12/31  19:39:55  kjb
  23. * Modified include file directories.
  24. *
  25. * Revision 1.4  91/10/28  03:17:02  kjb
  26. * Ported to the Iris.
  27. * Revision 1.3  91/09/24  19:48:05  kjb
  28. * Added getargs() to parse the entire command line and converting the
  29. * parameters to the types specified in a table of options.
  30. * Added routine print_desc() to print the option description from the
  31. * table to the standard output device.
  32. * Revision 1.2  91/09/03  18:27:52  ROOT_DOS
  33. * Ported to UNIX.
  34. * Revision 1.1  91/08/16  10:45:36  ROOT_DOS
  35. * Initial revision
  36. ****************************************************************************/
  37.  
  38. #include <stdio.h>
  39. #include <string.h>
  40. #include <ctype.h>
  41. #include "debug.h"
  42. #include "getopt.h"
  43.  
  44. /*------------------------- Global variables ------------------------------*/
  45.  
  46. int        nextargv    =    1;            /* Index into argv array            */
  47. char    *nextchar    =    NULL;        /* Pointer to next character        */
  48.  
  49. /*-------------------------- Implementation -------------------------------*/
  50.  
  51. #ifdef    __MSDOS__
  52. #define    IS_SWITCH_CHAR(c)        (c == '-') || (c == '/')
  53. #define    IS_NOT_SWITCH_CHAR(c)    (c != '-') && (c != '/')
  54. #else
  55. #define    IS_SWITCH_CHAR(c)        (c == '-')
  56. #define    IS_NOT_SWITCH_CHAR(c)    (c != '-')
  57. #endif
  58.  
  59. PUBLIC int getopt(int argc,char **argv,char *format,char **argument)
  60. /****************************************************************************
  61. *
  62. * Function:        getopt
  63. * Parameters:    argc        -    Value passed to program through argc
  64. *                                variable in the function main.
  65. *                argv        -     Pointer to the argv array that is passed to
  66. *                                the program in function main.
  67. *                format        -    A string representing the expected format
  68. *                                of the command line options that need to be
  69. *                                parsed.
  70. *                argument    -     Pointer to optional argument on command
  71. *                                line.
  72. *
  73. * Returns:        Character code representing the next option parsed from the
  74. *                command line by getopt. Returns ALLDONE (-1) when there are
  75. *                no more parameters to be parsed on the command line,
  76. *                PARAMETER (-2) when the argument being parsed is a
  77. *                parameter and not an option switch and lastly INVALID (-3)
  78. *                if an error occured while parsing the command line.
  79. *
  80. * Description:    Function to parse the command line option switches in
  81. *                UNIX System V style. When getopt is called, it returns the
  82. *                character code of the next valid option that is parsed from
  83. *                the command line as specified by the Format string. The
  84. *                format string should be in the following form:
  85. *
  86. *                        "abcd:e:f:"
  87. *
  88. *                where a,b and c represent single switch style options and
  89. *                the character code returned by getopt is the only value
  90. *                returned. Also d, e and f represent options that expect
  91. *                arguments immediately after them on the command line. The
  92. *                argument that follows the option on the command line is
  93. *                returned via a reference in the pointer argument. Thus
  94. *                a valid command line for this format string might be:
  95. *
  96. *                    myprogram -adlines /b /f format infile outfile
  97. *
  98. *                where a and b will be returned as single character options
  99. *                with no argument, while d is returned with the argument
  100. *                lines and f is returned with the argument format. Note that
  101. *                either UNIX style or MS-DOS command switches may be used
  102. *                interchangeably under MSDOS, but under UNIX only the UNIX
  103. *                style switches are supported.
  104. *
  105. *                When getopt returns with PARAMETER (we attempted to parse
  106. *                a paramter, not an option), the global variable NextArgv
  107. *                will hold an index in the argv array to the argument on the
  108. *                command line AFTER the options, ie in the above example the
  109. *                string 'infile'. If the parameter is successfully used,
  110. *                NextArgv should be incremented and getopt can be called
  111. *                again to parse any more options. Thus you can also have
  112. *                options interspersed throught the command line. eg:
  113. *
  114. *                    myprogram -adlines infile /b outfile /f format
  115. *
  116. *                can be made to be a valid form of the above command line.
  117. *
  118. ****************************************************************************/
  119. {
  120.     char    ch;
  121.     char    *formatchar;
  122.  
  123.     if (argc > nextargv) {
  124.         if (nextchar == NULL) {
  125.             nextchar = argv[nextargv];        /* Index next argument         */
  126.             if(nextchar == NULL) {
  127.                 nextargv++;
  128.                 return ALLDONE;                /* No more options             */
  129.                 }
  130.             if(IS_NOT_SWITCH_CHAR(*nextchar)) {
  131.                 nextchar = NULL;
  132.                 return PARAMETER;            /* We have a parameter         */
  133.                 }
  134.             nextchar++;                    /* Move past switch operator    */
  135.             if(IS_SWITCH_CHAR(*nextchar)) {
  136.                 nextchar = NULL;
  137.                 return INVALID;                /* Ignore rest of line         */
  138.                 }
  139.             }
  140.  
  141.         if ((ch = *(nextchar++)) == 0) {
  142.             nextchar = NULL;
  143.             return INVALID;                    /* No options on line         */
  144.             }
  145.  
  146.         if (ch == ':' ||  (formatchar = strchr(format, ch)) == NULL)
  147.             return INVALID;
  148.  
  149.         if (*(++formatchar) == ':') {    /* Expect an argument after option */
  150.             nextargv++;
  151.             if (*nextchar == 0) {
  152.                 if (argc <= nextargv)
  153.                     return INVALID;
  154.                 nextchar = argv[nextargv++];
  155.                 }
  156.             *argument = nextchar;
  157.             nextchar = NULL;
  158.             }
  159.         else {                        /* We have a switch style option    */
  160.             if (*nextchar == 0) {
  161.                 nextargv++;
  162.                 nextchar = NULL;
  163.             }
  164.             *argument = NULL;
  165.             }
  166.         return ch;                    /* return the option specifier         */
  167.         }
  168.     nextchar = NULL;
  169.     nextargv++;
  170.     return ALLDONE;                    /* no arguments on command line     */
  171. }
  172.  
  173. PRIVATE int parse_option(Option *optarr,char *argument)
  174. /****************************************************************************
  175. *
  176. * Function:        parse_option
  177. * Parameters:    optarr        - Description for the option we are parsing
  178. *                argument    - String to parse
  179. * Returns:        INVALID on error, ALLDONE on success.
  180. *
  181. * Description:    Parses the argument string depending on the type of argument
  182. *                that is expected, filling in the argument for that option.
  183. *                Note that to parse a string, we simply return a pointer
  184. *                to argument.
  185. *
  186. ****************************************************************************/
  187. {
  188.     int        num_read = 0;
  189.  
  190.     switch ((int)(optarr->type)) {
  191.         case OPT_INTEGER:
  192.             num_read = sscanf(argument,"%d",optarr->arg);
  193.             break;
  194.         case OPT_HEX:
  195.             num_read = sscanf(argument,"%x",optarr->arg);
  196.             break;
  197.         case OPT_OCTAL:
  198.             num_read = sscanf(argument,"%o",optarr->arg);
  199.             break;
  200.         case OPT_UNSIGNED:
  201.             num_read = sscanf(argument,"%u",optarr->arg);
  202.             break;
  203.         case OPT_LINTEGER:
  204.             num_read = sscanf(argument,"%ld",optarr->arg);
  205.             break;
  206.         case OPT_LHEX:
  207.             num_read = sscanf(argument,"%lx",optarr->arg);
  208.             break;
  209.         case OPT_LOCTAL:
  210.             num_read = sscanf(argument,"%lo",optarr->arg);
  211.             break;
  212.         case OPT_LUNSIGNED:
  213.             num_read = sscanf(argument,"%lu",optarr->arg);
  214.             break;
  215.         case OPT_FLOAT:
  216.             num_read = sscanf(argument,"%f",optarr->arg);
  217.             break;
  218.         case OPT_DOUBLE:
  219.             num_read = sscanf(argument,"%lf",optarr->arg);
  220.             break;
  221.         case OPT_LDOUBLE:
  222.             num_read = sscanf(argument,"%Lf",optarr->arg);
  223.             break;
  224.         case OPT_STRING:
  225.             num_read = 1;            /* This always works    */
  226.             *((char**)optarr->arg) = argument;
  227.             break;
  228.         default:
  229.             return INVALID;
  230.         }
  231.  
  232.     if (num_read == 0)
  233.         return INVALID;
  234.     else
  235.         return ALLDONE;
  236. }
  237.  
  238. PUBLIC int getargs(int argc,char *argv[],int num_opt,Option optarr[],
  239.                    int (*do_param)(char *param,int num))
  240. /****************************************************************************
  241. *
  242. * Function:        getargs
  243. * Parameters:    argc        - Number of arguments on command line
  244. *                argv        - Array of command line arguments
  245. *                num_opt        - Number of options in option array
  246. *                optarr        - Array to specify how to parse the command line
  247. *                do_param    - Routine to handle a command line parameter
  248. * Returns:        ALLDONE, INVALID or HELP
  249. *
  250. * Description:    Function to parse the command line according to a table of
  251. *                options. This routine calls getopt above to parse each
  252. *                individual option and attempts to parse each option into
  253. *                a variable of the specified type. The routine can parse
  254. *                integers and long integers in either decimal, octal,
  255. *                hexadecimal notation, unsigned integers and unsigned longs,
  256. *                strings and option switches. Option switches are simply
  257. *                boolean variables that get turned on if the switch was
  258. *                parsed.
  259. *
  260. *                Parameters are extracted from the command line by calling
  261. *                a user supplied routine do_param() to handle each parameter
  262. *                as it is encountered. The routine do_param() should accept
  263. *                a pointer to the parameter on the command line and an
  264. *                integer representing how many parameters have been
  265. *                encountered (ie: 1 if this is the first parameter, 10 if
  266. *                it is the 10th etc), and return ALLDONE upon successfully
  267. *                parsing it or INVALID if the parameter was invalid.
  268. *
  269. *                We return either ALLDONE if all the options were
  270. *                successfully parsed, INVALID if an invalid option was
  271. *                encountered or HELP if any of -h, -H or -? were present
  272. *                on the command line.
  273. *
  274. ****************************************************************************/
  275. {
  276.     int        i,opt;
  277.     char    *argument;
  278.     int        param_num = 1;
  279.     char    cmdstr[MAXARG*2 + 4];
  280.  
  281.     /* Build the command string from the array of options    */
  282.  
  283.     strcpy(cmdstr,"hH?");
  284.     for (i = 0,opt = 3; i < num_opt; i++,opt++) {
  285.         cmdstr[opt] = optarr[i].opt;
  286.         if (optarr[i].type != OPT_SWITCH) {
  287.             cmdstr[++opt] = ':';
  288.             }
  289.         }
  290.     cmdstr[opt] = '\0';
  291.  
  292.     while (true) {
  293.         opt = getopt(argc,argv,cmdstr,&argument);
  294.         switch (opt) {
  295.             case 'H':
  296.             case 'h':
  297.             case '?':
  298.                 return HELP;
  299.             case ALLDONE:
  300.                 return ALLDONE;
  301.             case INVALID:
  302.                 return INVALID;
  303.             case PARAMETER:
  304.                 if (do_param == NULL)
  305.                     return INVALID;
  306.                 if (do_param(argv[nextargv],param_num) == INVALID)
  307.                     return INVALID;
  308.                 nextargv++;
  309.                 param_num++;
  310.                 break;
  311.             default:
  312.  
  313.                 /* Search for the option in the option array. We are
  314.                  * guaranteed to find it.
  315.                  */
  316.  
  317.                 for (i = 0; i < num_opt; i++) {
  318.                     if (optarr[i].opt == opt)
  319.                         break;
  320.                     }
  321.                 if (optarr[i].type == OPT_SWITCH)
  322.                     *((bool*)optarr[i].arg) = true;
  323.                 else {
  324.                     if (parse_option(&optarr[i],argument) == INVALID)
  325.                         return INVALID;
  326.                     }
  327.                 break;
  328.             }
  329.         }
  330. }
  331.  
  332. PUBLIC void print_desc(int num_opt,Option optarr[])
  333. /****************************************************************************
  334. *
  335. * Function:        print_desc
  336. * Parameters:    num_opt    - Number of options in the table
  337. *                optarr    - Table of option descriptions
  338. *
  339. * Description:    Prints the description of each option in a standard format
  340. *                to the standard output device. The description for each
  341. *                option is obtained from the table of options.
  342. *
  343. ****************************************************************************/
  344. {
  345.     int        i;
  346.  
  347.     for (i = 0; i < num_opt; i++) {
  348.         if (optarr[i].type == OPT_SWITCH)
  349.             printf("  -%c       %s\n",optarr[i].opt,optarr[i].desc);
  350.         else
  351.             printf("  -%c<arg>  %s\n",optarr[i].opt,optarr[i].desc);
  352.         }
  353. }
  354.