This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / usr.bin / f2c / parse_args.c
CommitLineData
f1525c23
WH
1/****************************************************************
2Copyright 1990 by AT&T Bell Laboratories and Bellcore.
3
4Permission to use, copy, modify, and distribute this software
5and its documentation for any purpose and without fee is hereby
6granted, provided that the above copyright notice appear in all
7copies and that both that the copyright notice and this
8permission notice and warranty disclaimer appear in supporting
9documentation, and that the names of AT&T Bell Laboratories or
10Bellcore or any of their entities not be used in advertising or
11publicity pertaining to distribution of the software without
12specific, written prior permission.
13
14AT&T and Bellcore disclaim all warranties with regard to this
15software, including all implied warranties of merchantability
16and fitness. In no event shall AT&T or Bellcore be liable for
17any special, indirect or consequential damages or any damages
18whatsoever resulting from loss of use, data or profits, whether
19in an action of contract, negligence or other tortious action,
20arising out of or in connection with the use or performance of
21this software.
22****************************************************************/
23
24/* parse_args
25
26 This function will parse command line input into appropriate data
27 structures, output error messages when appropriate and provide some
28 minimal type conversion.
29
30 Input to the function consists of the standard argc,argv
31 values, and a table which directs the parser. Each table entry has the
32 following components:
33
34 prefix -- the (optional) switch character string, e.g. "-" "/" "="
35 switch -- the command string, e.g. "o" "data" "file" "F"
36 flags -- control flags, e.g. CASE_INSENSITIVE, REQUIRED_PREFIX
37 arg_count -- number of arguments this command requires, e.g. 0 for
38 booleans, 1 for filenames, INFINITY for input files
39 result_type -- how to interpret the switch arguments, e.g. STRING,
40 CHAR, FILE, OLD_FILE, NEW_FILE
41 result_ptr -- pointer to storage for the result, be it a table or
42 a string or whatever
43 table_size -- if the arguments fill a table, the maximum number of
44 entries; if there are no arguments, the value to
45 load into the result storage
46
47 Although the table can be used to hold a list of filenames, only
48 scalar values (e.g. pointers) can be stored in the table. No vector
49 processing will be done, only pointers to string storage will be moved.
50
51 An example entry, which could be used to parse input filenames, is:
52
53 "-", "o", 0, oo, OLD_FILE, infilenames, INFILE_TABLE_SIZE
54
55*/
56
57#include <stdio.h>
58#ifndef NULL
59/* ANSI C */
60#include <stddef.h>
61#endif
62#include "parse.h"
63#include <math.h> /* For atof */
64#include <ctype.h>
65
66#define MAX_INPUT_SIZE 1000
67
68#define arg_prefix(x) ((x).prefix)
69#define arg_string(x) ((x).string)
70#define arg_flags(x) ((x).flags)
71#define arg_count(x) ((x).count)
72#define arg_result_type(x) ((x).result_type)
73#define arg_result_ptr(x) ((x).result_ptr)
74#define arg_table_size(x) ((x).table_size)
75
76#ifndef TRUE
77#define TRUE 1
78#endif
79#ifndef FALSE
80#define FALSE 0
81#endif
82typedef int boolean;
83
84
85char *lower_string (/* char [], char * */);
86
87static char *this_program = "";
88
89#ifndef atol
90extern long atol();
91#endif
92static int arg_parse (/* char *, arg_info * */);
93
94
95boolean parse_args (argc, argv, table, entries, others, other_count)
96int argc;
97char *argv[];
98arg_info table[];
99int entries;
100char *others[];
101int other_count;
102{
103 boolean arg_verify (/* argv, table, entries */);
104 void init_store (/* table, entries */);
105
106 boolean result;
107
108 if (argv)
109 this_program = argv[0];
110
111/* Check the validity of the table and its parameters */
112
113 result = arg_verify (argv, table, entries);
114
115/* Initialize the storage values */
116
117 init_store (table, entries);
118
119 if (result) {
120 boolean use_prefix = TRUE;
121 char *argv0;
122
123 argc--;
124 argv0 = *++argv;
125 while (argc) {
126 int index, length;
127
128 index = match_table (*argv, table, entries, use_prefix, &length);
129 if (index < 0) {
130
131/* The argument doesn't match anything in the table */
132
133 if (others) {
134
135 if (*argv > argv0)
136 *--*argv = '-'; /* complain at invalid flag */
137
138 if (other_count > 0) {
139 *others++ = *argv;
140 other_count--;
141 } else {
142 fprintf (stderr, "%s: too many parameters: ",
143 this_program);
144 fprintf (stderr, "'%s' ignored\n", *argv);
145 } /* else */
146 } /* if (others) */
147 argv0 = *++argv;
148 argc--;
149 } else {
150
151/* A match was found */
152
153 if (length >= strlen (*argv)) {
154 argc--;
155 argv0 = *++argv;
156 use_prefix = TRUE;
157 } else {
158 (*argv) += length;
159 use_prefix = FALSE;
160 } /* else */
161
162/* Parse any necessary arguments */
163
164 if (arg_count (table[index]) != P_NO_ARGS) {
165
166/* Now length will be used to store the number of parsed characters */
167
168 length = arg_parse(*argv, &table[index]);
169 if (*argv == NULL)
170 argc = 0;
171 else if (length >= strlen (*argv)) {
172 argc--;
173 argv0 = *++argv;
174 use_prefix = TRUE;
175 } else {
176 (*argv) += length;
177 use_prefix = FALSE;
178 } /* else */
179 } /* if (argv_count != P_NO_ARGS) */
180 else
181 *arg_result_ptr(table[index]) =
182 arg_table_size(table[index]);
183 } /* else */
184 } /* while (argc) */
185 } /* if (result) */
186
187 return result;
188} /* parse_args */
189
190
191boolean arg_verify (argv, table, entries)
192char *argv[];
193arg_info table[];
194int entries;
195{
196 int i;
197 char *this_program = "";
198
199 if (argv)
200 this_program = argv[0];
201
202 for (i = 0; i < entries; i++) {
203 arg_info *arg = &table[i];
204
205/* Check the argument flags */
206
207 if (arg_flags (*arg) & ~(P_CASE_INSENSITIVE | P_REQUIRED_PREFIX)) {
208 fprintf (stderr, "%s [arg_verify]: too many ", this_program);
209 fprintf (stderr, "flags in entry %d: '%x' (hex)\n", i,
210 arg_flags (*arg));
211 } /* if */
212
213/* Check the argument count */
214
215 { int count = arg_count (*arg);
216
217 if (count != P_NO_ARGS && count != P_ONE_ARG && count !=
218 P_INFINITE_ARGS) {
219 fprintf (stderr, "%s [arg_verify]: invalid ", this_program);
220 fprintf (stderr, "argument count in entry %d: '%d'\n", i,
221 count);
222 } /* if count != P_NO_ARGS ... */
223
224/* Check the result field; want to be able to store results */
225
226 else
227 if (arg_result_ptr (*arg) == (int *) NULL) {
228 fprintf (stderr, "%s [arg_verify]: ", this_program);
229 fprintf (stderr, "no argument storage given for ");
230 fprintf (stderr, "entry %d\n", i);
231 } /* if arg_result_ptr */
232 }
233
234/* Check the argument type */
235
236 { int type = arg_result_type (*arg);
237
238 if (type < P_STRING || type > P_DOUBLE)
239 fprintf(stderr,
240 "%s [arg_verify]: bad arg type in entry %d: '%d'\n",
241 this_program, i, type);
242 }
243
244/* Check table size */
245
246 { int size = arg_table_size (*arg);
247
248 if (arg_count (*arg) == P_INFINITE_ARGS && size < 1) {
249 fprintf (stderr, "%s [arg_verify]: bad ", this_program);
250 fprintf (stderr, "table size in entry %d: '%d'\n", i,
251 size);
252 } /* if (arg_count == P_INFINITE_ARGS && size < 1) */
253 }
254
255 } /* for i = 0 */
256
257 return TRUE;
258} /* arg_verify */
259
260
261/* match_table -- returns the index of the best entry matching the input,
262 -1 if no match. The best match is the one of longest length which
263 appears lowest in the table. The length of the match will be returned
264 in length ONLY IF a match was found. */
265
266int match_table (norm_input, table, entries, use_prefix, length)
267register char *norm_input;
268arg_info table[];
269int entries;
270boolean use_prefix;
271int *length;
272{
273 extern int match (/* char *, char *, arg_info *, boolean */);
274
275 char low_input[MAX_INPUT_SIZE];
276 register int i;
277 int best_index = -1, best_length = 0;
278
279/* FUNCTION BODY */
280
281 (void) lower_string (low_input, norm_input);
282
283 for (i = 0; i < entries; i++) {
284 int this_length = match (norm_input, low_input, &table[i], use_prefix);
285
286 if (this_length > best_length) {
287 best_index = i;
288 best_length = this_length;
289 } /* if (this_length > best_length) */
290 } /* for (i = 0) */
291
292 if (best_index > -1 && length != (int *) NULL)
293 *length = best_length;
294
295 return best_index;
296} /* match_table */
297
298
299/* match -- takes an input string and table entry, and returns the length
300 of the longer match.
301
302 0 ==> input doesn't match
303
304 For example:
305
306 INPUT PREFIX STRING RESULT
307----------------------------------------------------------------------
308 "abcd" "-" "d" 0
309 "-d" "-" "d" 2 (i.e. "-d")
310 "dout" "-" "d" 1 (i.e. "d")
311 "-d" "" "-d" 2 (i.e. "-d")
312 "dd" "d" "d" 2 <= here's the weird one
313*/
314
315int match (norm_input, low_input, entry, use_prefix)
316char *norm_input, *low_input;
317arg_info *entry;
318boolean use_prefix;
319{
320 char *norm_prefix = arg_prefix (*entry);
321 char *norm_string = arg_string (*entry);
322 boolean prefix_match = FALSE, string_match = FALSE;
323 int result = 0;
324
325/* Buffers for the lowercased versions of the strings being compared.
326 These are used when the switch is to be case insensitive */
327
328 static char low_prefix[MAX_INPUT_SIZE];
329 static char low_string[MAX_INPUT_SIZE];
330 int prefix_length = strlen (norm_prefix);
331 int string_length = strlen (norm_string);
332
333/* Pointers for the required strings (lowered or nonlowered) */
334
335 register char *input, *prefix, *string;
336
337/* FUNCTION BODY */
338
339/* Use the appropriate strings to handle case sensitivity */
340
341 if (arg_flags (*entry) & P_CASE_INSENSITIVE) {
342 input = low_input;
343 prefix = lower_string (low_prefix, norm_prefix);
344 string = lower_string (low_string, norm_string);
345 } else {
346 input = norm_input;
347 prefix = norm_prefix;
348 string = norm_string;
349 } /* else */
350
351/* First, check the string formed by concatenating the prefix onto the
352 switch string, but only when the prefix is not being ignored */
353
354 if (use_prefix && prefix != NULL && *prefix != '\0')
355 prefix_match = (strncmp (input, prefix, prefix_length) == 0) &&
356 (strncmp (input + prefix_length, string, string_length) == 0);
357
358/* Next, check just the switch string, if that's allowed */
359
360 if (!use_prefix && (arg_flags (*entry) & P_REQUIRED_PREFIX) == 0)
361 string_match = strncmp (input, string, string_length) == 0;
362
363 if (prefix_match)
364 result = prefix_length + string_length;
365 else if (string_match)
366 result = string_length;
367
368 return result;
369} /* match */
370
371
372char *lower_string (dest, src)
373char *dest, *src;
374{
375 char *result = dest;
376 register int c;
377
378 if (dest == NULL || src == NULL)
379 result = NULL;
380 else
381 while (*dest++ = (c = *src++) >= 'A' && c <= 'Z' ? tolower(c) : c);
382
383 return result;
384} /* lower_string */
385
386
387/* arg_parse -- returns the number of characters parsed for this entry */
388
389static int arg_parse (str, entry)
390char *str;
391arg_info *entry;
392{
393 int length = 0;
394
395 if (arg_count (*entry) == P_ONE_ARG) {
396 char **store = (char **) arg_result_ptr (*entry);
397
398 length = put_one_arg (arg_result_type (*entry), str, store,
399 arg_prefix (*entry), arg_string (*entry));
400
401 } /* if (arg_count == P_ONE_ARG) */
402 else { /* Must be a table of arguments */
403 char **store = (char **) arg_result_ptr (*entry);
404
405 if (store) {
406 while (*store)
407 store++;
408
409 length = put_one_arg (arg_result_type (*entry), str, store++,
410 arg_prefix (*entry), arg_string (*entry));
411
412 *store = (char *) NULL;
413 } /* if (store) */
414 } /* else */
415
416 return length;
417} /* arg_parse */
418
419
420int put_one_arg (type, str, store, prefix, string)
421int type;
422char *str;
423char **store;
424char *prefix, *string;
425{
426 int length = 0;
427 long L;
428
429 if (store) {
430 switch (type) {
431 case P_STRING:
432 case P_FILE:
433 case P_OLD_FILE:
434 case P_NEW_FILE:
435 *store = str;
436 if (str == NULL)
437 fprintf (stderr, "%s: Missing argument after '%s%s'\n",
438 this_program, prefix, string);
439 length = str ? strlen (str) : 0;
440 break;
441 case P_CHAR:
442 *((char *) store) = *str;
443 length = 1;
444 break;
445 case P_SHORT:
446 L = atol(str);
447 *(short *)store = (short) L;
448 if (L != *(short *)store)
449 fprintf(stderr,
450 "%s%s parameter '%ld' is not a SHORT INT (truncating to %d)\n",
451 prefix, string, L, *(short *)store);
452 length = strlen (str);
453 break;
454 case P_INT:
455 L = atol(str);
456 *(int *)store = (int)L;
457 if (L != *(int *)store)
458 fprintf(stderr,
459 "%s%s parameter '%ld' is not an INT (truncating to %d)\n",
460 prefix, string, L, *(int *)store);
461 length = strlen (str);
462 break;
463 case P_LONG:
464 *(long *)store = atol(str);
465 length = strlen (str);
466 break;
467 case P_FLOAT:
468 *((float *) store) = (float) atof (str);
469 length = strlen (str);
470 break;
471 case P_DOUBLE:
472 *((double *) store) = (double) atof (str);
473 length = strlen (str);
474 break;
475 default:
476 fprintf (stderr, "put_one_arg: bad type '%d'\n",
477 type);
478 break;
479 } /* switch */
480 } /* if (store) */
481
482 return length;
483} /* put_one_arg */
484
485
486void init_store (table, entries)
487arg_info *table;
488int entries;
489{
490 int index;
491
492 for (index = 0; index < entries; index++)
493 if (arg_count (table[index]) == P_INFINITE_ARGS) {
494 char **place = (char **) arg_result_ptr (table[index]);
495
496 if (place)
497 *place = (char *) NULL;
498 } /* if arg_count == P_INFINITE_ARGS */
499
500} /* init_store */
501