]> cvs.zerfleddert.de Git - micropolis/blob - src/tk/tkargv.c
Fixes for compilation with gcc 15
[micropolis] / src / tk / tkargv.c
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 \f
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 (
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 {
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
90 * be '-'). */
91 int srcIndex; /* Location from which to read next argument
92 * from argv. */
93 int dstIndex; /* Index into argv to which next unused
94 * argument should be copied (never greater
95 * than srcIndex). */
96 int argc; /* # arguments in argv still to process. */
97 int length; /* Number of characters in current argument. */
98 int i;
99
100 if (flags & TK_ARGV_DONT_SKIP_FIRST_ARG) {
101 srcIndex = dstIndex = 0;
102 argc = *argcPtr;
103 } else {
104 srcIndex = dstIndex = 1;
105 argc = *argcPtr-1;
106 }
107
108 while (argc > 0) {
109 curArg = argv[srcIndex];
110 srcIndex++;
111 argc--;
112 c = curArg[1];
113 length = strlen(curArg);
114
115 /*
116 * Loop throught the argument descriptors searching for one with
117 * the matching key string. If found, leave a pointer to it in
118 * matchPtr.
119 */
120
121 matchPtr = NULL;
122 for (i = 0; i < 2; i++) {
123 if (i == 0) {
124 infoPtr = argTable;
125 } else {
126 infoPtr = defaultTable;
127 }
128 for (; infoPtr->type != TK_ARGV_END; infoPtr++) {
129 if (infoPtr->key == NULL) {
130 continue;
131 }
132 if ((infoPtr->key[1] != c)
133 || (strncmp(infoPtr->key, curArg, length) != 0)) {
134 continue;
135 }
136 if ((tkwin == NULL)
137 && ((infoPtr->type == TK_ARGV_CONST_OPTION)
138 || (infoPtr->type == TK_ARGV_OPTION_VALUE)
139 || (infoPtr->type == TK_ARGV_OPTION_NAME_VALUE))) {
140 continue;
141 }
142 if (infoPtr->key[length] == 0) {
143 matchPtr = infoPtr;
144 goto gotMatch;
145 }
146 if (flags & TK_ARGV_NO_ABBREV) {
147 continue;
148 }
149 if (matchPtr != NULL) {
150 Tcl_AppendResult(interp, "ambiguous option \"", curArg,
151 "\"", (char *) NULL);
152 return TCL_ERROR;
153 }
154 matchPtr = infoPtr;
155 }
156 }
157 if (matchPtr == NULL) {
158
159 /*
160 * Unrecognized argument. Just copy it down, unless the caller
161 * prefers an error to be registered.
162 */
163
164 if (flags & TK_ARGV_NO_LEFTOVERS) {
165 Tcl_AppendResult(interp, "unrecognized argument \"",
166 curArg, "\"", (char *) NULL);
167 return TCL_ERROR;
168 }
169 argv[dstIndex] = curArg;
170 dstIndex++;
171 continue;
172 }
173
174 /*
175 * Take the appropriate action based on the option type
176 */
177
178 gotMatch:
179 infoPtr = matchPtr;
180 switch (infoPtr->type) {
181 case TK_ARGV_CONSTANT:
182 *((int *) infoPtr->dst) = (int) infoPtr->src;
183 break;
184 case TK_ARGV_INT:
185 if (argc == 0) {
186 goto missingArg;
187 } else {
188 char *endPtr;
189
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);
196 return TCL_ERROR;
197 }
198 srcIndex++;
199 argc--;
200 }
201 break;
202 case TK_ARGV_STRING:
203 if (argc == 0) {
204 goto missingArg;
205 } else {
206 *((char **)infoPtr->dst) = argv[srcIndex];
207 srcIndex++;
208 argc--;
209 }
210 break;
211 case TK_ARGV_UID:
212 if (argc == 0) {
213 goto missingArg;
214 } else {
215 *((Tk_Uid *)infoPtr->dst) = Tk_GetUid(argv[srcIndex]);
216 srcIndex++;
217 argc--;
218 }
219 break;
220 case TK_ARGV_REST:
221 *((int *) infoPtr->dst) = dstIndex;
222 goto argsDone;
223 case TK_ARGV_FLOAT:
224 if (argc == 0) {
225 goto missingArg;
226 } else {
227 char *endPtr;
228
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], "\"",
235 (char *) NULL);
236 return TCL_ERROR;
237 }
238 srcIndex++;
239 argc--;
240 }
241 break;
242 case TK_ARGV_FUNC: {
243 int (*handlerProc)(char*, char*, char*);
244
245 handlerProc = (int (*)(char*, char*, char*))infoPtr->src;
246
247 if ((*handlerProc)(infoPtr->dst, infoPtr->key,
248 argv[srcIndex])) {
249 srcIndex += 1;
250 argc -= 1;
251 }
252 break;
253 }
254 case TK_ARGV_GENFUNC: {
255 int (*handlerProc)(char*, Tcl_Interp*, char*, int, char**);
256
257 handlerProc = (int (*)(char*, Tcl_Interp*, char*, int, char**))infoPtr->src;
258
259 argc = (*handlerProc)(infoPtr->dst, interp, infoPtr->key,
260 argc, argv+srcIndex);
261 if (argc < 0) {
262 return TCL_ERROR;
263 }
264 break;
265 }
266 case TK_ARGV_HELP:
267 PrintUsage (interp, argTable, flags);
268 return TCL_ERROR;
269 case TK_ARGV_CONST_OPTION:
270 Tk_AddOption(tkwin, infoPtr->dst, infoPtr->src,
271 TK_INTERACTIVE_PRIO);
272 break;
273 case TK_ARGV_OPTION_VALUE:
274 if (argc < 1) {
275 goto missingArg;
276 }
277 Tk_AddOption(tkwin, infoPtr->dst, argv[srcIndex],
278 TK_INTERACTIVE_PRIO);
279 srcIndex++;
280 argc--;
281 break;
282 case TK_ARGV_OPTION_NAME_VALUE:
283 if (argc < 2) {
284 Tcl_AppendResult(interp, "\"", curArg,
285 "\" option requires two following arguments",
286 (char *) NULL);
287 return TCL_ERROR;
288 }
289 Tk_AddOption(tkwin, argv[srcIndex], argv[srcIndex+1],
290 TK_INTERACTIVE_PRIO);
291 srcIndex += 2;
292 argc -= 2;
293 break;
294 default:
295 sprintf(interp->result, "bad argument type %d in Tk_ArgvInfo",
296 infoPtr->type);
297 return TCL_ERROR;
298 }
299 }
300
301 /*
302 * If we broke out of the loop because of an OPT_REST argument,
303 * copy the remaining arguments down.
304 */
305
306 argsDone:
307 while (argc) {
308 argv[dstIndex] = argv[srcIndex];
309 srcIndex++;
310 dstIndex++;
311 argc--;
312 }
313 argv[dstIndex] = (char *) NULL;
314 *argcPtr = dstIndex;
315 return TCL_OK;
316
317 missingArg:
318 Tcl_AppendResult(interp, "\"", curArg,
319 "\" option requires an additional argument", (char *) NULL);
320 return TCL_ERROR;
321 }
322 \f
323 /*
324 *----------------------------------------------------------------------
325 *
326 * PrintUsage --
327 *
328 * Generate a help string describing command-line options.
329 *
330 * Results:
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.
335 *
336 * Side effects:
337 * None.
338 *
339 *----------------------------------------------------------------------
340 */
341
342 static void
343 PrintUsage (
344 Tcl_Interp *interp, /* Place information in this interp's
345 * result area. */
346 Tk_ArgvInfo *argTable, /* Array of command-specific argument
347 * descriptions. */
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. */
351 )
352 {
353 register Tk_ArgvInfo *infoPtr;
354 int width, i, numSpaces;
355 #define NUM_SPACES 20
356 static char spaces[] = " ";
357 char tmp[30];
358
359 /*
360 * First, compute the width of the widest option key, so that we
361 * can make everything line up.
362 */
363
364 width = 4;
365 for (i = 0; i < 2; i++) {
366 for (infoPtr = i ? defaultTable : argTable;
367 infoPtr->type != TK_ARGV_END; infoPtr++) {
368 int length;
369 if (infoPtr->key == NULL) {
370 continue;
371 }
372 length = strlen(infoPtr->key);
373 if (length > width) {
374 width = length;
375 }
376 }
377 }
378
379 Tcl_AppendResult(interp, "Command-specific options:", (char *) NULL);
380 for (i = 0; ; i++) {
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);
385 continue;
386 }
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);
392 } else {
393 Tcl_AppendResult(interp, spaces+NUM_SPACES-numSpaces,
394 (char *) NULL);
395 }
396 numSpaces -= NUM_SPACES;
397 }
398 Tcl_AppendResult(interp, infoPtr->help, (char *) NULL);
399 switch (infoPtr->type) {
400 case TK_ARGV_INT: {
401 sprintf(tmp, "%d", *((int *) infoPtr->dst));
402 Tcl_AppendResult(interp, "\n\t\tDefault value: ",
403 tmp, (char *) NULL);
404 break;
405 }
406 case TK_ARGV_FLOAT: {
407 sprintf(tmp, "%lg", *((double *) infoPtr->dst));
408 Tcl_AppendResult(interp, "\n\t\tDefault value: ",
409 tmp, (char *) NULL);
410 break;
411 }
412 case TK_ARGV_STRING: {
413 char *string;
414
415 string = *((char **) infoPtr->dst);
416 if (string != NULL) {
417 Tcl_AppendResult(interp, "\n\t\tDefault value: \"",
418 string, "\"", (char *) NULL);
419 }
420 break;
421 }
422 default: {
423 break;
424 }
425 }
426 }
427
428 if ((flags & TK_ARGV_NO_DEFAULTS) || (i > 0)) {
429 break;
430 }
431 Tcl_AppendResult(interp, "\nGeneric options for all commands:",
432 (char *) NULL);
433 }
434 }
Impressum, Datenschutz