summaryrefslogtreecommitdiffstats
path: root/tk8.6/generic/tkArgv.c
diff options
context:
space:
mode:
Diffstat (limited to 'tk8.6/generic/tkArgv.c')
-rw-r--r--tk8.6/generic/tkArgv.c417
1 files changed, 417 insertions, 0 deletions
diff --git a/tk8.6/generic/tkArgv.c b/tk8.6/generic/tkArgv.c
new file mode 100644
index 0000000..6c2c5c5
--- /dev/null
+++ b/tk8.6/generic/tkArgv.c
@@ -0,0 +1,417 @@
+/*
+ * tkArgv.c --
+ *
+ * This file contains a function that handles table-based argv-argc
+ * parsing.
+ *
+ * Copyright (c) 1990-1994 The Regents of the University of California.
+ * Copyright (c) 1994-1997 Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ */
+
+#include "tkInt.h"
+
+/*
+ * Default table of argument descriptors. These are normally available in
+ * every application.
+ */
+
+static const Tk_ArgvInfo defaultTable[] = {
+ {"-help", TK_ARGV_HELP, NULL, NULL,
+ "Print summary of command-line options and abort"},
+ {NULL, TK_ARGV_END, NULL, NULL, NULL}
+};
+
+/*
+ * Forward declarations for functions defined in this file:
+ */
+
+static void PrintUsage(Tcl_Interp *interp, const Tk_ArgvInfo *argTable,
+ int flags);
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tk_ParseArgv --
+ *
+ * Process an argv array according to a table of expected command-line
+ * options. See the manual page for more details.
+ *
+ * Results:
+ * The return value is a standard Tcl return value. If an error occurs
+ * then an error message is left in the interp's result. Under normal
+ * conditions, both *argcPtr and *argv are modified to return the
+ * arguments that couldn't be processed here (they didn't match the
+ * option table, or followed an TK_ARGV_REST argument).
+ *
+ * Side effects:
+ * Variables may be modified, resources may be entered for tkwin, or
+ * functions may be called. It all depends on the arguments and their
+ * entries in argTable. See the user documentation for details.
+ *
+ *----------------------------------------------------------------------
+ */
+
+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. */
+ const Tk_ArgvInfo *argTable, /* Array of option descriptions */
+ int flags) /* Or'ed combination of various flag bits,
+ * such as TK_ARGV_NO_DEFAULTS. */
+{
+ register const Tk_ArgvInfo *infoPtr;
+ /* Pointer to the current entry in the table
+ * of argument descriptions. */
+ const 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. */
+ char *endPtr; /* Used for identifying junk in arguments. */
+ 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_SetObjResult(interp, Tcl_ObjPrintf(
+ "ambiguous option \"%s\"", curArg));
+ Tcl_SetErrorCode(interp, "TK", "ARG", "AMBIGUOUS", 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_SetObjResult(interp, Tcl_ObjPrintf(
+ "unrecognized argument \"%s\"", curArg));
+ Tcl_SetErrorCode(interp, "TK", "ARG", "UNRECOGNIZED", 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;
+ }
+ *((int *) infoPtr->dst) = strtol(argv[srcIndex], &endPtr, 0);
+ if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "expected %s argument for \"%s\" but got \"%s\"",
+ "integer", infoPtr->key, argv[srcIndex]));
+ Tcl_SetErrorCode(interp, "TK", "ARG", "INTEGER", curArg,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;
+ }
+ *((double *) infoPtr->dst) = strtod(argv[srcIndex], &endPtr);
+ if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "expected %s argument for \"%s\" but got \"%s\"",
+ "floating-point", infoPtr->key, argv[srcIndex]));
+ Tcl_SetErrorCode(interp, "TK", "ARG", "FLOAT", curArg, NULL);
+ return TCL_ERROR;
+ }
+ srcIndex++;
+ argc--;
+ break;
+ case TK_ARGV_FUNC: {
+ typedef int (ArgvFunc)(char *, const 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 *, const 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);
+ Tcl_SetErrorCode(interp, "TK", "ARG", "HELP", NULL);
+ 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_SetObjResult(interp, Tcl_ObjPrintf(
+ "\"%s\" option requires two following arguments",
+ curArg));
+ Tcl_SetErrorCode(interp, "TK", "ARG", "NAME_VALUE", curArg,
+ NULL);
+ return TCL_ERROR;
+ }
+ Tk_AddOption(tkwin, argv[srcIndex], argv[srcIndex+1],
+ TK_INTERACTIVE_PRIO);
+ srcIndex += 2;
+ argc -= 2;
+ break;
+ default:
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "bad argument type %d in Tk_ArgvInfo", infoPtr->type));
+ Tcl_SetErrorCode(interp, "TK", "API_ABUSE", NULL);
+ 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_SetObjResult(interp, Tcl_ObjPrintf(
+ "\"%s\" option requires an additional argument", curArg));
+ Tcl_SetErrorCode(interp, "TK", "ARG", "MISSING", curArg, NULL);
+ return TCL_ERROR;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * PrintUsage --
+ *
+ * Generate a help string describing command-line options.
+ *
+ * Results:
+ * The interp's result will be modified to hold a help string describing
+ * all the options in argTable, plus all those in the default table
+ * unless TK_ARGV_NO_DEFAULTS is specified in flags.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+PrintUsage(
+ Tcl_Interp *interp, /* Place information in this interp's result
+ * area. */
+ const Tk_ArgvInfo *argTable,/* Array of command-specific argument
+ * descriptions. */
+ int flags) /* If the TK_ARGV_NO_DEFAULTS bit is set in
+ * this word, then don't generate information
+ * for default options. */
+{
+ register const Tk_ArgvInfo *infoPtr;
+ size_t width, i, numSpaces;
+ Tcl_Obj *message;
+
+ /*
+ * First, compute the width of the widest option key, so that we can make
+ * everything line up.
+ */
+
+ width = 4;
+ for (i = 0; i < 2; i++) {
+ for (infoPtr = i ? defaultTable : argTable;
+ infoPtr->type != TK_ARGV_END; infoPtr++) {
+ size_t length;
+
+ if (infoPtr->key == NULL) {
+ continue;
+ }
+ length = strlen(infoPtr->key);
+ if (length > width) {
+ width = length;
+ }
+ }
+ }
+
+ message = Tcl_NewStringObj("Command-specific options:", -1);
+ for (i = 0; ; i++) {
+ for (infoPtr = i ? defaultTable : argTable;
+ infoPtr->type != TK_ARGV_END; infoPtr++) {
+ if ((infoPtr->type == TK_ARGV_HELP) && (infoPtr->key == NULL)) {
+ Tcl_AppendPrintfToObj(message, "\n%s", infoPtr->help);
+ continue;
+ }
+ Tcl_AppendPrintfToObj(message, "\n %s:", infoPtr->key);
+ numSpaces = width + 1 - strlen(infoPtr->key);
+ while (numSpaces-- > 0) {
+ Tcl_AppendToObj(message, " ", 1);
+ }
+ Tcl_AppendToObj(message, infoPtr->help, -1);
+ switch (infoPtr->type) {
+ case TK_ARGV_INT:
+ Tcl_AppendPrintfToObj(message, "\n\t\tDefault value: %d",
+ *((int *) infoPtr->dst));
+ break;
+ case TK_ARGV_FLOAT:
+ Tcl_AppendPrintfToObj(message, "\n\t\tDefault value: %f",
+ *((double *) infoPtr->dst));
+ break;
+ case TK_ARGV_STRING: {
+ char *string = *((char **) infoPtr->dst);
+
+ if (string != NULL) {
+ Tcl_AppendPrintfToObj(message,
+ "\n\t\tDefault value: \"%s\"", string);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if ((flags & TK_ARGV_NO_DEFAULTS) || (i > 0)) {
+ break;
+ }
+ Tcl_AppendToObj(message, "\nGeneric options for all commands:", -1);
+ }
+ Tcl_SetObjResult(interp, message);
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 78
+ * End:
+ */