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 *----------------------------------------------------------------------
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. */
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
90 int srcIndex
; /* Location from which to read next argument
92 int dstIndex
; /* Index into argv to which next unused
93 * argument should be copied (never greater
95 int argc
; /* # arguments in argv still to process. */
96 int length
; /* Number of characters in current argument. */
99 if (flags
& TK_ARGV_DONT_SKIP_FIRST_ARG
) {
100 srcIndex
= dstIndex
= 0;
103 srcIndex
= dstIndex
= 1;
108 curArg
= argv
[srcIndex
];
112 length
= strlen(curArg
);
115 * Loop throught the argument descriptors searching for one with
116 * the matching key string. If found, leave a pointer to it in
121 for (i
= 0; i
< 2; i
++) {
125 infoPtr
= defaultTable
;
127 for (; infoPtr
->type
!= TK_ARGV_END
; infoPtr
++) {
128 if (infoPtr
->key
== NULL
) {
131 if ((infoPtr
->key
[1] != c
)
132 || (strncmp(infoPtr
->key
, curArg
, length
) != 0)) {
136 && ((infoPtr
->type
== TK_ARGV_CONST_OPTION
)
137 || (infoPtr
->type
== TK_ARGV_OPTION_VALUE
)
138 || (infoPtr
->type
== TK_ARGV_OPTION_NAME_VALUE
))) {
141 if (infoPtr
->key
[length
] == 0) {
145 if (flags
& TK_ARGV_NO_ABBREV
) {
148 if (matchPtr
!= NULL
) {
149 Tcl_AppendResult(interp
, "ambiguous option \"", curArg
,
150 "\"", (char *) NULL
);
156 if (matchPtr
== NULL
) {
159 * Unrecognized argument. Just copy it down, unless the caller
160 * prefers an error to be registered.
163 if (flags
& TK_ARGV_NO_LEFTOVERS
) {
164 Tcl_AppendResult(interp
, "unrecognized argument \"",
165 curArg
, "\"", (char *) NULL
);
168 argv
[dstIndex
] = curArg
;
174 * Take the appropriate action based on the option type
179 switch (infoPtr
->type
) {
180 case TK_ARGV_CONSTANT
:
181 *((int *) infoPtr
->dst
) = (int) infoPtr
->src
;
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
);
205 *((char **)infoPtr
->dst
) = argv
[srcIndex
];
214 *((Tk_Uid
*)infoPtr
->dst
) = Tk_GetUid(argv
[srcIndex
]);
220 *((int *) infoPtr
->dst
) = dstIndex
;
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
], "\"",
242 int (*handlerProc
)();
244 handlerProc
= (int (*)())infoPtr
->src
;
246 if ((*handlerProc
)(infoPtr
->dst
, infoPtr
->key
,
253 case TK_ARGV_GENFUNC
: {
254 int (*handlerProc
)();
256 handlerProc
= (int (*)())infoPtr
->src
;
258 argc
= (*handlerProc
)(infoPtr
->dst
, interp
, infoPtr
->key
,
259 argc
, argv
+srcIndex
);
266 PrintUsage (interp
, argTable
, flags
);
268 case TK_ARGV_CONST_OPTION
:
269 Tk_AddOption(tkwin
, infoPtr
->dst
, infoPtr
->src
,
270 TK_INTERACTIVE_PRIO
);
272 case TK_ARGV_OPTION_VALUE
:
276 Tk_AddOption(tkwin
, infoPtr
->dst
, argv
[srcIndex
],
277 TK_INTERACTIVE_PRIO
);
281 case TK_ARGV_OPTION_NAME_VALUE
:
283 Tcl_AppendResult(interp
, "\"", curArg
,
284 "\" option requires two following arguments",
288 Tk_AddOption(tkwin
, argv
[srcIndex
], argv
[srcIndex
+1],
289 TK_INTERACTIVE_PRIO
);
294 sprintf(interp
->result
, "bad argument type %d in Tk_ArgvInfo",
301 * If we broke out of the loop because of an OPT_REST argument,
302 * copy the remaining arguments down.
307 argv
[dstIndex
] = argv
[srcIndex
];
312 argv
[dstIndex
] = (char *) NULL
;
317 Tcl_AppendResult(interp
, "\"", curArg
,
318 "\" option requires an additional argument", (char *) NULL
);
323 *----------------------------------------------------------------------
327 * Generate a help string describing command-line options.
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.
338 *----------------------------------------------------------------------
342 PrintUsage(interp
, argTable
, flags
)
343 Tcl_Interp
*interp
; /* Place information in this interp's
345 Tk_ArgvInfo
*argTable
; /* Array of command-specific argument
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. */
351 register Tk_ArgvInfo
*infoPtr
;
352 int width
, i
, numSpaces
;
353 #define NUM_SPACES 20
354 static char spaces
[] = " ";
358 * First, compute the width of the widest option key, so that we
359 * can make everything line up.
363 for (i
= 0; i
< 2; i
++) {
364 for (infoPtr
= i
? defaultTable
: argTable
;
365 infoPtr
->type
!= TK_ARGV_END
; infoPtr
++) {
367 if (infoPtr
->key
== NULL
) {
370 length
= strlen(infoPtr
->key
);
371 if (length
> width
) {
377 Tcl_AppendResult(interp
, "Command-specific options:", (char *) NULL
);
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
);
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
);
391 Tcl_AppendResult(interp
, spaces
+NUM_SPACES
-numSpaces
,
394 numSpaces
-= NUM_SPACES
;
396 Tcl_AppendResult(interp
, infoPtr
->help
, (char *) NULL
);
397 switch (infoPtr
->type
) {
399 sprintf(tmp
, "%d", *((int *) infoPtr
->dst
));
400 Tcl_AppendResult(interp
, "\n\t\tDefault value: ",
404 case TK_ARGV_FLOAT
: {
405 sprintf(tmp
, "%lg", *((double *) infoPtr
->dst
));
406 Tcl_AppendResult(interp
, "\n\t\tDefault value: ",
410 case TK_ARGV_STRING
: {
413 string
= *((char **) infoPtr
->dst
);
414 if (string
!= NULL
) {
415 Tcl_AppendResult(interp
, "\n\t\tDefault value: \"",
416 string
, "\"", (char *) NULL
);
426 if ((flags
& TK_ARGV_NO_DEFAULTS
) || (i
> 0)) {
429 Tcl_AppendResult(interp
, "\nGeneric options for all commands:",