Annotation of researchv10no/cmd/f2c/parse_args.c, revision 1.1.1.1

1.1       root        1: /****************************************************************
                      2: Copyright 1990 by AT&T Bell Laboratories and Bellcore.
                      3: 
                      4: Permission to use, copy, modify, and distribute this software
                      5: and its documentation for any purpose and without fee is hereby
                      6: granted, provided that the above copyright notice appear in all
                      7: copies and that both that the copyright notice and this
                      8: permission notice and warranty disclaimer appear in supporting
                      9: documentation, and that the names of AT&T Bell Laboratories or
                     10: Bellcore or any of their entities not be used in advertising or
                     11: publicity pertaining to distribution of the software without
                     12: specific, written prior permission.
                     13: 
                     14: AT&T and Bellcore disclaim all warranties with regard to this
                     15: software, including all implied warranties of merchantability
                     16: and fitness.  In no event shall AT&T or Bellcore be liable for
                     17: any special, indirect or consequential damages or any damages
                     18: whatsoever resulting from loss of use, data or profits, whether
                     19: in an action of contract, negligence or other tortious action,
                     20: arising out of or in connection with the use or performance of
                     21: this software.
                     22: ****************************************************************/
                     23: 
                     24: /* parse_args
                     25: 
                     26:        This function will parse command line input into appropriate data
                     27:    structures, output error messages when appropriate and provide some
                     28:    minimal type conversion.
                     29: 
                     30:        Input to the function consists of the standard   argc,argv
                     31:    values, and a table which directs the parser.  Each table entry has the
                     32:    following components:
                     33: 
                     34:        prefix -- the (optional) switch character string, e.g. "-" "/" "="
                     35:        switch -- the command string, e.g. "o" "data" "file" "F"
                     36:        flags -- control flags, e.g.   CASE_INSENSITIVE, REQUIRED_PREFIX
                     37:        arg_count -- number of arguments this command requires, e.g. 0 for
                     38:                     booleans, 1 for filenames, INFINITY for input files
                     39:        result_type -- how to interpret the switch arguments, e.g. STRING,
                     40:                       CHAR, FILE, OLD_FILE, NEW_FILE
                     41:        result_ptr -- pointer to storage for the result, be it a table or
                     42:                      a string or whatever
                     43:        table_size -- if the arguments fill a table, the maximum number of
                     44:                      entries; if there are no arguments, the value to
                     45:                      load into the result storage
                     46: 
                     47:        Although the table can be used to hold a list of filenames, only
                     48:    scalar values (e.g. pointers) can be stored in the table.  No vector
                     49:    processing will be done, only pointers to string storage will be moved.
                     50: 
                     51:        An example entry, which could be used to parse input filenames, is:
                     52: 
                     53:        "-", "o", 0, oo, OLD_FILE, infilenames, INFILE_TABLE_SIZE
                     54: 
                     55: */
                     56: 
                     57: #include <stdio.h>
                     58: #ifndef NULL
                     59: /* ANSI C */
                     60: #include <stddef.h>
                     61: #endif
                     62: #include "parse.h"
                     63: #include <math.h>           /* For atof */
                     64: #include <ctype.h>
                     65: 
                     66: #define MAX_INPUT_SIZE 1000
                     67: 
                     68: #define arg_prefix(x) ((x).prefix)
                     69: #define arg_string(x) ((x).string)
                     70: #define arg_flags(x) ((x).flags)
                     71: #define arg_count(x) ((x).count)
                     72: #define arg_result_type(x) ((x).result_type)
                     73: #define arg_result_ptr(x) ((x).result_ptr)
                     74: #define arg_table_size(x) ((x).table_size)
                     75: 
                     76: #ifndef TRUE
                     77: #define TRUE 1
                     78: #endif
                     79: #ifndef FALSE
                     80: #define FALSE 0
                     81: #endif
                     82: typedef int boolean;
                     83: 
                     84: 
                     85: char *lower_string (/* char [], char * */);
                     86: 
                     87: static char *this_program = "";
                     88: 
                     89: extern long atol();
                     90: static int arg_parse (/* char *, arg_info * */);
                     91: 
                     92: 
                     93: boolean parse_args (argc, argv, table, entries, others, other_count)
                     94: int argc;
                     95: char *argv[];
                     96: arg_info table[];
                     97: int entries;
                     98: char *others[];
                     99: int other_count;
                    100: {
                    101:     boolean arg_verify (/* argv, table, entries */);
                    102:     void init_store (/* table, entries */);
                    103: 
                    104:     boolean result;
                    105: 
                    106:     if (argv)
                    107:        this_program = argv[0];
                    108: 
                    109: /* Check the validity of the table and its parameters */
                    110: 
                    111:     result = arg_verify (argv, table, entries);
                    112: 
                    113: /* Initialize the storage values */
                    114: 
                    115:     init_store (table, entries);
                    116: 
                    117:     if (result) {
                    118:        boolean use_prefix = TRUE;
                    119:        char *argv0;
                    120: 
                    121:        argc--;
                    122:        argv0 = *++argv;
                    123:        while (argc) {
                    124:            int index, length;
                    125: 
                    126:            index = match_table (*argv, table, entries, use_prefix, &length);
                    127:            if (index < 0) {
                    128: 
                    129: /* The argument doesn't match anything in the table */
                    130: 
                    131:                if (others) {
                    132: 
                    133:                    if (*argv > argv0)
                    134:                        *--*argv = '-'; /* complain at invalid flag */
                    135: 
                    136:                    if (other_count > 0) {
                    137:                        *others++ = *argv;
                    138:                        other_count--;
                    139:                    } else {
                    140:                        fprintf (stderr, "%s:  too many parameters: ",
                    141:                                this_program);
                    142:                        fprintf (stderr, "'%s' ignored\n", *argv);
                    143:                    } /* else */
                    144:                } /* if (others) */
                    145:                argv0 = *++argv;
                    146:                argc--;
                    147:            } else {
                    148: 
                    149: /* A match was found */
                    150: 
                    151:                if (length >= strlen (*argv)) {
                    152:                    argc--;
                    153:                    argv0 = *++argv;
                    154:                    use_prefix = TRUE;
                    155:                } else {
                    156:                    (*argv) += length;
                    157:                    use_prefix = FALSE;
                    158:                } /* else */
                    159: 
                    160: /* Parse any necessary arguments */
                    161: 
                    162:                if (arg_count (table[index]) != P_NO_ARGS) {
                    163: 
                    164: /* Now   length   will be used to store the number of parsed characters */
                    165: 
                    166:                    length = arg_parse(*argv, &table[index]);
                    167:                    if (*argv == NULL)
                    168:                        argc = 0;
                    169:                    else if (length >= strlen (*argv)) {
                    170:                        argc--;
                    171:                        argv0 = *++argv;
                    172:                        use_prefix = TRUE;
                    173:                    } else {
                    174:                        (*argv) += length;
                    175:                        use_prefix = FALSE;
                    176:                    } /* else */
                    177:                } /* if (argv_count != P_NO_ARGS) */
                    178:                  else
                    179:                    *arg_result_ptr(table[index]) =
                    180:                            arg_table_size(table[index]);
                    181:            } /* else */
                    182:        } /* while (argc) */
                    183:     } /* if (result) */
                    184: 
                    185:     return result;
                    186: } /* parse_args */
                    187: 
                    188: 
                    189: boolean arg_verify (argv, table, entries)
                    190: char *argv[];
                    191: arg_info table[];
                    192: int entries;
                    193: {
                    194:     int i;
                    195:     char *this_program = "";
                    196: 
                    197:     if (argv)
                    198:        this_program = argv[0];
                    199: 
                    200:     for (i = 0; i < entries; i++) {
                    201:        arg_info *arg = &table[i];
                    202: 
                    203: /* Check the argument flags */
                    204: 
                    205:        if (arg_flags (*arg) & ~(P_CASE_INSENSITIVE | P_REQUIRED_PREFIX)) {
                    206:            fprintf (stderr, "%s [arg_verify]:  too many ", this_program);
                    207:            fprintf (stderr, "flags in entry %d:  '%x' (hex)\n", i,
                    208:                    arg_flags (*arg));
                    209:        } /* if */
                    210: 
                    211: /* Check the argument count */
                    212: 
                    213:        { int count = arg_count (*arg);
                    214: 
                    215:            if (count != P_NO_ARGS && count != P_ONE_ARG && count !=
                    216:                    P_INFINITE_ARGS) {
                    217:                fprintf (stderr, "%s [arg_verify]:  invalid ", this_program);
                    218:                fprintf (stderr, "argument count in entry %d:  '%d'\n", i,
                    219:                        count);
                    220:            } /* if count != P_NO_ARGS ... */
                    221: 
                    222: /* Check the result field; want to be able to store results */
                    223: 
                    224:              else
                    225:                if (arg_result_ptr (*arg) == (int *) NULL) {
                    226:                    fprintf (stderr, "%s [arg_verify]:  ", this_program);
                    227:                    fprintf (stderr, "no argument storage given for ");
                    228:                    fprintf (stderr, "entry %d\n", i);
                    229:                } /* if arg_result_ptr */
                    230:        }
                    231: 
                    232: /* Check the argument type */
                    233: 
                    234:        { int type = arg_result_type (*arg);
                    235: 
                    236:            if (type < P_STRING || type > P_DOUBLE)
                    237:                    fprintf(stderr,
                    238:                        "%s [arg_verify]:  bad arg type in entry %d:  '%d'\n",
                    239:                        this_program, i, type);
                    240:        }
                    241: 
                    242: /* Check table size */
                    243: 
                    244:        { int size = arg_table_size (*arg);
                    245: 
                    246:            if (arg_count (*arg) == P_INFINITE_ARGS && size < 1) {
                    247:                fprintf (stderr, "%s [arg_verify]:  bad ", this_program);
                    248:                fprintf (stderr, "table size in entry %d:  '%d'\n", i,
                    249:                        size);
                    250:            } /* if (arg_count == P_INFINITE_ARGS && size < 1) */
                    251:        }
                    252: 
                    253:     } /* for i = 0 */
                    254: 
                    255:     return TRUE;
                    256: } /* arg_verify */
                    257: 
                    258: 
                    259: /* match_table -- returns the index of the best entry matching the input,
                    260:    -1 if no match.  The best match is the one of longest length which
                    261:    appears lowest in the table.  The length of the match will be returned
                    262:    in   length   ONLY IF a match was found.   */
                    263: 
                    264: int match_table (norm_input, table, entries, use_prefix, length)
                    265: register char *norm_input;
                    266: arg_info table[];
                    267: int entries;
                    268: boolean use_prefix;
                    269: int *length;
                    270: {
                    271:     extern int match (/* char *, char *, arg_info *, boolean */);
                    272: 
                    273:     char low_input[MAX_INPUT_SIZE];
                    274:     register int i;
                    275:     int best_index = -1, best_length = 0;
                    276: 
                    277: /* FUNCTION BODY */
                    278: 
                    279:     (void) lower_string (low_input, norm_input);
                    280: 
                    281:     for (i = 0; i < entries; i++) {
                    282:        int this_length = match (norm_input, low_input, &table[i], use_prefix);
                    283: 
                    284:        if (this_length > best_length) {
                    285:            best_index = i;
                    286:            best_length = this_length;
                    287:        } /* if (this_length > best_length) */
                    288:     } /* for (i = 0) */
                    289: 
                    290:     if (best_index > -1 && length != (int *) NULL)
                    291:        *length = best_length;
                    292: 
                    293:     return best_index;
                    294: } /* match_table */
                    295: 
                    296: 
                    297: /* match -- takes an input string and table entry, and returns the length
                    298:    of the longer match.
                    299: 
                    300:        0 ==> input doesn't match
                    301: 
                    302:    For example:
                    303: 
                    304:        INPUT   PREFIX  STRING  RESULT
                    305: ----------------------------------------------------------------------
                    306:        "abcd"  "-"     "d"     0
                    307:        "-d"    "-"     "d"     2    (i.e. "-d")
                    308:        "dout"  "-"     "d"     1    (i.e. "d")
                    309:        "-d"    ""      "-d"    2    (i.e. "-d")
                    310:        "dd"    "d"     "d"     2       <= here's the weird one
                    311: */
                    312: 
                    313: int match (norm_input, low_input, entry, use_prefix)
                    314: char *norm_input, *low_input;
                    315: arg_info *entry;
                    316: boolean use_prefix;
                    317: {
                    318:     char *norm_prefix = arg_prefix (*entry);
                    319:     char *norm_string = arg_string (*entry);
                    320:     boolean prefix_match = FALSE, string_match = FALSE;
                    321:     int result = 0;
                    322: 
                    323: /* Buffers for the lowercased versions of the strings being compared.
                    324:    These are used when the switch is to be case insensitive */
                    325: 
                    326:     static char low_prefix[MAX_INPUT_SIZE];
                    327:     static char low_string[MAX_INPUT_SIZE];
                    328:     int prefix_length = strlen (norm_prefix);
                    329:     int string_length = strlen (norm_string);
                    330: 
                    331: /* Pointers for the required strings (lowered or nonlowered) */
                    332: 
                    333:     register char *input, *prefix, *string;
                    334: 
                    335: /* FUNCTION BODY */
                    336: 
                    337: /* Use the appropriate strings to handle case sensitivity */
                    338: 
                    339:     if (arg_flags (*entry) & P_CASE_INSENSITIVE) {
                    340:        input = low_input;
                    341:        prefix = lower_string (low_prefix, norm_prefix);
                    342:        string = lower_string (low_string, norm_string);
                    343:     } else {
                    344:        input = norm_input;
                    345:        prefix = norm_prefix;
                    346:        string = norm_string;
                    347:     } /* else */
                    348: 
                    349: /* First, check the string formed by concatenating the prefix onto the
                    350:    switch string, but only when the prefix is not being ignored */
                    351: 
                    352:     if (use_prefix && prefix != NULL && *prefix != '\0')
                    353:         prefix_match = (strncmp (input, prefix, prefix_length) == 0) &&
                    354:                (strncmp (input + prefix_length, string, string_length) == 0);
                    355: 
                    356: /* Next, check just the switch string, if that's allowed */
                    357: 
                    358:     if (!use_prefix && (arg_flags (*entry) & P_REQUIRED_PREFIX) == 0)
                    359:        string_match = strncmp (input, string, string_length) == 0;
                    360: 
                    361:     if (prefix_match)
                    362:        result = prefix_length + string_length;
                    363:     else if (string_match)
                    364:        result = string_length;
                    365: 
                    366:     return result;
                    367: } /* match */
                    368: 
                    369: 
                    370: char *lower_string (dest, src)
                    371: char *dest, *src;
                    372: {
                    373:     char *result = dest;
                    374:     register int c;
                    375: 
                    376:     if (dest == NULL || src == NULL)
                    377:        result = NULL;
                    378:     else
                    379:        while (*dest++ = (c = *src++) >= 'A' && c <= 'Z' ? tolower(c) : c);
                    380: 
                    381:     return result;
                    382: } /* lower_string */
                    383: 
                    384: 
                    385: /* arg_parse -- returns the number of characters parsed for this entry */
                    386: 
                    387: static int arg_parse (str, entry)
                    388: char *str;
                    389: arg_info *entry;
                    390: {
                    391:     int length = 0;
                    392: 
                    393:     if (arg_count (*entry) == P_ONE_ARG) {
                    394:        char **store = (char **) arg_result_ptr (*entry);
                    395: 
                    396:        length = put_one_arg (arg_result_type (*entry), str, store,
                    397:                arg_prefix (*entry), arg_string (*entry));
                    398: 
                    399:     } /* if (arg_count == P_ONE_ARG) */
                    400:       else { /* Must be a table of arguments */
                    401:        char **store = (char **) arg_result_ptr (*entry);
                    402: 
                    403:        if (store) {
                    404:            while (*store)
                    405:                store++;
                    406: 
                    407:            length = put_one_arg (arg_result_type (*entry), str, store++,
                    408:                    arg_prefix (*entry), arg_string (*entry));
                    409: 
                    410:            *store = (char *) NULL;
                    411:        } /* if (store) */
                    412:     } /* else */
                    413: 
                    414:     return length;
                    415: } /* arg_parse */
                    416: 
                    417: 
                    418: int put_one_arg (type, str, store, prefix, string)
                    419: int type;
                    420: char *str;
                    421: char **store;
                    422: char *prefix, *string;
                    423: {
                    424:     int length = 0;
                    425:     long L;
                    426: 
                    427:     if (store) {
                    428:        switch (type) {
                    429:            case P_STRING:
                    430:            case P_FILE:
                    431:            case P_OLD_FILE:
                    432:            case P_NEW_FILE:
                    433:                *store = str;
                    434:                if (str == NULL)
                    435:                    fprintf (stderr, "%s: Missing argument after '%s%s'\n",
                    436:                            this_program, prefix, string);
                    437:                length = str ? strlen (str) : 0;
                    438:                break;
                    439:            case P_CHAR:
                    440:                *((char *) store) = *str;
                    441:                length = 1;
                    442:                break;
                    443:            case P_SHORT:
                    444:                L = atol(str);
                    445:                *(short *)store = (short) L;
                    446:                if (L != *(short *)store)
                    447:                    fprintf(stderr,
                    448:        "%s%s parameter '%ld' is not a SHORT INT (truncating to %d)\n",
                    449:                            prefix, string, L, *(short *)store);
                    450:                length = strlen (str);
                    451:                break;
                    452:            case P_INT:
                    453:                L = atol(str);
                    454:                *(int *)store = (int)L;
                    455:                if (L != *(int *)store)
                    456:                    fprintf(stderr,
                    457:        "%s%s parameter '%ld' is not an INT (truncating to %d)\n",
                    458:                            prefix, string, L, *(int *)store);
                    459:                length = strlen (str);
                    460:                break;
                    461:            case P_LONG:
                    462:                *(long *)store = atol(str);
                    463:                length = strlen (str);
                    464:                break;
                    465:            case P_FLOAT:
                    466:                *((float *) store) = (float) atof (str);
                    467:                length = strlen (str);
                    468:                break;
                    469:            case P_DOUBLE:
                    470:                *((double *) store) = (double) atof (str);
                    471:                length = strlen (str);
                    472:                break;
                    473:            default:
                    474:                fprintf (stderr, "put_one_arg:  bad type '%d'\n",
                    475:                        type);
                    476:                break;
                    477:        } /* switch */
                    478:     } /* if (store) */
                    479: 
                    480:     return length;
                    481: } /* put_one_arg */
                    482: 
                    483: 
                    484: void init_store (table, entries)
                    485: arg_info *table;
                    486: int entries;
                    487: {
                    488:     int index;
                    489: 
                    490:     for (index = 0; index < entries; index++)
                    491:        if (arg_count (table[index]) == P_INFINITE_ARGS) {
                    492:            char **place = (char **) arg_result_ptr (table[index]);
                    493: 
                    494:            if (place)
                    495:                *place = (char *) NULL;
                    496:        } /* if arg_count == P_INFINITE_ARGS */
                    497: 
                    498: } /* init_store */
                    499: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.