modules/up/src/util/Argv.cc
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- ParseArgv
- PrintUsage
1 /*
2 * Argv.c --
3 *
4 * Targvle 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 This software is copyrighted by the Regents of the University of
11 California, Sun Microsystems, Inc., and other parties. The following
12 terms apply to all files associated with the software unless explicitly
13 disclaimed in individual files.
14
15 The authors hereby grant permission to use, copy, modify, distribute,
16 and license this software and its documentation for any purpose, provided
17 that existing copyright notices are retained in all copies and that this
18 notice is included verbatim in any distributions. No written agreement,
19 license, or royalty fee is required for any of the authorized uses.
20 Modifications to this software may be copyrighted by their authors
21 and need not follow the licensing terms described here, provided that
22 the new terms are clearly indicated on the first page of each file where
23 they apply.
24
25 IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
26 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
27 ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
28 DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
30
31 THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
32 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
33 FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
34 IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
35 NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
36 MODIFICATIONS.
37
38 RESTRICTED RIGHTS: Use, duplication or disclosure by the government
39 is subject to the restrictions as set forth in subparagraph (c) (1) (ii)
40 of the Rights in Technical Data and Computer Software Clause as DFARS
41 252.227-7013 and FAR 52.227-19.
42 *
43 */
44
45 #include "config.h"
46 #include <iostream.h>
47 #include <cstring>
48 #include <cstdlib>
49 #include "Argv.hh"
50 #include "version.hh" /* For version control */
51
52 /*
53 * Default table of argument descriptors. These are normally available
54 * in every application.
55 */
56
57 static ArgvInfo defaultTable[] = {
58 {"-help", ARGV_HELP, (char *) NULL, (char *) NULL,
59 "Print summary of command-line options and abort"},
60 {NULL, ARGV_END, (char *) NULL, (char *) NULL,
61 (char *) NULL}
62 };
63
64 /*
65 * Forward declarations for procedures defined in this file:
66 */
67
68 static void PrintUsage(ArgvInfo *argTable, int flags);
69
70 /*
71 *----------------------------------------------------------------------
72 *
73 * ParseArgv --
74 *
75 * Process an argv array according to a table of expected
76 * command-line options. See the manual page for more details.
77 *
78 * Results:
79 * Under normal conditions, both *argcPtr and *argv are modified
80 * to return the arguments that couldn't be processed here (they
81 * didn't match the option table, or followed an ARGV_REST
82 * argument).
83 *
84 * Side effects:
85 * Variables may be modified, or procedures may be called. It
86 * all depends on the arguments
87 * and their entries in argTable. See the user documentation
88 * for details.
89 *
90 *----------------------------------------------------------------------
91 */
92
93 int ParseArgv(int *argcPtr, char **argv, ArgvInfo *argTable, int flags)
/* [<][>][^][v][top][bottom][index][help] */
94 /* argcPtr: Number of arguments in argv. Modified
95 * to hold # args left in argv at end. */
96 /* argv: Array of arguments. Modified to hold
97 * those that couldn't be processed here. */
98 /* argTable: Array of option descriptions */
99 /* flags: Or'ed combination of various flag bits,
100 * such as ARGV_NO_DEFAULTS. */
101 {
102 register ArgvInfo *infoPtr;
103 /* Pointer to the current entry in the
104 * table of argument descriptions. */
105 ArgvInfo *matchPtr; /* Descriptor that matches current argument. */
106 char *curArg; /* Current argument */
107 register char c; /* Second character of current arg (used for
108 * quick check for matching; use 2nd char.
109 * because first char. will almost always
110 * be '-'). */
111 int srcIndex; /* Location from which to read next argument
112 * from argv. */
113 int dstIndex; /* Index into argv to which next unused
114 * argument should be copied (never greater
115 * than srcIndex). */
116 int argc; /* # arguments in argv still to process. */
117 int length; /* Number of characters in current argument. */
118 int i;
119
120 /* Try to fill the name of current program into ProjectGoal[64] -- wlee@ISI.EDU */
121 int len = strlen(argv[0]);
122 char *pGoal = argv[0] + len;
123 while (*pGoal != '/' && *pGoal != '\\' && --len >= 0) pGoal--;
124 strcpy(ProjectGoal, pGoal);
125
126 if (flags & ARGV_DONT_SKIP_FIRST_ARG) {
127 srcIndex = dstIndex = 0;
128 argc = *argcPtr;
129 } else {
130 srcIndex = dstIndex = 1;
131 argc = *argcPtr-1;
132 }
133
134 while (argc > 0) {
135 curArg = argv[srcIndex];
136 srcIndex++;
137 argc--;
138 length = strlen(curArg);
139 if (length > 0) {
140 c = curArg[1];
141 } else {
142 c = 0;
143 }
144
145 /*
146 * Loop throught the argument descriptors searching for one with
147 * the matching key string. If found, leave a pointer to it in
148 * matchPtr.
149 */
150
151 matchPtr = NULL;
152 for (i = 0; i < 2; i++) {
153 if (i == 0) {
154 infoPtr = argTable;
155 } else {
156 infoPtr = defaultTable;
157 }
158 for (; (infoPtr != NULL) && (infoPtr->type != ARGV_END);
159 infoPtr++) {
160 if (infoPtr->key == NULL) {
161 continue;
162 }
163 if ((infoPtr->key[1] != c)
164 || (strncmp(infoPtr->key, curArg, length) != 0)) {
165 continue;
166 }
167 if (infoPtr->key[length] == 0) {
168 matchPtr = infoPtr;
169 goto gotMatch;
170 }
171 if (flags & ARGV_NO_ABBREV) {
172 continue;
173 }
174 if (matchPtr != NULL) {
175 cerr << "ambiguous option \"" << curArg << "\"";
176 return ARGV_ERROR;
177 }
178 matchPtr = infoPtr;
179 }
180 }
181 if (matchPtr == NULL) {
182
183 /*
184 * Unrecognized argument. Just copy it down, unless the caller
185 * prefers an error to be registered.
186 */
187
188 if (flags & ARGV_NO_LEFTOVERS) {
189 cerr << "unrecognized argument \"" << curArg << "\"";
190 return ARGV_ERROR;
191 }
192 argv[dstIndex] = curArg;
193 dstIndex++;
194 continue;
195 }
196
197 /*
198 * Take the appropriate action based on the option type
199 */
200
201 gotMatch:
202 infoPtr = matchPtr;
203 switch (infoPtr->type) {
204 case ARGV_BOOL:
205 *((bool *) infoPtr->dst) = ! *((bool *) infoPtr->dst);
206 break;
207 case ARGV_CONSTANT:
208 *((int *) infoPtr->dst) = (int) infoPtr->src;
209 break;
210 case ARGV_INT:
211 if (argc == 0) {
212 goto missingArg;
213 } else {
214 char *endPtr;
215
216 *((int *) infoPtr->dst) =
217 strtol(argv[srcIndex], &endPtr, 0);
218 if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) {
219 cerr << "expected integer argument for \""
220 << infoPtr->key << "\" but got \""
221 << argv[srcIndex] << "\"";
222 return ARGV_ERROR;
223 }
224 srcIndex++;
225 argc--;
226 }
227 break;
228 case ARGV_STRING:
229 if (argc == 0) {
230 goto missingArg;
231 } else {
232 *((char **)infoPtr->dst) = argv[srcIndex];
233 srcIndex++;
234 argc--;
235 }
236 break;
237 case ARGV_REST:
238 *((int *) infoPtr->dst) = dstIndex;
239 goto argsDone;
240 case ARGV_FLOAT:
241 if (argc == 0) {
242 goto missingArg;
243 } else {
244 char *endPtr;
245
246 *((double *) infoPtr->dst) =
247 strtod(argv[srcIndex], &endPtr);
248 if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) {
249 cerr << "expected floating-point argument for \""
250 << infoPtr->key << "\" but got \""
251 << argv[srcIndex] << "\"";
252 return ARGV_ERROR;
253 }
254 srcIndex++;
255 argc--;
256 }
257 break;
258 case ARGV_FUNC: {
259 int (*handlerProc)(...);
260
261 handlerProc = (int (*)(...))infoPtr->src;
262
263 if ((*handlerProc)(infoPtr->dst, infoPtr->key,
264 argv[srcIndex])) {
265 srcIndex += 1;
266 argc -= 1;
267 }
268 break;
269 }
270 case ARGV_GENFUNC: {
271 int (*handlerProc)(...);
272
273 handlerProc = (int (*)(...))infoPtr->src;
274
275 argc = (*handlerProc)(infoPtr->dst, infoPtr->key,
276 argc, argv+srcIndex);
277 if (argc < 0) {
278 return ARGV_ERROR;
279 }
280 break;
281 }
282 case ARGV_HELP:
283 PrintUsage (argTable, flags);
284 return ARGV_ERROR;
285 default:
286 cerr << "bad argument type %d in ArgvInfo" << infoPtr->type;
287 return ARGV_ERROR;
288 }
289 }
290
291 /*
292 * If we broke out of the loop because of an OPT_REST argument,
293 * copy the remaining arguments down.
294 */
295
296 argsDone:
297 while (argc) {
298 argv[dstIndex] = argv[srcIndex];
299 srcIndex++;
300 dstIndex++;
301 argc--;
302 }
303 argv[dstIndex] = (char *) NULL;
304 *argcPtr = dstIndex;
305 return ARGV_OK;
306
307 missingArg:
308 cerr << "\"" << curArg << "\" option requires an additional argument";
309 return ARGV_ERROR;
310 }
311
312 /*
313 *----------------------------------------------------------------------
314 *
315 * PrintUsage --
316 *
317 * Print (in cerr) a help string describing command-line options.
318 *
319 * Results:
320 * None.
321 *
322 * Side effects:
323 * None.
324 *
325 *----------------------------------------------------------------------
326 */
327
328 static void
329 PrintUsage(ArgvInfo *argTable, int flags)
/* [<][>][^][v][top][bottom][index][help] */
330 /* argTable: Array of command-specific argument
331 * descriptions. */
332 /* flags: If the ARGV_NO_DEFAULTS bit is set
333 * in this word, then don't generate
334 * information for default options. */
335 {
336 register ArgvInfo *infoPtr;
337 int width, i, numSpaces;
338 #define NUM_SPACES 20
339 static char spaces[] = " ";
340 char tmp[30];
341
342 /*
343 * First, compute the width of the widest option key, so that we
344 * can make everything line up.
345 */
346
347 width = 4;
348 for (i = 0; i < 2; i++) {
349 for (infoPtr = i ? defaultTable : argTable;
350 infoPtr->type != ARGV_END; infoPtr++) {
351 int length;
352 if (infoPtr->key == NULL) {
353 continue;
354 }
355 length = strlen(infoPtr->key);
356 if (length > width) {
357 width = length;
358 }
359 }
360 }
361
362 // Added by wlee@isi.edu
363 cerr << endl;
364
365 cerr << "Command-specific options:";
366 for (i = 0; ; i++) {
367 for (infoPtr = i ? defaultTable : argTable;
368 infoPtr->type != ARGV_END; infoPtr++) {
369 if ((infoPtr->type == ARGV_HELP) && (infoPtr->key == NULL)) {
370 cerr << "\n" << infoPtr->help;
371 continue;
372 }
373 // Modified by wlee@isi.edu to get rid of ':'
374 cerr << "\n " << infoPtr->key << " ";
375 // cerr << "\n " << infoPtr->key << ":";
376 numSpaces = width + 1 - strlen(infoPtr->key);
377 while (numSpaces > 0) {
378 if (numSpaces >= NUM_SPACES) {
379 cerr << spaces;
380 } else {
381 cerr << spaces+NUM_SPACES-numSpaces;
382 }
383 numSpaces -= NUM_SPACES;
384 }
385 cerr << infoPtr->help;
386 switch (infoPtr->type) {
387 case ARGV_INT: {
388 cerr << "\n\t\tDefault value: " << *((int *) infoPtr->dst);
389 break;
390 }
391 case ARGV_FLOAT: {
392 cerr << "\n\t\tDefault value: " << *((double *) infoPtr->dst);
393 break;
394 }
395 case ARGV_STRING: {
396 char *string;
397
398 string = *((char **) infoPtr->dst);
399 if (string != NULL) {
400 cerr << "\n\t\tDefault value: \"" << string << "\"";
401 }
402 break;
403 }
404 default: {
405 break;
406 }
407 }
408 }
409
410 if ((flags & ARGV_NO_DEFAULTS) || (i > 0)) {
411 break;
412 }
413 cerr << "\nGeneric options for all commands:";
414 }
415 // Added by wlee@isi.edu
416 cerr << endl;
417 }
418
419
420