tkArgv.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:11k
源码类别:

通讯编程

开发平台:

Visual C++

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