Line Name ----- ---- 74 cmdopt_cmp 122 kwdef_cmp 189 kwstrleadlen 165 kwstrlen 315 process_keyword 214 process_options 454 process_options_file 390 translate_keyword 36 ustrncmp
BEGINNING OF FILE
1: /****************************************************************************/ 2: /* */ 3: /* FACILITY: Generic Support Library */ 4: /* */ 5: /* MODULE: Command Line Keyword and Option Processing */ 6: /* */ 7: /* AUTHOR: Steve Branam, Network Product Support Group, Digital */ 8: /* Equipment Corporation, Littleton, MA, USA. */ 9: /* */ 10: /* DESCRIPTION: This module contains routines to process command line */ 11: /* arguments, given a dispatch table of keywords and handlers. This can be */ 12: /* used for main program command lines, or internal command lines parsed */ 13: /* in a similar manner. */ 14: /* */ 15: /* REVISION HISTORY: */ 16: /* */ 17: /* V0.1-00 24-AUG-1994 Steve Branam */ 18: /* */ 19: /* Original version. */ 20: /* */ 21: /* V0.2-00 23-SEP-1994 Steve Branam */ 22: /* */ 23: /* Addded keyword translation code. */ 24: /* */ 25: /****************************************************************************/ 26: 27: #include <stdio.h> 28: #include <ctype.h> 29: #include "cmdopt.h" 30: 31: static KEYWORD_DEFINITION /* Option dispatch table, */ 32: *mOptionTable; /* used by options file */ 33: /* processing. */ 34: 35: /*************************************************************************++*/
36: int ustrncmp( 37: /* Compares strings in upper-case, serving as a case-insensitive string */ 38: /* comparison; otherwise identical to strncmp. */ 39: 40: char *aStr1, 41: /* (READ, BY ADDR): */ 42: /* First string to compare. */ 43: 44: char *aStr2, 45: /* (READ, BY ADDR): */ 46: /* Second string to compare. */ 47: 48: int vLength 49: /* (READ, BY VAL): */ 50: /* Maximum number of characters to compare. */ 51: 52: ) /* Returns status value indicating comparison results: */ 53: /* 0 - Strings are equal. */ 54: /* < 0 - String aStr1 is less than aStr2. */ 55: /* > 0 - String aStr1 is greater than aStr2. */ 56: /*****************************************************************--*/ 57: 58: { 59: /*+ */ 60: /* Compare upper-case version of each char in strings until unequal */ 61: /* chars ard found, end of string is found, or maximum number of */ 62: /* characters exceeded. */ 63: /*- */ 64: 65: for (; toupper(*aStr1) == toupper(*aStr2); aStr1++, aStr2++) { 66: if (*aStr1 == '\0' || --vLength == 0) { 67: return 0; /* Strings are "equal". */ 68: } 69: } /* String are not equal. */ 70: return toupper(*aStr1) - toupper(*aStr2); 71: }END ustrncmp. Go to: Beginning of routine.
72: 73: /*************************************************************************++*/
74: static int cmdopt_cmp( 75: /* Compares an argument string to a command line option using a case- */ 76: /* insensitive string comparison. The argument matches the option if the */ 77: /* keyword portion is at least as long as the minimum option keyword */ 78: /* length, and matches the keyword for all specified characters. */ 79: 80: KEYWORD_DEFINITION 81: *aOption, 82: /* (READ, BY ADDR): */ 83: /* Command line option keyword definition to compare. */ 84: 85: char *aArgStr 86: /* (READ, BY ADDR): */ 87: /* Argument string to compare. Options are assumed to be */ 88: /* specified in one of two forms, either just the option switch */ 89: /* char followed by the keyword (for toggle options), or the */ 90: /* option switch char and keyword followed by an equal sign and */ 91: /* the option value string (for value options). */ 92: 93: ) /* Returns length of keyword portion of aArgstr (including switch */ 94: /* char) to indicate successful match, or 0 if argument does not */ 95: /* match option. */ 96: /********************************************************************/ 97: 98: { 99: int kwlen; /* Length of argument keyword */ 100: /* portion (including switch */ 101: /* char). */ 102: 103: /*+ */ 104: /* Find length of argument keyword portion. If it is less than minimum */ 105: /* required length, no match. Otherwise, compare argument to option */ 106: /* keyword to determine match. */ 107: /*- */ 108: 109: if ((kwlen = kwstrlen(&aArgStr[1])) < kwdef_minlen(aOption)) { 110: return 0; /* Too short, no match. */ 111: } 112: else if (ustrncmp(kwdef_keyword(aOption), &aArgStr[1], 113: max(kwlen, kwdef_minlen(aOption))) == 0) { 114: return kwlen + 1; /* Argument matches option. */ 115: } 116: else { 117: return 0; /* No match. */ 118: } 119: }END cmdopt_cmp. Go to: Beginning of routine.
120: 121: /*************************************************************************++*/
122: static int kwdef_cmp( 123: /* Compares a string to a keyword using a case- insensitive string */ 124: /* comparison. The string matches the keyword if it is at least as long as */ 125: /* the minimum keyword length, and matches the keyword for all specified */ 126: /* characters. */ 127: 128: KEYWORD_DEFINITION 129: *aKwDef, 130: /* (READ, BY ADDR): */ 131: /* Keyword definition to compare. */ 132: 133: char *aKwStr, 134: /* (READ, BY ADDR): */ 135: /* Keyword string to compare. */ 136: 137: int vLength 138: /* (READ, BY VAL): */ 139: /* Keyword string length. */ 140: 141: ) /* Returns status flag: */ 142: /* 1 - Successful match */ 143: /* 0 - String does not match keyword. */ 144: /* ****************************************************************** */ 145: 146: { 147: /*+ */ 148: /* If string length is less than minimum required length, no match. */ 149: /* Otherwise, compare argument to option keyword to determine match. */ 150: /* */ 151: 152: if (vLength < kwdef_minlen(aKwDef)) { 153: return 0; /* Too short, no match. */ 154: } 155: else if (ustrncmp(kwdef_keyword(aKwDef), aKwStr, 156: max(vLength, kwdef_minlen(aKwDef))) == 0) { 157: return 1; /* String matches keyword. */ 158: } 159: else { 160: return 0; /* No match. */ 161: } 162: }END kwdef_cmp. Go to: Beginning of routine.
163: 164: /*************************************************************************++*/
165: int kwstrlen( 166: /* Finds the length of a keyword string. A keyword is a contiguous string */ 167: /* of alphanumerics and the underscore character '_'. */ 168: 169: char *aKwStr 170: /* (READ, BY ADDR): */ 171: /* Keyword string to find length of. It is assumed to contain */ 172: /* no leading non-keyword characters (if it does, the length */ 173: /* returned will be 0). */ 174: 175: ) /* Returns length of string, or 0 if the first character is not a */ 176: /* valid keyword string character. */ 177: /********************************************************************/ 178: 179: { 180: int kwlen; /* Length of keyword. */ 181: 182: for (kwlen = 0; 183: isalnum(aKwStr[kwlen]) || aKwStr[kwlen] == '_'; 184: kwlen++); 185: return kwlen; 186: }END kwstrlen. Go to: Beginning of routine.
187: 188: /*************************************************************************++*/
189: int kwstrleadlen( 190: /* Finds the length of leading non-keyword characters in a keyword string, */ 191: /* which may subsequently be treated as the offset to the beginning of the */ 192: /* keyword. */ 193: 194: char *aKwStr 195: /* (READ, BY ADDR): */ 196: /* Keyword string that may contain leading non-keyword */ 197: /* characters. */ 198: 199: ) /* Returns length of leading characters, or 0 if the string */ 200: /* contains no leading characters (or is a null string). */ 201: /********************************************************************/ 202: 203: { 204: int leadlen; /* Length of leading chars. */ 205: 206: for (leadlen = 0; 207: !isalnum(aKwStr[leadlen]) 208: && aKwStr[leadlen] != '_' && aKwStr[leadlen] != '\0'; 209: leadlen++); 210: return leadlen; 211: }END kwstrleadlen. Go to: Beginning of routine.
212: 213: /*************************************************************************++*/
214: int process_options( 215: /* Parses user command line arguments for options and dispatches option */ 216: /* handler routines. Processing will terminate if any handler indicates */ 217: /* failure. */ 218: 219: int vArgc, 220: /* (READ, BY VAL): */ 221: /* Number of program argument strings in aArgv. */ 222: 223: char *aArgv[], 224: /* (READ, BY ADDR): */ 225: /* List of program argument strings. */ 226: 227: int vFirstOption, 228: /* (READ, BY VAL): */ 229: /* Starting argument number for option. All preceding arguments */ 230: /* are assumed to be required, not options. */ 231: 232: KEYWORD_DEFINITION 233: *aOptionTable 234: /* (READ, BY ADDR): */ 235: 236: /* Option definition table, containing option keywords (not */ 237: /* including option switch character), handler routine ptrs, */ 238: /* and keyword translation codes. The table is terminated by */ 239: /* an entry containing a NULL keyword ptr. The interface for a */ 240: /* handler routine is: */ 241: /* */ 242: /* int handler(code, valstr, n) */ 243: /* */ 244: /* where code is the translation code for the matched keyword, */ 245: /* valstr is the ptr to the remainder of the argument string */ 246: /* following the matched argument characters, and n is the */ 247: /* option's argument position on the command line; however, a */ 248: /* handler is free to ignore (and therefore not declare) any */ 249: /* trailing subset of these parameters. The handler returns 1 */ 250: /* if the argument is handled successfully, or 0 otherwise. */ 251: /* This interface supports two styles of usage: common handlers */ 252: /* may handle several different options, discriminating the */ 253: /* matched option via the translation code; or individual */ 254: /* handlers may be used for each option, ignoring the */ 255: /* translation codes. */ 256: 257: ) /* Returns status indicating processing success: */ 258: /* 1 - All options handled successfully (any unrecognized */ 259: /* arguments/options ignored). */ 260: /* 0 - An argument could not be processed. */ 261: /********************************************************************/ 262: 263: { 264: int arg; /* Argument number. */ 265: KEYWORD_DEFINITION /* Current keyword def. */ 266: *kwdef; 267: int kwlen; /* Length of argument */ 268: /* keyword portion */ 269: /* (including switch char). */ 270: 271: /*+ */ 272: /* Save option table ptr in case we run into an option to process an */ 273: /* options file, then attempt to process each command line argument */ 274: /* following the required ones as an option. */ 275: /*- */ 276: 277: mOptionTable = aOptionTable; 278: for (arg = vFirstOption; arg < vArgc; arg++) { 279: 280: /*+ */ 281: /* If argument starts with option switch character, go through */ 282: /* option table trying to match it. On match, call option handler */ 283: /* and skip the rest of the option table; if the handler return */ 284: /* failure, abort. If no match, issue warning and ignore the */ 285: /* argument. If it did not start with switch char, issue warning */ 286: /* and ignore it. */ 287: /*- */ 288: 289: if (*aArgv[arg] == CMDLINE_OPTION_SWITCH) { 290: for (kwdef = aOptionTable; kwdef_keyword(kwdef) != NULL; kwdef++) { 291: if ((kwlen = cmdopt_cmp(kwdef, aArgv[arg]))) { 292: 293: /* Match, call handler. */ 294: if (!(kwdef_handler(kwdef))(kwdef_code(kwdef), 295: &aArgv[arg][kwlen], arg)) { 296: return 0; /* Abort, handler failed! */ 297: } 298: break; /* Skip rest of table. */ 299: } 300: } 301: if (!kwlen) { /* No option matches. */ 302: printf("ERROR: Unrecognized/ambiguous option %s\n", aArgv[arg]); 303: return 0; 304: } 305: } 306: else { /* Not an option argument. */ 307: printf("ERROR: Unexpected command line argument %s\n", aArgv[arg]); 308: return 0; 309: } 310: } /* All options processed */ 311: return 1; /* successfully. */ 312: }END process_options. Go to: Beginning of routine.
313: 314: /*************************************************************************++*/
315: int process_keyword( 316: /* Parses keyword strings and dispatches to keyword handler routines. */ 317: /* Processing will terminate if any handler indicates failure. */ 318: 319: char *aKwStr, 320: /* (READ, BY ADDR): */ 321: /* Keyword string, with no leading, trailing, or enclosed */ 322: /* whitespace. May be a single keyword, or a list of keywords, */ 323: /* separated by commas. */ 324: 325: KEYWORD_DEFINITION 326: *aKwTable 327: /* (READ, BY ADDR): */ 328: /* Keyword definition table, containing keywords, handler */ 329: /* routine ptrs, and keyword translation codes. The table is */ 330: /* terminated by an entry containing a NULL keyword ptr. The */ 331: /* interface for a handler routine is: */ 332: /* */ 333: /* int handler(code) */ 334: /* */ 335: /* where code is the keyword translation code. (there are no */ 336: /* arguments to the handler). The handler returns 1 if the */ 337: /* argument is handled successfully, or 0 otherwise. This */ 338: /* interface supports two styles of usage: common handlers may */ 339: /* handle several different keywords, discriminating the */ 340: /* matched keyword via the translation code; or individual */ 341: /* handlers may be used for each keyword, ignoring the */ 342: /* translation codes. */ 343: 344: ) /* Returns status indicating processing success: */ 345: /* 1 - All keywords handled successfully. */ 346: /* 0 - A keyword could not be processed. */ 347: /********************************************************************/ 348: 349: { 350: KEYWORD_DEFINITION /* Current keyword def. */ 351: *kwdef; 352: int kwlen; /* Length of keyword. */ 353: int found; /* Flag indicating match. */ 354: char *savestr = aKwStr; /* Saved string ptr. */ 355: 356: /* For each keyword in list */ 357: while (*aKwStr != '\0') { /* (or just one)... */ 358: 359: if ((kwlen = kwstrlen(aKwStr)) == 0) { 360: printf("ERROR: Missing keyword %s\n", savestr); 361: return 0; 362: } 363: else { /* Scan keyword table for */ 364: /* match. */ 365: for (kwdef = aKwTable; kwdef_keyword(kwdef) != NULL; kwdef++) { 366: if ((found = kwdef_cmp(kwdef, aKwStr, kwlen))) { 367: 368: /* Match, call handler with */ 369: /* translation code. */ 370: if (!(kwdef_handler(kwdef))(kwdef_code(kwdef))) { 371: return 0; /* Abort, handler failed! */ 372: } 373: break; /* Skip rest of table. */ 374: } 375: } 376: if (!found) { 377: printf("ERROR: Unrecognized/ambiguous keyword %s\n", aKwStr); 378: return 0; 379: } 380: } 381: if (aKwStr[kwlen] == KEYWORD_LIST_SEPARATOR) { 382: kwlen++; /* Account for separator. */ 383: } 384: aKwStr += kwlen; /* Advance past keyword. */ 385: } 386: return 1; /* All keywords processed */ 387: } /* successfully. */END process_keyword. Go to: Beginning of routine.
388: 389: /*************************************************************************++*/
390: int translate_keyword( 391: /* Parses a single keyword string and returns a translation code. */ 392: 393: char *aKwStr, 394: /* (READ, BY ADDR): */ 395: /* Keyword string. If it contains any leading non-keyword */ 396: /* characters, they will be ignored. If it contains more than */ 397: /* one keyword, only the first one will be translated. */ 398: 399: KEYWORD_DEFINITION 400: *aKwTable 401: /* (READ, BY ADDR): */ 402: /* Keyword definition table, containing keywords, handler */ 403: /* routine ptrs, and keyword translation codes. The table is */ 404: /* terminated by an entry containing a NULL keyword ptr. The */ 405: /* handler routine is called only if its ptr is non-NULL. The */ 406: /* interface for a handler routine is: */ 407: /* */ 408: /* int handler(code) */ 409: /* */ 410: /* where code is the keyword translation code. (there are no */ 411: /* arguments to the handler). The handler returns 1 if the */ 412: /* argument is handled successfully, or 0 otherwise. This */ 413: /* interface supports two styles of usage: common handlers may */ 414: /* handle several different keywords, discriminating the */ 415: /* matched keyword via the translation code; or individual */ 416: /* handlers may be used for each keyword, ignoring the */ 417: /* translation codes. */ 418: 419: ) /* Returns matching keyword translation code, or 0 if no match */ 420: /* found or the matching keyword handler returns 0. */ 421: /********************************************************************/ 422: 423: { 424: KEYWORD_DEFINITION /* Current keyword def. */ 425: *kwdef; 426: int kwlen; /* Length of keyword. */ 427: char *savestr = aKwStr; /* Saved string ptr. */ 428: 429: if ((kwlen = kwstrlen(aKwStr)) == 0) { 430: return 0; 431: } 432: else { /* Scan keyword table for */ 433: /* match. */ 434: for (kwdef = aKwTable; kwdef_keyword(kwdef) != NULL; kwdef++) { 435: if (kwdef_cmp(kwdef, aKwStr, kwlen)) { 436: 437: /* Match, if handler */ 438: /* defined, call it with */ 439: /* translation code. */ 440: if (kwdef_handler(kwdef) != NULL 441: && !(kwdef_handler(kwdef))(kwdef_code(kwdef))) { 442: return 0; /* Abort, handler failed! */ 443: } 444: else { /* Handler ok (or not */ 445: return kwdef_code(kwdef); /* defined), return code. */ 446: } 447: } 448: } 449: return 0; /* No match. */ 450: } 451: }END translate_keyword. Go to: Beginning of routine.
452: 453: /*************************************************************************++*/
454: int process_options_file( 455: /* Command line option handler to read an options file, where each line is */ 456: /* a single command line option, just as if it were parsed from the command */ 457: /* line. Option files may be nested, just be careful of looped files or */ 458: /* running out of resources due to excessive nesting. Comments lines and */ 459: /* trailing comment are allowed. */ 460: 461: int vKwCode, 462: /* (READ, BY ADDR): */ 463: /* Option keyword translation code, ignored by this routine. */ 464: 465: char *aValStr 466: /* (READ, BY ADDR): */ 467: /* Option value string, preceded by equal sign. */ 468: 469: ) /* Returns status code: */ 470: /* 1 - Successful processing of this option. */ 471: /* 0 - Option file name missing, or file cannot be opened. */ 472: /*****************************************************************--*/ 473: 474: { 475: FILE *optfile; /* Options file ptr. */ 476: int rcount; /* Routine name count. */ 477: char option[512]; /* Option string buffer. */ 478: char *optend; /* End-of-option ptr. */ 479: char *optv; /* Option buffer ptr. */ 480: 481: /* Check for equal sign and */ 482: /* make sure there is a file. */ 483: if (*aValStr++ == CMDLINE_OPTION_SEPARATOR && *aValStr != '\0') { 484: if ((optfile = fopen(aValStr, "r")) != NULL) { 485: 486: /* For each line, locate */ 487: /* beginning of text. */ 488: while (fgets(option, sizeof(option), optfile) != NULL) { 489: for (optv = option; 490: *optv != '\0' && *optv != CMDLINE_OPTION_SWITCH && 491: *optv != CMDLINE_OPTION_COMMENT; 492: optv++); 493: /* Ignore comment lines. Find */ 494: /* end of option field and */ 495: /* process option. */ 496: if (*optv != CMDLINE_OPTION_COMMENT) { 497: for (optend = optv; 498: *optend > ' ' && *optend != CMDLINE_OPTION_COMMENT; 499: optend++); 500: *optend = '\0'; 501: if (!process_options(1, &optv, 0, mOptionTable)) { 502: printf( 503: "ERROR: Failure processing option \"%s\" in %s\n", 504: option, aValStr); 505: fclose(optfile); 506: return 0; 507: } 508: } 509: } 510: fclose(optfile); 511: return 1; 512: } 513: else { 514: printf("ERROR: Unable to open options file %s for input\n", 515: aValStr); 516: return 0; 517: } 518: } 519: else { 520: printf("ERROR: %coptions option requires options file name\n", 521: CMDLINE_OPTION_SWITCH); 522: return 0; 523: } 524: }END process_options_file. Go to: Beginning of routine.
525:
END OF FILE TOTAL: 9 routines, 53 Avg Length