static int AddFromString( Tcl_Interp *interp, /* Interpreter to use for reporting results. */ Tk_Window tkwin, /* Token for window: options are entered for * this window's main window. */ char *string, /* String containing option specifiers. */ int priority) /* Priority level to use for options in this * string, such as TK_USER_DEFAULT_PRIO or * TK_INTERACTIVE_PRIO. Must be between 0 and * TK_MAX_PRIO. */ { register char *src, *dst; char *name, *value; int lineNum; src = string; lineNum = 1; while (1) { /* * Skip leading white space and empty lines and comment lines, and * check for the end of the spec. */ while ((*src == ' ') || (*src == '\t')) { src++; } if ((*src == '#') || (*src == '!')) { do { src++; if ((src[0] == '\\') && (src[1] == '\n')) { src += 2; lineNum++; } } while ((*src != '\n') && (*src != 0)); } if (*src == '\n') { src++; lineNum++; continue; } if (*src == '\0') { break; } /* * Parse off the option name, collapsing out backslash-newline * sequences of course. */ dst = name = src; while (*src != ':') { if ((*src == '\0') || (*src == '\n')) { char buf[32 + TCL_INTEGER_SPACE]; sprintf(buf, "missing colon on line %d", lineNum); Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_ERROR; } if ((src[0] == '\\') && (src[1] == '\n')) { src += 2; lineNum++; } else { *dst = *src; dst++; src++; } } /* * Eliminate trailing white space on the name, and null-terminate * it. */ while ((dst != name) && ((dst[-1] == ' ') || (dst[-1] == '\t'))) { dst--; } *dst = '\0'; /* * Skip white space between the name and the value. */ src++; while ((*src == ' ') || (*src == '\t')) { src++; } if (*src == '\0') { char buf[32 + TCL_INTEGER_SPACE]; sprintf(buf, "missing value on line %d", lineNum); Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_ERROR; } /* * Parse off the value, squeezing out backslash-newline sequences * along the way. */ dst = value = src; while (*src != '\n') { if (*src == '\0') { char buf[32 + TCL_INTEGER_SPACE]; sprintf(buf, "missing newline on line %d", lineNum); Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_ERROR; } if ((src[0] == '\\') && (src[1] == '\n')) { src += 2; lineNum++; } else { *dst = *src; dst++; src++; } } *dst = 0; /* * Enter the option into the database. */ Tk_AddOption(tkwin, name, value, priority); src++; lineNum++; } return TCL_OK; }
int Tk_ParseArgv( Tcl_Interp *interp, /* Place to store error message. */ Tk_Window tkwin, /* Window to use for setting Tk options. NULL * means ignore Tk option specs. */ int *argcPtr, /* Number of arguments in argv. Modified to * hold # args left in argv at end. */ CONST char **argv, /* Array of arguments. Modified to hold those * that couldn't be processed here. */ Tk_ArgvInfo *argTable, /* Array of option descriptions */ int flags) /* Or'ed combination of various flag bits, * such as TK_ARGV_NO_DEFAULTS. */ { register Tk_ArgvInfo *infoPtr; /* Pointer to the current entry in the table * of argument descriptions. */ Tk_ArgvInfo *matchPtr; /* Descriptor that matches current argument. */ CONST char *curArg; /* Current argument */ register char c; /* Second character of current arg (used for * quick check for matching; use 2nd char. * because first char. will almost always be * '-'). */ int srcIndex; /* Location from which to read next argument * from argv. */ int dstIndex; /* Index into argv to which next unused * argument should be copied (never greater * than srcIndex). */ int argc; /* # arguments in argv still to process. */ size_t length; /* Number of characters in current argument. */ int i; if (flags & TK_ARGV_DONT_SKIP_FIRST_ARG) { srcIndex = dstIndex = 0; argc = *argcPtr; } else { srcIndex = dstIndex = 1; argc = *argcPtr-1; } while (argc > 0) { curArg = argv[srcIndex]; srcIndex++; argc--; length = strlen(curArg); if (length > 0) { c = curArg[1]; } else { c = 0; } /* * Loop throught the argument descriptors searching for one with the * matching key string. If found, leave a pointer to it in matchPtr. */ matchPtr = NULL; for (i = 0; i < 2; i++) { if (i == 0) { infoPtr = argTable; } else { infoPtr = defaultTable; } for (; (infoPtr != NULL) && (infoPtr->type != TK_ARGV_END); infoPtr++) { if (infoPtr->key == NULL) { continue; } if ((infoPtr->key[1] != c) || (strncmp(infoPtr->key, curArg, length) != 0)) { continue; } if ((tkwin == NULL) && ((infoPtr->type == TK_ARGV_CONST_OPTION) || (infoPtr->type == TK_ARGV_OPTION_VALUE) || (infoPtr->type == TK_ARGV_OPTION_NAME_VALUE))) { continue; } if (infoPtr->key[length] == 0) { matchPtr = infoPtr; goto gotMatch; } if (flags & TK_ARGV_NO_ABBREV) { continue; } if (matchPtr != NULL) { Tcl_AppendResult(interp, "ambiguous option \"", curArg, "\"", NULL); return TCL_ERROR; } matchPtr = infoPtr; } } if (matchPtr == NULL) { /* * Unrecognized argument. Just copy it down, unless the caller * prefers an error to be registered. */ if (flags & TK_ARGV_NO_LEFTOVERS) { Tcl_AppendResult(interp, "unrecognized argument \"", curArg, "\"", NULL); return TCL_ERROR; } argv[dstIndex] = curArg; dstIndex++; continue; } /* * Take the appropriate action based on the option type */ gotMatch: infoPtr = matchPtr; switch (infoPtr->type) { case TK_ARGV_CONSTANT: *((int *) infoPtr->dst) = PTR2INT(infoPtr->src); break; case TK_ARGV_INT: if (argc == 0) { goto missingArg; } else { char *endPtr; *((int *) infoPtr->dst) = strtol(argv[srcIndex], &endPtr, 0); if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) { Tcl_AppendResult(interp,"expected integer argument for \"", infoPtr->key, "\" but got \"", argv[srcIndex], "\"", NULL); return TCL_ERROR; } srcIndex++; argc--; } break; case TK_ARGV_STRING: if (argc == 0) { goto missingArg; } *((CONST char **)infoPtr->dst) = argv[srcIndex]; srcIndex++; argc--; break; case TK_ARGV_UID: if (argc == 0) { goto missingArg; } *((Tk_Uid *)infoPtr->dst) = Tk_GetUid(argv[srcIndex]); srcIndex++; argc--; break; case TK_ARGV_REST: *((int *) infoPtr->dst) = dstIndex; goto argsDone; case TK_ARGV_FLOAT: if (argc == 0) { goto missingArg; } else { char *endPtr; *((double *) infoPtr->dst) = strtod(argv[srcIndex], &endPtr); if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) { Tcl_AppendResult(interp, "expected floating-point ", "argument for \"", infoPtr->key, "\" but got \"", argv[srcIndex], "\"", NULL); return TCL_ERROR; } srcIndex++; argc--; } break; case TK_ARGV_FUNC: { typedef int (ArgvFunc)(char *, char *, CONST char *); ArgvFunc *handlerProc = (ArgvFunc *) infoPtr->src; if ((*handlerProc)(infoPtr->dst, infoPtr->key, argv[srcIndex])) { srcIndex++; argc--; } break; } case TK_ARGV_GENFUNC: { typedef int (ArgvGenFunc)(char *, Tcl_Interp *, char *, int, CONST char **); ArgvGenFunc *handlerProc = (ArgvGenFunc *) infoPtr->src; argc = (*handlerProc)(infoPtr->dst, interp, infoPtr->key, argc, argv+srcIndex); if (argc < 0) { return TCL_ERROR; } break; } case TK_ARGV_HELP: PrintUsage(interp, argTable, flags); return TCL_ERROR; case TK_ARGV_CONST_OPTION: Tk_AddOption(tkwin, infoPtr->dst, infoPtr->src, TK_INTERACTIVE_PRIO); break; case TK_ARGV_OPTION_VALUE: if (argc < 1) { goto missingArg; } Tk_AddOption(tkwin, infoPtr->dst, argv[srcIndex], TK_INTERACTIVE_PRIO); srcIndex++; argc--; break; case TK_ARGV_OPTION_NAME_VALUE: if (argc < 2) { Tcl_AppendResult(interp, "\"", curArg, "\" option requires two following arguments", NULL); return TCL_ERROR; } Tk_AddOption(tkwin, argv[srcIndex], argv[srcIndex+1], TK_INTERACTIVE_PRIO); srcIndex += 2; argc -= 2; break; default: { char buf[64 + TCL_INTEGER_SPACE]; sprintf(buf, "bad argument type %d in Tk_ArgvInfo", infoPtr->type); Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_ERROR; } } } /* * If we broke out of the loop because of an OPT_REST argument, copy the * remaining arguments down. */ argsDone: while (argc) { argv[dstIndex] = argv[srcIndex]; srcIndex++; dstIndex++; argc--; } argv[dstIndex] = NULL; *argcPtr = dstIndex; return TCL_OK; missingArg: Tcl_AppendResult(interp, "\"", curArg, "\" option requires an additional argument", NULL); return TCL_ERROR; }
int Tk_OptionObjCmd( ClientData clientData, /* Main window associated with interpreter. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of Tcl_Obj arguments. */ Tcl_Obj *const objv[]) /* Tcl_Obj arguments. */ { Tk_Window tkwin = clientData; int index, result; ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); static const char *const optionCmds[] = { "add", "clear", "get", "readfile", NULL }; enum optionVals { OPTION_ADD, OPTION_CLEAR, OPTION_GET, OPTION_READFILE }; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "cmd arg ?arg ...?"); return TCL_ERROR; } result = Tcl_GetIndexFromObj(interp, objv[1], optionCmds, "option", 0, &index); if (result != TCL_OK) { return result; } result = TCL_OK; switch ((enum optionVals) index) { case OPTION_ADD: { int priority; if ((objc != 4) && (objc != 5)) { Tcl_WrongNumArgs(interp, 2, objv, "pattern value ?priority?"); return TCL_ERROR; } if (objc == 4) { priority = TK_INTERACTIVE_PRIO; } else { priority = ParsePriority(interp, Tcl_GetString(objv[4])); if (priority < 0) { return TCL_ERROR; } } Tk_AddOption(tkwin, Tcl_GetString(objv[2]), Tcl_GetString(objv[3]), priority); break; } case OPTION_CLEAR: { TkMainInfo *mainPtr; if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } mainPtr = ((TkWindow *) tkwin)->mainPtr; if (mainPtr->optionRootPtr != NULL) { ClearOptionTree(mainPtr->optionRootPtr); mainPtr->optionRootPtr = NULL; } tsdPtr->cachedWindow = NULL; break; } case OPTION_GET: { Tk_Window window; Tk_Uid value; if (objc != 5) { Tcl_WrongNumArgs(interp, 2, objv, "window name class"); return TCL_ERROR; } window = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), tkwin); if (window == NULL) { return TCL_ERROR; } value = Tk_GetOption(window, Tcl_GetString(objv[3]), Tcl_GetString(objv[4])); if (value != NULL) { Tcl_SetResult(interp, (char *) value, TCL_STATIC); } break; } case OPTION_READFILE: { int priority; if ((objc != 3) && (objc != 4)) { Tcl_WrongNumArgs(interp, 2, objv, "fileName ?priority?"); return TCL_ERROR; } if (objc == 4) { priority = ParsePriority(interp, Tcl_GetString(objv[3])); if (priority < 0) { return TCL_ERROR; } } else { priority = TK_INTERACTIVE_PRIO; } result = ReadOptionFile(interp, tkwin, Tcl_GetString(objv[2]), priority); break; } } return result; }