4 * This file contains a procedure that handles table-based
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.
18 static char rcsid
[] = "$Header: /user6/ouster/wish/RCS/tkArgv.c,v 1.12 92/08/07 08:39:48 ouster Exp $ SPRITE (Berkeley)";
25 * Default table of argument descriptors. These are normally available
26 * in every application.
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
,
37 * Forward declarations for procedures defined in this file:
40 static void PrintUsage
_ANSI_ARGS_((Tcl_Interp
*interp
,
41 Tk_ArgvInfo
*argTable
, int flags
));
44 *----------------------------------------------------------------------
48 * Process an argv array according to a table of expected
49 * command-line options. See the manual page for more details.
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
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
65 *----------------------------------------------------------------------
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. */
82 register Tk_ArgvInfo
*infoPtr
;
83 /* Pointer to the current entry in the
84 * table of argument descriptions. */
85 Tk_ArgvInfo
*matchPtr
; /* Descriptor that matches current argument. */
86 char *curArg
; /* Current argument */
87 register char c
; /* Second character of current arg (used for
88 * quick check for matching; use 2nd char.
89 * because first char. will almost always
91 int srcIndex
; /* Location from which to read next argument
93 int dstIndex
; /* Index into argv to which next unused
94 * argument should be copied (never greater
96 int argc
; /* # arguments in argv still to process. */
97 int length
; /* Number of characters in current argument. */
100 if (flags
& TK_ARGV_DONT_SKIP_FIRST_ARG
) {
101 srcIndex
= dstIndex
= 0;
104 srcIndex
= dstIndex
= 1;
109 curArg
= argv
[srcIndex
];
113 length
= strlen(curArg
);
116 * Loop throught the argument descriptors searching for one with
117 * the matching key string. If found, leave a pointer to it in
122 for (i
= 0; i
< 2; i
++) {
126 infoPtr
= defaultTable
;
128 for (; infoPtr
->type
!= TK_ARGV_END
; infoPtr
++) {
129 if (infoPtr
->key
== NULL
) {
132 if ((infoPtr
->key
[1] != c
)
133 || (strncmp(infoPtr
->key
, curArg
, length
) != 0)) {
137 && ((infoPtr
->type
== TK_ARGV_CONST_OPTION
)
138 || (infoPtr
->type
== TK_ARGV_OPTION_VALUE
)
139 || (infoPtr
->type
== TK_ARGV_OPTION_NAME_VALUE
))) {
142 if (infoPtr
->key
[length
] == 0) {
146 if (flags
& TK_ARGV_NO_ABBREV
) {
149 if (matchPtr
!= NULL
) {
150 Tcl_AppendResult(interp
, "ambiguous option \"", curArg
,
151 "\"", (char *) NULL
);
157 if (matchPtr
== NULL
) {
160 * Unrecognized argument. Just copy it down, unless the caller
161 * prefers an error to be registered.
164 if (flags
& TK_ARGV_NO_LEFTOVERS
) {
165 Tcl_AppendResult(interp
, "unrecognized argument \"",
166 curArg
, "\"", (char *) NULL
);
169 argv
[dstIndex
] = curArg
;
175 * Take the appropriate action based on the option type
180 switch (infoPtr
->type
) {
181 case TK_ARGV_CONSTANT
:
182 *((int *) infoPtr
->dst
) = (int) infoPtr
->src
;
190 *((int *) infoPtr
->dst
) =
191 strtol(argv
[srcIndex
], &endPtr
, 0);
192 if ((endPtr
== argv
[srcIndex
]) || (*endPtr
!= 0)) {
193 Tcl_AppendResult(interp
, "expected integer argument ",
194 "for \"", infoPtr
->key
, "\" but got \"",
195 argv
[srcIndex
], "\"", (char *) NULL
);
206 *((char **)infoPtr
->dst
) = argv
[srcIndex
];
215 *((Tk_Uid
*)infoPtr
->dst
) = Tk_GetUid(argv
[srcIndex
]);
221 *((int *) infoPtr
->dst
) = dstIndex
;
229 *((double *) infoPtr
->dst
) =
230 strtod(argv
[srcIndex
], &endPtr
);
231 if ((endPtr
== argv
[srcIndex
]) || (*endPtr
!= 0)) {
232 Tcl_AppendResult(interp
, "expected floating-point ",
233 "argument for \"", infoPtr
->key
,
234 "\" but got \"", argv
[srcIndex
], "\"",
243 int (*handlerProc
)(char*, char*, char*);
245 handlerProc
= (int (*)(char*, char*, char*))infoPtr
->src
;
247 if ((*handlerProc
)(infoPtr
->dst
, infoPtr
->key
,
254 case TK_ARGV_GENFUNC
: {
255 int (*handlerProc
)(char*, Tcl_Interp
*, char*, int, char**);
257 handlerProc
= (int (*)(char*, Tcl_Interp
*, char*, int, char**))infoPtr
->src
;
259 argc
= (*handlerProc
)(infoPtr
->dst
, interp
, infoPtr
->key
,
260 argc
, argv
+srcIndex
);
267 PrintUsage (interp
, argTable
, flags
);
269 case TK_ARGV_CONST_OPTION
:
270 Tk_AddOption(tkwin
, infoPtr
->dst
, infoPtr
->src
,
271 TK_INTERACTIVE_PRIO
);
273 case TK_ARGV_OPTION_VALUE
:
277 Tk_AddOption(tkwin
, infoPtr
->dst
, argv
[srcIndex
],
278 TK_INTERACTIVE_PRIO
);
282 case TK_ARGV_OPTION_NAME_VALUE
:
284 Tcl_AppendResult(interp
, "\"", curArg
,
285 "\" option requires two following arguments",
289 Tk_AddOption(tkwin
, argv
[srcIndex
], argv
[srcIndex
+1],
290 TK_INTERACTIVE_PRIO
);
295 sprintf(interp
->result
, "bad argument type %d in Tk_ArgvInfo",
302 * If we broke out of the loop because of an OPT_REST argument,
303 * copy the remaining arguments down.
308 argv
[dstIndex
] = argv
[srcIndex
];
313 argv
[dstIndex
] = (char *) NULL
;
318 Tcl_AppendResult(interp
, "\"", curArg
,
319 "\" option requires an additional argument", (char *) NULL
);
324 *----------------------------------------------------------------------
328 * Generate a help string describing command-line options.
331 * Interp->result will be modified to hold a help string
332 * describing all the options in argTable, plus all those
333 * in the default table unless TK_ARGV_NO_DEFAULTS is
334 * specified in flags.
339 *----------------------------------------------------------------------
344 Tcl_Interp
*interp
, /* Place information in this interp's
346 Tk_ArgvInfo
*argTable
, /* Array of command-specific argument
348 int flags
/* If the TK_ARGV_NO_DEFAULTS bit is set
349 * in this word, then don't generate
350 * information for default options. */
353 register Tk_ArgvInfo
*infoPtr
;
354 int width
, i
, numSpaces
;
355 #define NUM_SPACES 20
356 static char spaces
[] = " ";
360 * First, compute the width of the widest option key, so that we
361 * can make everything line up.
365 for (i
= 0; i
< 2; i
++) {
366 for (infoPtr
= i
? defaultTable
: argTable
;
367 infoPtr
->type
!= TK_ARGV_END
; infoPtr
++) {
369 if (infoPtr
->key
== NULL
) {
372 length
= strlen(infoPtr
->key
);
373 if (length
> width
) {
379 Tcl_AppendResult(interp
, "Command-specific options:", (char *) NULL
);
381 for (infoPtr
= i
? defaultTable
: argTable
;
382 infoPtr
->type
!= TK_ARGV_END
; infoPtr
++) {
383 if ((infoPtr
->type
== TK_ARGV_HELP
) && (infoPtr
->key
== NULL
)) {
384 Tcl_AppendResult(interp
, "\n", infoPtr
->help
, (char *) NULL
);
387 Tcl_AppendResult(interp
, "\n ", infoPtr
->key
, ":", (char *) NULL
);
388 numSpaces
= width
+ 1 - strlen(infoPtr
->key
);
389 while (numSpaces
> 0) {
390 if (numSpaces
>= NUM_SPACES
) {
391 Tcl_AppendResult(interp
, spaces
, (char *) NULL
);
393 Tcl_AppendResult(interp
, spaces
+NUM_SPACES
-numSpaces
,
396 numSpaces
-= NUM_SPACES
;
398 Tcl_AppendResult(interp
, infoPtr
->help
, (char *) NULL
);
399 switch (infoPtr
->type
) {
401 sprintf(tmp
, "%d", *((int *) infoPtr
->dst
));
402 Tcl_AppendResult(interp
, "\n\t\tDefault value: ",
406 case TK_ARGV_FLOAT
: {
407 sprintf(tmp
, "%lg", *((double *) infoPtr
->dst
));
408 Tcl_AppendResult(interp
, "\n\t\tDefault value: ",
412 case TK_ARGV_STRING
: {
415 string
= *((char **) infoPtr
->dst
);
416 if (string
!= NULL
) {
417 Tcl_AppendResult(interp
, "\n\t\tDefault value: \"",
418 string
, "\"", (char *) NULL
);
428 if ((flags
& TK_ARGV_NO_DEFAULTS
) || (i
> 0)) {
431 Tcl_AppendResult(interp
, "\nGeneric options for all commands:",