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