home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / sound / players / mp02_tar.z / mp02_tar / mp02 / cmdline.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-29  |  10.2 KB  |  343 lines

  1. /* cmdline.c -- command line parsing routines */
  2. /*
  3.  * This module is designed to allow various modules to scan (and rescan)
  4.  * the command line for applicable arguments.  The goal is to hide as
  5.  * much information about switches and their names as possible so that
  6.  * switches become more consistent across applications and so that the
  7.  * author of an application need not do a lot of work to provide numerous
  8.  * options.  Instead, each module scans the command line for its own
  9.  * arguments.
  10.  *
  11.  * Command lines are of the following form:
  12.  *    command -s1 -s2 opt2 -s3 arg1 arg2 -s4 opt4 arg3
  13.  * Note that there are three kinds of command line parameters:
  14.  * (1) A Switch is a "-" followed by a name, e.g. "-s1"
  15.  * (2) An Option is a Switch followed by a space and name, e.g. "-s2 opt2"
  16.  * (3) An Argument is a name by itself, e.g. "arg1"
  17.  * Note also that a switch followed by an argument looks just like an
  18.  * option, so a list of valid option names is necessary to disambiguate.
  19.  *
  20.  * A main program that uses cmdline.c should do the following:
  21.  *    (1) create an array of pointers to strings (char *names[]) that
  22.  *        contains every possible option name
  23.  *    (2) create another array of pointers to strings that contains
  24.  *        every possible switch name
  25.  *    (2) call cl_init(switches, nsw, options, nopt, argv, argc)
  26.  * cl_init will report an error (to stderr) if it finds any illegal
  27.  * switch or option names.
  28.  *
  29.  * Afterward, switches, options, and arguments can be accessed by
  30.  * calling cl_switch, cl_option, and cl_arg.  If cl_switch or cl_option
  31.  * is called with a switch name that was not mentioned in the call to 
  32.  * cl_init, an error will result.  This indicates that the application
  33.  * author omitted a valid switch or option name when calling cl_init.
  34.  * This is an error because the full set of names is needed for error
  35.  * checking and to distinguish arguments from options.
  36.  *
  37.  * cl_nswitch and cl_noption are similar to cl_switch and cl_option,
  38.  * except they each take a list of equivalent switch or option names.  
  39.  * This makes it simple to allow both verbose (-debug) and terse (-d) names.
  40.  */
  41.  
  42. /*****************************************************************************
  43. *        Change Log
  44. *  Date        | Change
  45. *-----------+-----------------------------------------------------------------
  46. * 13-Jun-86 | Created Change Log
  47. *  6-Aug-86 | Modified for Lattice 3.0 -- use "void" to type some routines
  48. *****************************************************************************/
  49.  
  50. #include "cext.h"
  51. #include "stdio.h"
  52. #include "cmdline.h"
  53.  
  54. private char **voptions;    /* valid options */
  55. private int noptions;        /* number of options */
  56. private char **vswitches;    /* valid switches */
  57. private int nswitches;        /* number of switches */
  58. private char **argv;        /* command line argument vector */
  59. private int argc;        /* length of argv */
  60.  
  61. private int cl_rdy = false;    /* set to true when initialized */
  62.  
  63. /*****************************************************************************
  64. *    Routines local to this module
  65. *****************************************************************************/
  66. private    void    check_names();
  67. private int    find_match();
  68. private int    find_string();
  69. private    void    ready_check();
  70.  
  71. /****************************************************************
  72. *            check_names
  73. * Inputs:
  74. *    char *names[]:    array of alternative switch or option names
  75. *    int nnames:    number of alternative switch or option names
  76. *    char *valid[]:    array of valid names
  77. *    int nvalid:    number of valid names
  78. * Effect:
  79. *    Checks that all names are in validnames.  If not, print
  80. *    an error message.
  81. *****************************************************************/
  82.  
  83. private void check_names(names, nnames, valid, nvalid)
  84.     char *names[];
  85.     int nnames;
  86.     char *valid[];
  87.     int nvalid;
  88. {
  89.     int i;    /* loop counters */
  90.     for (i = 0; i < nnames; i++) {
  91.     if (find_string(names[i], valid, nvalid) >= nvalid) {
  92.         fprintf(stderr, "internal error detected by cmdline module:\n");
  93.         fprintf(stderr, "\t'%s' should be in valid lists\n", names[i]);
  94.     }
  95.     }
  96. }
  97.  
  98. /****************************************************************
  99. *            cl_arg
  100. * Inputs:
  101. *    n: the index of the arg needed
  102. * Results:
  103. *    pointer to the nth arg, or NULL if none exists
  104. *    arg 0 is the command name
  105. *****************************************************************/
  106.  
  107. char *cl_arg(n)
  108.     int n;
  109. {
  110.     int i = 1;
  111.     if (n <= 0) return argv[0];
  112.     while (i < argc) {
  113.     if (*argv[i] == '-') {
  114.         if (find_string(argv[i], voptions, noptions) < noptions)
  115.         i += 2; /* skip name and option */
  116.         else i += 1; /* skip over switch name */
  117.     } else if (n == 1) {
  118.         return argv[i];
  119.     } else { /* skip over argument */
  120.         n--;
  121.         i++;
  122.     }
  123.     }
  124.     return NULL;
  125. }
  126.  
  127. /*****************************************************************************
  128. *            cl_init
  129. * Inputs:
  130. *    char *switches[]:    array of switch names
  131. *    int nsw:        number of switch names
  132. *    char *options[]:    array of option names
  133. *    int nopt:        number of option names
  134. *    char *av:        array of command line fields (argv)
  135. *    int ac:            number of command line fields (argc)
  136. * Effect:
  137. *    Checks that all command line entries are valid.
  138. *    Saves info for use by other routines.
  139. * Returns:
  140. *    True if syntax checks OK, otherwise false
  141. *****************************************************************************/
  142.  
  143. boolean cl_init(switches, nsw, options, nopt, av, ac)
  144.     char *switches[];
  145.     int nsw;
  146.     char *options[];
  147.     int nopt;
  148.     char *av[];
  149.     int ac;
  150. {
  151.     int i;    /* index into argv */
  152.     boolean result = true;
  153.  
  154.     vswitches = switches;    nswitches = nsw;
  155.     voptions = options;        noptions = nopt;
  156.     argv = av;            argc = ac;
  157.  
  158. #ifndef UNIX
  159.     for (i = 1; i < argc; i++) {  /* case fold lower */
  160.     int j;
  161.     for (j = 0; j < strlen(argv[i]); j++)
  162.         argv[i][j] = tolower(argv[i][j]);
  163.     }
  164. #endif
  165.     /* check command line syntax: */
  166.     i = 1;
  167.     while (i < argc) {
  168.     if (*argv[i] == '-') {
  169.         if (find_string(argv[i], voptions, noptions) < noptions) {
  170.         i += 1; /* skip name and option */
  171.         if (i < argc && *argv[i] == '-') {
  172.             fprintf(stderr, "missing argument after %s\n", argv[i-1]);
  173.             result = false;
  174.             i += 1;
  175.         }
  176.         } else if (find_string(argv[i], vswitches, nswitches) < 
  177.                nswitches) {
  178.         i += 1; /* skip over switch name */
  179.         } else {
  180.         fprintf(stderr, "invalid switch: %s\n", argv[i]);
  181.         i += 1;
  182.         result = false;
  183.         }
  184.     } else i++; /* skip over argument */
  185.     }
  186.     cl_rdy = true;
  187.     return result;
  188. }
  189.  
  190. /****************************************************************
  191. *            cl_noption
  192. * Inputs:
  193. *    char *names[]:    array of alternative switch names
  194. *    int nnames:    number of alternative switch names
  195. * Result:
  196. *    returns pointer to  if one exists, otherwise null
  197. * Effect:
  198. *    looks for pattern in command line of the form "-n s",
  199. *    where n is a member of names.  Returns pointer to s.
  200. * Implementation:
  201. *    find the option name, then
  202. *    see if the switch is followed by a string that does
  203. *    not start with "-"
  204. *****************************************************************/
  205.  
  206. char *cl_noption(names, nnames)
  207.     char *names[];
  208.     int nnames;
  209. {
  210.     int i;    /* index of switch */
  211.  
  212.     ready_check();
  213.     check_names(names, nnames, voptions, noptions);
  214.     i = find_match(names, nnames) + 1; /* point at the option */
  215.     if (i < argc) { /* make sure option exists */
  216.     if (*(argv[i]) != '-') return argv[i];
  217.     }
  218.     return NULL;
  219. }
  220.  
  221. /*****************************************************************
  222. *            cl_nswitch
  223. * Inputs:
  224. *    char *names[]:    array of alternative switch names
  225. *    int nnames:    number of alternative switch names
  226. * Effect:
  227. *    Checks that names is valid.
  228. *    Finds a pattern in command line of the form "-n", where
  229. *    n is a member of names.
  230. * Result:
  231. *    returns pointer to command line switch if one exists,
  232. *    otherwise null
  233. *****************************************************************/
  234.  
  235. char *cl_nswitch(names, nnames)
  236.     char *names[];
  237.     int nnames;
  238. {
  239.     int i;    /* index of switch */
  240.  
  241.     ready_check();
  242.     check_names(names, nnames, vswitches, nswitches);
  243.     i = find_match(names, nnames);
  244.     if (i < argc) return argv[i];
  245.     /* else */ return NULL;
  246. }
  247.  
  248. /****************************************************************
  249. *            cl_option
  250. * Inputs:
  251. *    char *name:    option name
  252. * Outputs:
  253. *    returns char *: the option string if found, otherwise null
  254. ****************************************************************/
  255.  
  256. char *cl_option(name)
  257.     char *name;
  258. {
  259.     char *names[1];    /* array to hold name */
  260.  
  261.     names[0] = name;
  262.     return cl_noption(names, 1);
  263. }
  264.  
  265. /****************************************************************
  266. *            cl_switch
  267. * Inputs:
  268. *    char *name:    switch name
  269. * Outputs:
  270. *    boolean:    true if switch found
  271. ****************************************************************/
  272.  
  273. boolean cl_switch(name)
  274.     char *name;
  275. {
  276.     char *names[1];    /* array to hold name */
  277.  
  278.     names[0] = name;
  279.     return cl_nswitch(names, 1) != NULL;
  280. }
  281.  
  282. /****************************************************************
  283. *            find_match
  284. * Inputs:
  285. *    char *names[]:    array of alternative switch or option names
  286. *    int nnames:    number of alternative switch or option names
  287. * Effect:
  288. *    Looks for command line switch that matches one of names.
  289. * Returns:
  290. *    Index of switch if found, argc if not found.
  291. *****************************************************************/
  292.  
  293. private int find_match(names, nnames)
  294.     char *names[];
  295.     int nnames;
  296. {
  297.     int j;    /* loop counter */
  298.     for (j = 0; j < argc; j++) {
  299.     if (find_string(argv[j], names, nnames) < nnames) return j;
  300.     }
  301.     return argc;
  302. }
  303.  
  304. /****************************************************************
  305. *            find_string
  306. * Inputs:
  307. *    char *s:    string to find
  308. *    char *names[]:    array of strings
  309. *    int nnames:    number of strings
  310. * Effect:
  311. *    Looks for s in names
  312. * Returns:
  313. *    Index of s in names if found, nnames if not found
  314. *****************************************************************/
  315.  
  316. private int find_string(s, names, nnames)
  317.     char *s;
  318.     char *names[];
  319.     int nnames;
  320. {
  321.     int i; /* loop counter */
  322.     for (i = 0; i < nnames; i++) {
  323.     if (strcmp(s, names[i]) == 0) {
  324.         return i;
  325.     }
  326.     }
  327.     return nnames;
  328. }
  329.  
  330. /****************************************************************
  331. *            ready_check
  332. * Effect:
  333. *    Halt program if cl_rdy is not true.
  334. *****************************************************************/
  335. private void ready_check()
  336. {
  337.     if (!cl_rdy) {
  338.     fprintf(stderr,
  339.         "Internal error: cl_init was not called, see cmdline.c\n");
  340.     exit(1);
  341.     }
  342. }
  343.