|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.