|
|
1.1 ! root 1: /* ! 2: * tkArgv.c -- ! 3: * ! 4: * This file contains a procedure that handles table-based ! 5: * argv-argc parsing. ! 6: * ! 7: * Copyright 1990 Regents of the University of California ! 8: * Permission to use, copy, modify, and distribute this ! 9: * software and its documentation for any purpose and without ! 10: * fee is hereby granted, provided that the above copyright ! 11: * notice appear in all copies. The University of California ! 12: * makes no representations about the suitability of this ! 13: * software for any purpose. It is provided "as is" without ! 14: * express or implied warranty. ! 15: */ ! 16: ! 17: #ifndef lint ! 18: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkArgv.c,v 1.12 92/08/07 08:39:48 ouster Exp $ SPRITE (Berkeley)"; ! 19: #endif ! 20: ! 21: #include "tkconfig.h" ! 22: #include "tk.h" ! 23: ! 24: /* ! 25: * Default table of argument descriptors. These are normally available ! 26: * in every application. ! 27: */ ! 28: ! 29: static Tk_ArgvInfo defaultTable[] = { ! 30: {"-help", TK_ARGV_HELP, (char *) NULL, (char *) NULL, ! 31: "Print summary of command-line options and abort"}, ! 32: {NULL, TK_ARGV_END, (char *) NULL, (char *) NULL, ! 33: (char *) NULL} ! 34: }; ! 35: ! 36: /* ! 37: * Forward declarations for procedures defined in this file: ! 38: */ ! 39: ! 40: static void PrintUsage _ANSI_ARGS_((Tcl_Interp *interp, ! 41: Tk_ArgvInfo *argTable, int flags)); ! 42: ! 43: /* ! 44: *---------------------------------------------------------------------- ! 45: * ! 46: * Tk_ParseArgv -- ! 47: * ! 48: * Process an argv array according to a table of expected ! 49: * command-line options. See the manual page for more details. ! 50: * ! 51: * Results: ! 52: * The return value is a standard Tcl return value. If an ! 53: * error occurs then an error message is left in interp->result. ! 54: * Under normal conditions, both *argcPtr and *argv are modified ! 55: * to return the arguments that couldn't be processed here (they ! 56: * didn't match the option table, or followed an TK_ARGV_REST ! 57: * argument). ! 58: * ! 59: * Side effects: ! 60: * Variables may be modified, resources may be entered for tkwin, ! 61: * or procedures may be called. It all depends on the arguments ! 62: * and their entries in argTable. See the user documentation ! 63: * for details. ! 64: * ! 65: *---------------------------------------------------------------------- ! 66: */ ! 67: ! 68: int ! 69: Tk_ParseArgv(interp, tkwin, argcPtr, argv, argTable, flags) ! 70: Tcl_Interp *interp; /* Place to store error message. */ ! 71: Tk_Window tkwin; /* Window to use for setting Tk options. ! 72: * NULL means ignore Tk option specs. */ ! 73: int *argcPtr; /* Number of arguments in argv. Modified ! 74: * to hold # args left in argv at end. */ ! 75: char **argv; /* Array of arguments. Modified to hold ! 76: * those that couldn't be processed here. */ ! 77: Tk_ArgvInfo *argTable; /* Array of option descriptions */ ! 78: int flags; /* Or'ed combination of various flag bits, ! 79: * such as TK_ARGV_NO_DEFAULTS. */ ! 80: { ! 81: register Tk_ArgvInfo *infoPtr; ! 82: /* Pointer to the current entry in the ! 83: * table of argument descriptions. */ ! 84: Tk_ArgvInfo *matchPtr; /* Descriptor that matches current argument. */ ! 85: char *curArg; /* Current argument */ ! 86: register char c; /* Second character of current arg (used for ! 87: * quick check for matching; use 2nd char. ! 88: * because first char. will almost always ! 89: * be '-'). */ ! 90: int srcIndex; /* Location from which to read next argument ! 91: * from argv. */ ! 92: int dstIndex; /* Index into argv to which next unused ! 93: * argument should be copied (never greater ! 94: * than srcIndex). */ ! 95: int argc; /* # arguments in argv still to process. */ ! 96: int length; /* Number of characters in current argument. */ ! 97: int i; ! 98: ! 99: if (flags & TK_ARGV_DONT_SKIP_FIRST_ARG) { ! 100: srcIndex = dstIndex = 0; ! 101: argc = *argcPtr; ! 102: } else { ! 103: srcIndex = dstIndex = 1; ! 104: argc = *argcPtr-1; ! 105: } ! 106: ! 107: while (argc > 0) { ! 108: curArg = argv[srcIndex]; ! 109: srcIndex++; ! 110: argc--; ! 111: c = curArg[1]; ! 112: length = strlen(curArg); ! 113: ! 114: /* ! 115: * Loop throught the argument descriptors searching for one with ! 116: * the matching key string. If found, leave a pointer to it in ! 117: * matchPtr. ! 118: */ ! 119: ! 120: matchPtr = NULL; ! 121: for (i = 0; i < 2; i++) { ! 122: if (i == 0) { ! 123: infoPtr = argTable; ! 124: } else { ! 125: infoPtr = defaultTable; ! 126: } ! 127: for (; infoPtr->type != TK_ARGV_END; infoPtr++) { ! 128: if (infoPtr->key == NULL) { ! 129: continue; ! 130: } ! 131: if ((infoPtr->key[1] != c) ! 132: || (strncmp(infoPtr->key, curArg, length) != 0)) { ! 133: continue; ! 134: } ! 135: if ((tkwin == NULL) ! 136: && ((infoPtr->type == TK_ARGV_CONST_OPTION) ! 137: || (infoPtr->type == TK_ARGV_OPTION_VALUE) ! 138: || (infoPtr->type == TK_ARGV_OPTION_NAME_VALUE))) { ! 139: continue; ! 140: } ! 141: if (infoPtr->key[length] == 0) { ! 142: matchPtr = infoPtr; ! 143: goto gotMatch; ! 144: } ! 145: if (flags & TK_ARGV_NO_ABBREV) { ! 146: continue; ! 147: } ! 148: if (matchPtr != NULL) { ! 149: Tcl_AppendResult(interp, "ambiguous option \"", curArg, ! 150: "\"", (char *) NULL); ! 151: return TCL_ERROR; ! 152: } ! 153: matchPtr = infoPtr; ! 154: } ! 155: } ! 156: if (matchPtr == NULL) { ! 157: ! 158: /* ! 159: * Unrecognized argument. Just copy it down, unless the caller ! 160: * prefers an error to be registered. ! 161: */ ! 162: ! 163: if (flags & TK_ARGV_NO_LEFTOVERS) { ! 164: Tcl_AppendResult(interp, "unrecognized argument \"", ! 165: curArg, "\"", (char *) NULL); ! 166: return TCL_ERROR; ! 167: } ! 168: argv[dstIndex] = curArg; ! 169: dstIndex++; ! 170: continue; ! 171: } ! 172: ! 173: /* ! 174: * Take the appropriate action based on the option type ! 175: */ ! 176: ! 177: gotMatch: ! 178: infoPtr = matchPtr; ! 179: switch (infoPtr->type) { ! 180: case TK_ARGV_CONSTANT: ! 181: *((int *) infoPtr->dst) = (int) infoPtr->src; ! 182: break; ! 183: case TK_ARGV_INT: ! 184: if (argc == 0) { ! 185: goto missingArg; ! 186: } else { ! 187: char *endPtr; ! 188: ! 189: *((int *) infoPtr->dst) = ! 190: strtol(argv[srcIndex], &endPtr, 0); ! 191: if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) { ! 192: Tcl_AppendResult(interp, "expected integer argument ", ! 193: "for \"", infoPtr->key, "\" but got \"", ! 194: argv[srcIndex], "\"", (char *) NULL); ! 195: return TCL_ERROR; ! 196: } ! 197: srcIndex++; ! 198: argc--; ! 199: } ! 200: break; ! 201: case TK_ARGV_STRING: ! 202: if (argc == 0) { ! 203: goto missingArg; ! 204: } else { ! 205: *((char **)infoPtr->dst) = argv[srcIndex]; ! 206: srcIndex++; ! 207: argc--; ! 208: } ! 209: break; ! 210: case TK_ARGV_UID: ! 211: if (argc == 0) { ! 212: goto missingArg; ! 213: } else { ! 214: *((Tk_Uid *)infoPtr->dst) = Tk_GetUid(argv[srcIndex]); ! 215: srcIndex++; ! 216: argc--; ! 217: } ! 218: break; ! 219: case TK_ARGV_REST: ! 220: *((int *) infoPtr->dst) = dstIndex; ! 221: goto argsDone; ! 222: case TK_ARGV_FLOAT: ! 223: if (argc == 0) { ! 224: goto missingArg; ! 225: } else { ! 226: char *endPtr; ! 227: ! 228: *((double *) infoPtr->dst) = ! 229: strtod(argv[srcIndex], &endPtr); ! 230: if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) { ! 231: Tcl_AppendResult(interp, "expected floating-point ", ! 232: "argument for \"", infoPtr->key, ! 233: "\" but got \"", argv[srcIndex], "\"", ! 234: (char *) NULL); ! 235: return TCL_ERROR; ! 236: } ! 237: srcIndex++; ! 238: argc--; ! 239: } ! 240: break; ! 241: case TK_ARGV_FUNC: { ! 242: int (*handlerProc)(); ! 243: ! 244: handlerProc = (int (*)())infoPtr->src; ! 245: ! 246: if ((*handlerProc)(infoPtr->dst, infoPtr->key, ! 247: argv[srcIndex])) { ! 248: srcIndex += 1; ! 249: argc -= 1; ! 250: } ! 251: break; ! 252: } ! 253: case TK_ARGV_GENFUNC: { ! 254: int (*handlerProc)(); ! 255: ! 256: handlerProc = (int (*)())infoPtr->src; ! 257: ! 258: argc = (*handlerProc)(infoPtr->dst, interp, infoPtr->key, ! 259: argc, argv+srcIndex); ! 260: if (argc < 0) { ! 261: return TCL_ERROR; ! 262: } ! 263: break; ! 264: } ! 265: case TK_ARGV_HELP: ! 266: PrintUsage (interp, argTable, flags); ! 267: return TCL_ERROR; ! 268: case TK_ARGV_CONST_OPTION: ! 269: Tk_AddOption(tkwin, infoPtr->dst, infoPtr->src, ! 270: TK_INTERACTIVE_PRIO); ! 271: break; ! 272: case TK_ARGV_OPTION_VALUE: ! 273: if (argc < 1) { ! 274: goto missingArg; ! 275: } ! 276: Tk_AddOption(tkwin, infoPtr->dst, argv[srcIndex], ! 277: TK_INTERACTIVE_PRIO); ! 278: srcIndex++; ! 279: argc--; ! 280: break; ! 281: case TK_ARGV_OPTION_NAME_VALUE: ! 282: if (argc < 2) { ! 283: Tcl_AppendResult(interp, "\"", curArg, ! 284: "\" option requires two following arguments", ! 285: (char *) NULL); ! 286: return TCL_ERROR; ! 287: } ! 288: Tk_AddOption(tkwin, argv[srcIndex], argv[srcIndex+1], ! 289: TK_INTERACTIVE_PRIO); ! 290: srcIndex += 2; ! 291: argc -= 2; ! 292: break; ! 293: default: ! 294: sprintf(interp->result, "bad argument type %d in Tk_ArgvInfo", ! 295: infoPtr->type); ! 296: return TCL_ERROR; ! 297: } ! 298: } ! 299: ! 300: /* ! 301: * If we broke out of the loop because of an OPT_REST argument, ! 302: * copy the remaining arguments down. ! 303: */ ! 304: ! 305: argsDone: ! 306: while (argc) { ! 307: argv[dstIndex] = argv[srcIndex]; ! 308: srcIndex++; ! 309: dstIndex++; ! 310: argc--; ! 311: } ! 312: argv[dstIndex] = (char *) NULL; ! 313: *argcPtr = dstIndex; ! 314: return TCL_OK; ! 315: ! 316: missingArg: ! 317: Tcl_AppendResult(interp, "\"", curArg, ! 318: "\" option requires an additional argument", (char *) NULL); ! 319: return TCL_ERROR; ! 320: } ! 321: ! 322: /* ! 323: *---------------------------------------------------------------------- ! 324: * ! 325: * PrintUsage -- ! 326: * ! 327: * Generate a help string describing command-line options. ! 328: * ! 329: * Results: ! 330: * Interp->result will be modified to hold a help string ! 331: * describing all the options in argTable, plus all those ! 332: * in the default table unless TK_ARGV_NO_DEFAULTS is ! 333: * specified in flags. ! 334: * ! 335: * Side effects: ! 336: * None. ! 337: * ! 338: *---------------------------------------------------------------------- ! 339: */ ! 340: ! 341: static void ! 342: PrintUsage(interp, argTable, flags) ! 343: Tcl_Interp *interp; /* Place information in this interp's ! 344: * result area. */ ! 345: Tk_ArgvInfo *argTable; /* Array of command-specific argument ! 346: * descriptions. */ ! 347: int flags; /* If the TK_ARGV_NO_DEFAULTS bit is set ! 348: * in this word, then don't generate ! 349: * information for default options. */ ! 350: { ! 351: register Tk_ArgvInfo *infoPtr; ! 352: int width, i, numSpaces; ! 353: #define NUM_SPACES 20 ! 354: static char spaces[] = " "; ! 355: char tmp[30]; ! 356: ! 357: /* ! 358: * First, compute the width of the widest option key, so that we ! 359: * can make everything line up. ! 360: */ ! 361: ! 362: width = 4; ! 363: for (i = 0; i < 2; i++) { ! 364: for (infoPtr = i ? defaultTable : argTable; ! 365: infoPtr->type != TK_ARGV_END; infoPtr++) { ! 366: int length; ! 367: if (infoPtr->key == NULL) { ! 368: continue; ! 369: } ! 370: length = strlen(infoPtr->key); ! 371: if (length > width) { ! 372: width = length; ! 373: } ! 374: } ! 375: } ! 376: ! 377: Tcl_AppendResult(interp, "Command-specific options:", (char *) NULL); ! 378: for (i = 0; ; i++) { ! 379: for (infoPtr = i ? defaultTable : argTable; ! 380: infoPtr->type != TK_ARGV_END; infoPtr++) { ! 381: if ((infoPtr->type == TK_ARGV_HELP) && (infoPtr->key == NULL)) { ! 382: Tcl_AppendResult(interp, "\n", infoPtr->help, (char *) NULL); ! 383: continue; ! 384: } ! 385: Tcl_AppendResult(interp, "\n ", infoPtr->key, ":", (char *) NULL); ! 386: numSpaces = width + 1 - strlen(infoPtr->key); ! 387: while (numSpaces > 0) { ! 388: if (numSpaces >= NUM_SPACES) { ! 389: Tcl_AppendResult(interp, spaces, (char *) NULL); ! 390: } else { ! 391: Tcl_AppendResult(interp, spaces+NUM_SPACES-numSpaces, ! 392: (char *) NULL); ! 393: } ! 394: numSpaces -= NUM_SPACES; ! 395: } ! 396: Tcl_AppendResult(interp, infoPtr->help, (char *) NULL); ! 397: switch (infoPtr->type) { ! 398: case TK_ARGV_INT: { ! 399: sprintf(tmp, "%d", *((int *) infoPtr->dst)); ! 400: Tcl_AppendResult(interp, "\n\t\tDefault value: ", ! 401: tmp, (char *) NULL); ! 402: break; ! 403: } ! 404: case TK_ARGV_FLOAT: { ! 405: sprintf(tmp, "%lg", *((double *) infoPtr->dst)); ! 406: Tcl_AppendResult(interp, "\n\t\tDefault value: ", ! 407: tmp, (char *) NULL); ! 408: break; ! 409: } ! 410: case TK_ARGV_STRING: { ! 411: char *string; ! 412: ! 413: string = *((char **) infoPtr->dst); ! 414: if (string != NULL) { ! 415: Tcl_AppendResult(interp, "\n\t\tDefault value: \"", ! 416: string, "\"", (char *) NULL); ! 417: } ! 418: break; ! 419: } ! 420: default: { ! 421: break; ! 422: } ! 423: } ! 424: } ! 425: ! 426: if ((flags & TK_ARGV_NO_DEFAULTS) || (i > 0)) { ! 427: break; ! 428: } ! 429: Tcl_AppendResult(interp, "\nGeneric options for all commands:", ! 430: (char *) NULL); ! 431: } ! 432: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.