📄 cmdline.c
字号:
/* cmdline.c -- command line parsing routines *//* * This module is designed to allow various modules to scan (and rescan) * the command line for applicable arguments. The goal is to hide as * much information about switches and their names as possible so that * switches become more consistent across applications and so that the * author of an application need not do a lot of work to provide numerous * options. Instead, each module scans the command line for its own * arguments. * * Command lines are of the following form: * command -s1 -s2 opt2 -s3 arg1 arg2 -s4 opt4 arg3 * command @filename * The @filename form reads commands of the first form from filename * Note that there are three kinds of command line parameters: * (1) A Switch is a "-" followed by a name, e.g. "-s1" * (2) An Option is a Switch followed by a space and name, e.g. "-s2 opt2" * (3) An Argument is a name by itself, e.g. "arg1" * Note also that a switch followed by an argument looks just like an * option, so a list of valid option names is necessary to disambiguate. * * A main program that uses cmdline.c should do the following: * (1) create an array of pointers to strings (char *names[]) that * contains every possible option name * (2) create another array of pointers to strings that contains * every possible switch name * (2) call cl_init(switches, nsw, options, nopt, argv, argc) * cl_init will report an error (to stderr) if it finds any illegal * switch or option names. * * Afterward, switches, options, and arguments can be accessed by * calling cl_switch, cl_option, and cl_arg. If cl_switch or cl_option * is called with a switch name that was not mentioned in the call to * cl_init, an error will result. This indicates that the application * author omitted a valid switch or option name when calling cl_init. * This is an error because the full set of names is needed for error * checking and to distinguish arguments from options. * * cl_nswitch and cl_noption are similar to cl_switch and cl_option, * except they each take a list of equivalent switch or option names. * This makes it simple to allow both verbose (-debug) and terse (-d) names. *//****************************************************************************** Change Log* Date | Change*-----------+-----------------------------------------------------------------* 13-Jun-86 | Created Change Log* 6-Aug-86 | Modified for Lattice 3.0 -- use "void" to type some routines* 27-Dec-93 | "@file" as first arg reads command line args from file*****************************************************************************/#include "stdlib.h"#include "cext.h"#include "stdio.h"#include "ctype.h"#include "cmdline.h"#include "string.h"private char **voptions; /* valid options */private int noptions; /* number of options */private char **vswitches; /* valid switches */private int nswitches; /* number of switches */private char **argv; /* command line argument vector */private int argc; /* length of argv */private int cl_rdy = false; /* set to true when initialized *//****************************************************************************** Routines local to this module*****************************************************************************/private void check_names();private int find_match();private int find_string();private void ready_check();void indirect_command(char *filename, char ***argvp, int *argcp, char *oldarg0);/***************************************************************** check_names* Inputs:* char *names[]: array of alternative switch or option names* int nnames: number of alternative switch or option names* char *valid[]: array of valid names* int nvalid: number of valid names* Effect:* Checks that all names are in validnames. If not, print* an error message.*****************************************************************/private void check_names(names, nnames, valid, nvalid) char *names[]; int nnames; char *valid[]; int nvalid;{ int i; /* loop counters */ for (i = 0; i < nnames; i++) { if (find_string(names[i], valid, nvalid) >= nvalid) { fprintf(stderr, "internal error detected by cmdline module:\n"); fprintf(stderr, "\t'%s' should be in valid lists\n", names[i]); } }}/***************************************************************** cl_arg* Inputs:* n: the index of the arg needed* Results:* pointer to the nth arg, or NULL if none exists* arg 0 is the command name*****************************************************************/char *cl_arg(n) int n;{ int i = 1; if (n <= 0) return argv[0]; while (i < argc) { if (*argv[i] == '-') { if (find_string(argv[i], voptions, noptions) < noptions) i += 2; /* skip name and option */ else i += 1; /* skip over switch name */ } else if (n == 1) { return argv[i]; } else { /* skip over argument */ n--; i++; } } return NULL;}/****************************************************************************** cl_init* Inputs:* char *switches[]: array of switch names* int nsw: number of switch names* char *options[]: array of option names* int nopt: number of option names* char *av: array of command line fields (argv)* int ac: number of command line fields (argc)* Effect:* Checks that all command line entries are valid.* Saves info for use by other routines.* Returns:* True if syntax checks OK, otherwise false*****************************************************************************/boolean cl_init(switches, nsw, options, nopt, av, ac) char *switches[]; int nsw; char *options[]; int nopt; char *av[]; int ac;{ int i; /* index into argv */ boolean result = true; vswitches = switches; nswitches = nsw; voptions = options; noptions = nopt; argv = av; argc = ac; if (ac == 2 && *(av[1]) == '@') { /* read new args from file */ indirect_command(av[1] + 1, &argv, &argc, av[0]); } for (i = 1; i < argc; i++) { /* case fold lower */ size_t j; for (j = 0; j < strlen(argv[i]); j++) if (isupper(argv[i][j])) argv[i][j] = tolower(argv[i][j]); } /* check command line syntax: */ i = 1; while (i < argc) { if (*argv[i] == '-') { if (find_string(argv[i], voptions, noptions) < noptions) { i += 1; /* skip name and option */ if (i < argc && *argv[i] == '-') { fprintf(stderr, "missing argument after %s\n", argv[i-1]); result = false; i += 1; } } else if (find_string(argv[i], vswitches, nswitches) < nswitches) { i += 1; /* skip over switch name */ } else { fprintf(stderr, "invalid switch: %s\n", argv[i]); i += 1; result = false; } } else i++; /* skip over argument */ } cl_rdy = true; return result;}/***************************************************************** cl_noption* Inputs:* char *names[]: array of alternative switch names* int nnames: number of alternative switch names* Result:* returns pointer to if one exists, otherwise null* Effect:* looks for pattern in command line of the form "-n s",* where n is a member of names. Returns pointer to s.* Implementation:* find the option name, then* see if the switch is followed by a string that does* not start with "-"*****************************************************************/char *cl_noption(names, nnames) char *names[]; int nnames;{ int i; /* index of switch */ ready_check(); check_names(names, nnames, voptions, noptions); i = find_match(names, nnames) + 1; /* point at the option */ if (i < argc) { /* make sure option exists */ if (*(argv[i]) != '-') return argv[i]; } return NULL;}/****************************************************************** cl_nswitch* Inputs:* char *names[]: array of alternative switch names* int nnames: number of alternative switch names* Effect:* Checks that names is valid.* Finds a pattern in command line of the form "-n", where* n is a member of names.* Result:* returns pointer to command line switch if one exists,* otherwise null*****************************************************************/char *cl_nswitch(names, nnames) char *names[]; int nnames;{ int i; /* index of switch */ ready_check(); check_names(names, nnames, vswitches, nswitches); i = find_match(names, nnames); if (i < argc) return argv[i]; /* else */ return NULL;}/***************************************************************** cl_option* Inputs:* char *name: option name* Outputs:* returns char *: the option string if found, otherwise null****************************************************************/char *cl_option(name) char *name;{ char *names[1]; /* array to hold name */ names[0] = name; return cl_noption(names, 1);}/***************************************************************** cl_switch* Inputs:* char *name: switch name* Outputs:* boolean: true if switch found****************************************************************/boolean cl_switch(name) char *name;{ char *names[1]; /* array to hold name */ names[0] = name; return cl_nswitch(names, 1) != NULL;}/***************************************************************** find_match* Inputs:* char *names[]: array of alternative switch or option names* int nnames: number of alternative switch or option names* Effect:* Looks for command line switch that matches one of names.* Returns:* Index of switch if found, argc if not found.*****************************************************************/private int find_match(names, nnames) char *names[]; int nnames;{ int j; /* loop counter */ for (j = 0; j < argc; j++) { if (find_string(argv[j], names, nnames) < nnames) return j; } return argc;}/***************************************************************** find_string* Inputs:* char *s: string to find* char *names[]: array of strings* int nnames: number of strings* Effect:* Looks for s in names* Returns:* Index of s in names if found, nnames if not found*****************************************************************/private int find_string(s, names, nnames) char *s; char *names[]; int nnames;{ int i; /* loop counter */ for (i = 0; i < nnames; i++) { if (strcmp(s, names[i]) == 0) { return i; } } return nnames;}boolean is_whitespace(int c){ return c == ' ' || c == '\t' || c == '\n' || c == '\r';}boolean get_arg(file, arg) FILE *file; char *arg;{ int c; while ((c = getc(file)) != EOF && is_whitespace(c)) ; if (c == EOF) return false; ungetc(c, file); while ((c = getc(file)) != EOF && !is_whitespace(c)) { *arg++ = c; } *arg = 0; return true;}void indirect_command(filename, argvp, argcp, oldarg0) char *filename; char ***argvp; int *argcp; char *oldarg0;{ FILE *argfile = fopen(filename, "r"); if (!argfile) { *argvp = (char **) malloc(sizeof(char *)); (*argvp)[0] = oldarg0; *argcp = 1; } else { int i = 1; char arg[100]; while (get_arg(argfile, arg)) i++; fclose(argfile); argfile = fopen(filename, "r"); *argvp = (char **) malloc(sizeof(char *) * i); (*argvp)[0] = oldarg0; *argcp = i; i = 1; while (get_arg(argfile, arg)) { (*argvp)[i] = (char *) malloc(strlen(arg) + 1); strcpy((*argvp)[i], arg); i++; } }}/***************************************************************** ready_check* Effect:* Halt program if cl_rdy is not true.*****************************************************************/private void ready_check(){ if (!cl_rdy) { fprintf(stderr, "Internal error: cl_init was not called, see cmdline.c\n"); exit(1); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -