|
|
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.