1: /* 2: * Copyright (c) 1990 Michael A. Cooper. 3: * This software may be freely distributed provided it is not sold for 4: * profit and the author is credited appropriately. 5: */ 6: 7: #if !defined(lint) && defined(DOSCCS) 8: static char *RCSid = "$Header: options.c,v 1.13.1 96/3/23 18:13:28 sms Exp $"; 9: #endif 10: 11: /* 12: * $Log: options.c,v $ 13: * Revision 1.13 90/12/15 18:13:28 mcooper 14: * Add copywrite notice. 15: * 16: * Revision 1.12 90/12/15 17:51:46 mcooper 17: * Add #ifdef HAS_VARARGS around include for <varargs>. 18: * 19: * Revision 1.11 90/11/13 16:39:28 mcooper 20: * Add #ifdef HAS_VARARGS for systems without 21: * varargs. 22: * 23: * Revision 1.10 90/11/13 15:28:01 mcooper 24: * - Add OptBool cvtarg routine. 25: * - Print default values in HelpOptions() 26: * when appropriate. 27: * 28: * Revision 1.9 90/11/13 15:19:00 mcooper 29: * Added supported for options being both 30: * SepArg and StickyArg. 31: * 32: * Revision 1.8 90/10/30 21:02:31 mcooper 33: * Need to exit() if -help is specified. 34: * 35: * Revision 1.7 90/10/30 20:24:33 mcooper 36: * Fixed bug in UsageString(). 37: * 38: * Revision 1.6 90/10/30 19:53:05 mcooper 39: * Cleaned up some NeXT cc and lint stuff. 40: * 41: * Revision 1.5 90/10/30 19:45:31 mcooper 42: * Remove unneeded paramter to HelpOptions(). 43: * 44: * Revision 1.4 90/10/29 14:47:42 mcooper 45: * Added real function UsageString() to 46: * handle formating usage option strings. 47: * 48: * Revision 1.3 90/10/29 14:17:00 mcooper 49: * Allow options to be abbreviated 50: * (for all non StickArg options). 51: * 52: * Revision 1.2 90/10/26 15:56:11 mcooper 53: * - Fix bug in SepArg code that ate arguments. 54: * - Cleanup help message. 55: * - Add ArgHidden code. 56: * 57: * Revision 1.1 90/10/26 14:42:51 mcooper 58: * Initial revision 59: * 60: */ 61: 62: /* 63: * Functions to parse options. 64: */ 65: 66: #include "options.h" 67: #ifdef HAS_VARARGS 68: #include <varargs.h> 69: #endif 70: 71: char *OptionChars = "-+"; /* Default option switching characters */ 72: char *ProgramName = NULL; /* Name of this program */ 73: char *UsageString(); 74: static int isopt(); 75: static int suppress_help_msg = 0; 76: char *strcat(); 77: 78: /* 79: * ParseOptions - Parse options found in argv using "options". 80: * Returns the number of options parsed if there 81: * were no errors. Returns -1 if an error occurs. 82: */ 83: int ParseOptions(options, num_options, argc, argv) 84: OptionDescRec *options; 85: int num_options; 86: int argc; 87: char **argv; 88: { 89: OptionDescRec *opt; 90: register int x; 91: char *p; 92: 93: if (ProgramName == NULL) 94: ProgramName = argv[0]; 95: 96: #ifdef OPTION_DEBUG 97: (void) printf("Option list is:\n"); 98: for (x = 0; x < num_options; ++x) { 99: opt = &options[x]; 100: (void) printf("%s\n", opt->option); 101: } 102: 103: (void) printf("Arguments (%d):", argc); 104: for (x = 0; x < argc; ++x) { 105: (void) printf(" %s", argv[x]); 106: } 107: (void) printf("\n"); 108: #endif /* OPTION_DEBUG */ 109: 110: for (x = 1; x < argc; ++x) { 111: if (strcmp(HELPSTR, argv[x]) == 0) { 112: HelpOptions(options, num_options, (char **)NULL); 113: exit(0); 114: } 115: 116: opt = FindOption(options, num_options, argv[x]); 117: if (opt == NULL) { 118: if (isopt(argv[x])) { /* this was suppose to be an option */ 119: UsageOptions(options, num_options, argv[x]); 120: return(-1); 121: } else { /* must be end of options */ 122: break; 123: } 124: } 125: 126: if (opt->flags & NoArg) { 127: if (!(*opt->cvtarg)(opt, opt->value, FALSE)) { 128: UsageOptions(options, num_options, opt->option); 129: return(-1); 130: } 131: } else if (opt->flags & IsArg) { 132: if (!(*opt->cvtarg)(opt, opt->option, FALSE)) { 133: UsageOptions(options, num_options, opt->option); 134: return(-1); 135: } 136: } else if ((opt->flags & StickyArg) && (opt->flags & SepArg)) { 137: p = (char *) &argv[x][strlen(opt->option)]; 138: if (!*p) { /*** SepArg ***/ 139: if (x + 1 >= argc || isopt(argv[x+1])) { 140: if (opt->value == (caddr_t) NULL) { 141: UserError("%s: Option requires an argument.", argv[x]); 142: UsageOptions(options, num_options, opt->option); 143: return(-1); 144: } 145: p = opt->value; 146: } else { 147: p = argv[++x]; 148: } 149: } 150: if (!(*opt->cvtarg)(opt, p, TRUE)) { 151: UsageOptions(options, num_options, opt->option); 152: return(-1); 153: } 154: } else if (opt->flags & StickyArg) { 155: p = (char *) &argv[x][strlen(opt->option)]; 156: if (!*p) { 157: if (opt->value == (caddr_t) NULL) { 158: UserError("%s: Option requires an argument.", argv[x]); 159: UsageOptions(options, num_options, opt->option); 160: return(-1); 161: } else { 162: p = opt->value; 163: } 164: } 165: if (!(*opt->cvtarg)(opt, p, TRUE)) { 166: UsageOptions(options, num_options, opt->option); 167: return(-1); 168: } 169: } else if (opt->flags & SepArg) { 170: if (x + 1 >= argc || isopt(argv[x+1])) { 171: if (opt->value == (caddr_t) NULL) { 172: UserError("%s: Option requires an argument.", argv[x]); 173: UsageOptions(options, num_options, opt->option); 174: return(-1); 175: } else { 176: p = opt->value; 177: } 178: } else { 179: p = argv[++x]; 180: } 181: if (!(*opt->cvtarg)(opt, p, TRUE)) { 182: UsageOptions(options, num_options, opt->option); 183: return(-1); 184: } 185: } else if (opt->flags & SkipArg) { 186: x += 2; 187: } else if (opt->flags & SkipLine) { 188: return(x); 189: } else if (opt->flags & SkipNArgs) { 190: if (opt->value) { 191: x += atoi(opt->value); 192: } else { 193: UserError("Internal Error: No 'value' set for SkipNArgs."); 194: return(-1); 195: } 196: } else { 197: UserError("Internal Error: Unknown argument type for option '%s'.", 198: opt->option); 199: return(-1); 200: } 201: } 202: 203: return(x); 204: } 205: 206: /* 207: * FindOption - Find "option" in "options". Returns NULL if not found. 208: */ 209: OptionDescRec *FindOption(options, num_options, option) 210: OptionDescRec *options; 211: int num_options; 212: char *option; 213: { 214: OptionDescRec *opt; 215: register int x; 216: 217: for (x = 0; x < num_options; ++x) { 218: opt = &options[x]; 219: if (opt->flags & StickyArg) { 220: if (strncmp(option, opt->option, strlen(opt->option)) == 0) 221: return(opt); 222: } else { 223: if (strncmp(option, opt->option, strlen(option)) == 0) 224: return(opt); 225: } 226: } 227: 228: return(NULL); 229: } 230: 231: /* 232: * isopt - Is "str" an option string? Compare first char of str against 233: * list of option switch characters. Returns TRUE if it is an option. 234: */ 235: static int isopt(str) 236: char *str; 237: { 238: register char *p; 239: 240: for (p = OptionChars; p && *p; *++p) { 241: if (*str == *p) { 242: return(TRUE); 243: } 244: } 245: 246: return(FALSE); 247: } 248: 249: /* 250: * UsageOptions - Print a usage message based on "options". 251: */ 252: void UsageOptions(options, num_opts, badOption) 253: OptionDescRec *options; 254: int num_opts; 255: char *badOption; 256: { 257: OptionDescRec *opt; 258: char *optstr; 259: register int x; 260: int col, len; 261: 262: if (badOption) 263: (void) fprintf (stderr, "%s: bad command line option \"%s\"\r\n\n", 264: ProgramName, badOption); 265: 266: (void) fprintf (stderr, "usage: %s", ProgramName); 267: col = 8 + strlen(ProgramName); 268: for (x = 0; x < num_opts; x++) { 269: opt = &options[x]; 270: if (opt->flags & ArgHidden) 271: continue; 272: optstr = UsageString(opt); 273: len = strlen(optstr) + 3; /* space [ string ] */ 274: if (col + len > 79) { 275: (void) fprintf (stderr, "\r\n "); /* 3 spaces */ 276: col = 3; 277: } 278: (void) fprintf (stderr, " [%s]", optstr); 279: col += len; 280: } 281: 282: if (suppress_help_msg) 283: (void) fprintf(stderr, "\r\n\n"); 284: else 285: (void) fprintf(stderr, 286: "\r\n\nType \"%s %s\" for a full description.\r\n\n", 287: ProgramName, HELPSTR); 288: } 289: 290: /* 291: * HelpOptions - Print a nice help/usage message based on options. 292: */ 293: void HelpOptions(options, num_opts, message) 294: OptionDescRec *options; 295: int num_opts; 296: char **message; 297: { 298: OptionDescRec *opt; 299: register int x; 300: char **cpp; 301: 302: suppress_help_msg = 1; 303: UsageOptions(options, num_opts, (char *)NULL); 304: suppress_help_msg = 0; 305: 306: (void) fprintf (stderr, "where options include:\n"); 307: for (x = 0; x < num_opts; x++) { 308: opt = &options[x]; 309: if (opt->flags & ArgHidden) 310: continue; 311: (void) fprintf (stderr, " %-28s %s\n", UsageString(opt), 312: (opt->desc) ? opt->desc : ""); 313: if (opt->value && opt->cvtarg != OptBool) 314: (void) fprintf (stderr, " %-28s [ Default value is %s ]\n", 315: "", opt->value); 316: } 317: 318: if (message) { 319: (void) putc ('\n', stderr); 320: for (cpp = message; *cpp; cpp++) { 321: (void) fputs (*cpp, stderr); 322: (void) putc ('\n', stderr); 323: } 324: (void) putc ('\n', stderr); 325: } 326: } 327: 328: /* 329: * UserError - Print a user error. 330: */ 331: #ifdef HAS_VARARGS 332: void UserError(va_alist) 333: va_dcl 334: { 335: va_list args; 336: char *fmt; 337: 338: va_start(args); 339: if (ProgramName) 340: (void) fprintf(stderr, "%s: ", ProgramName); 341: fmt = (char *) va_arg(args, char *); 342: (void) vfprintf(stderr, fmt, args); 343: va_end(args); 344: (void) fprintf(stderr, "\n"); 345: } 346: #else 347: void UserError(fmt, a1, a2, a3, a4, a5, a6) 348: char *fmt; 349: { 350: if (ProgramName) 351: (void) fprintf(stderr, "%s: ", ProgramName); 352: (void) fprintf(stderr, fmt, a1, a2, a3, a4, a5, a6); 353: (void) fprintf(stderr, "\n"); 354: } 355: #endif 356: 357: OptBool(opt, value, docopy) 358: OptionDescRec *opt; 359: caddr_t value; 360: int docopy; /*ARGSUSED*/ 361: { 362: char *vpp; 363: 364: *(int *) opt->valp = (int) strtol(value, &vpp, 0); 365: if (*vpp) { 366: UserError("Invalid integer argument for '%s'.", opt->option); 367: return(FALSE); 368: } else { 369: return(TRUE); 370: } 371: } 372: 373: OptInt(opt, value, docopy) 374: OptionDescRec *opt; 375: caddr_t value; 376: int docopy; /*ARGSUSED*/ 377: { 378: char *vpp; 379: 380: *(int *) opt->valp = (int) strtol(value, &vpp, 0); 381: if (*vpp) { 382: UserError("Invalid integer argument for '%s'.", opt->option); 383: return(FALSE); 384: } else { 385: return(TRUE); 386: } 387: } 388: 389: OptShort(opt, value, docopy) 390: OptionDescRec *opt; 391: caddr_t value; 392: int docopy; /*ARGSUSED*/ 393: { 394: char *vpp; 395: 396: *(short *) opt->valp = (short) strtol(value, &vpp, 0); 397: if (*vpp) { 398: UserError("Invalid integer argument for '%s'.", opt->option); 399: return(FALSE); 400: } else { 401: return(TRUE); 402: } 403: } 404: 405: OptLong(opt, value, docopy) 406: OptionDescRec *opt; 407: caddr_t value; 408: int docopy; /*ARGSUSED*/ 409: { 410: char *vpp; 411: 412: *(long *) opt->valp = (long) strtol(value, &vpp, 0); 413: if (*vpp) { 414: UserError("Invalid integer argument for '%s'.", opt->option); 415: return(FALSE); 416: } else { 417: return(TRUE); 418: } 419: } 420: 421: OptStr(opt, value, docopy) 422: OptionDescRec *opt; 423: caddr_t value; 424: int docopy; 425: { 426: char *p; 427: 428: if (docopy) { 429: if ((p = (char *) malloc((unsigned)strlen(value)+1)) == NULL) { 430: UserError("Cannot malloc memory."); 431: return(FALSE); 432: } 433: (void) strcpy(p, value); 434: } else { 435: p = value; 436: } 437: 438: *(char **) opt->valp = p; 439: 440: return(TRUE); 441: } 442: 443: static char *UsageString(opt) 444: OptionDescRec *opt; 445: { 446: static char buf[BUFSIZ], buf2[BUFSIZ]; 447: 448: (void) sprintf(buf, opt->option); 449: (void) strcpy(buf2, ""); 450: if (opt->usage) { 451: (void) sprintf(buf2, "%s%s%s%s", 452: ((opt->flags & StickyArg) && 453: !((opt->flags & StickyArg) && (opt->flags & SepArg))) 454: ? "" : " ", 455: (opt->value) ? "[" : "", 456: opt->usage, 457: (opt->value) ? "]" : "" 458: ); 459: } 460: (void) strcat(buf, buf2); 461: 462: return(buf); 463: }