Annotation of src/usr.bin/asn1_compile/getarg.c, Revision 1.4
1.1 hin 1: /*
2: * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
3: * (Royal Institute of Technology, Stockholm, Sweden).
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: *
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: *
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: *
17: * 3. Neither the name of the Institute nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: */
33:
34: #ifdef HAVE_CONFIG_H
35: #include <config.h>
36: RCSID("$KTH: getarg.c,v 1.46 2002/08/20 16:23:07 joda Exp $");
37: #endif
38:
39: #include <stdio.h>
40: #include <stdlib.h>
41: #include <string.h>
1.4 ! pedro 42: #include <err.h>
1.1 hin 43: #include "getarg.h"
44:
45: #define ISFLAG(X) ((X).type == arg_flag || (X).type == arg_negative_flag)
46:
47: extern char *__progname;
48:
49: static size_t
50: print_arg (char *string, size_t len, int mdoc, int longp, struct getargs *arg)
51: {
52: const char *s;
53:
54: *string = '\0';
55:
56: if (ISFLAG(*arg) || (!longp && arg->type == arg_counter))
57: return 0;
58:
59: if(mdoc){
60: if(longp)
61: strlcat(string, "= Ns", len);
62: strlcat(string, " Ar ", len);
63: } else {
64: if (longp)
65: strlcat (string, "=", len);
66: else
67: strlcat (string, " ", len);
68: }
69:
70: if (arg->arg_help)
71: s = arg->arg_help;
72: else if (arg->type == arg_integer || arg->type == arg_counter)
73: s = "integer";
74: else if (arg->type == arg_string)
75: s = "string";
76: else if (arg->type == arg_strings)
77: s = "strings";
78: else if (arg->type == arg_double)
79: s = "float";
80: else
81: s = "<undefined>";
82:
83: strlcat(string, s, len);
84: return 1 + strlen(s);
85: }
86:
87: #if 0
88: static void
89: mandoc_template(struct getargs *args,
90: size_t num_args,
91: const char *progname,
92: const char *extra_string)
93: {
94: int i;
95: char timestr[64], cmd[64];
96: char buf[128];
97: const char *p;
98: time_t t;
99:
100: printf(".\\\" Things to fix:\n");
101: printf(".\\\" * correct section, and operating system\n");
102: printf(".\\\" * remove Op from mandatory flags\n");
103: printf(".\\\" * use better macros for arguments (like .Pa for files)\n");
104: printf(".\\\"\n");
105: t = time(NULL);
106: strftime(timestr, sizeof(timestr), "%B %e, %Y", localtime(&t));
107: printf(".Dd %s\n", timestr);
108: p = strrchr(progname, '/');
109: if(p) p++; else p = progname;
110: strlcpy(cmd, p, sizeof(cmd));
111: strupr(cmd);
112:
113: printf(".Dt %s SECTION\n", cmd);
114: printf(".Os OPERATING_SYSTEM\n");
115: printf(".Sh NAME\n");
116: printf(".Nm %s\n", p);
117: printf(".Nd\n");
118: printf("in search of a description\n");
119: printf(".Sh SYNOPSIS\n");
120: printf(".Nm\n");
121: for(i = 0; i < num_args; i++){
122: /* we seem to hit a limit on number of arguments if doing
123: short and long flags with arguments -- split on two lines */
124: if(ISFLAG(args[i]) ||
125: args[i].short_name == 0 || args[i].long_name == NULL) {
126: printf(".Op ");
127:
128: if(args[i].short_name) {
129: print_arg(buf, sizeof(buf), 1, 0, args + i);
130: printf("Fl %c%s", args[i].short_name, buf);
131: if(args[i].long_name)
132: printf(" | ");
133: }
134: if(args[i].long_name) {
135: print_arg(buf, sizeof(buf), 1, 1, args + i);
136: printf("Fl -%s%s%s",
137: args[i].type == arg_negative_flag ? "no-" : "",
138: args[i].long_name, buf);
139: }
140: printf("\n");
141: } else {
142: print_arg(buf, sizeof(buf), 1, 0, args + i);
143: printf(".Oo Fl %c%s \\*(Ba Xo\n", args[i].short_name, buf);
144: print_arg(buf, sizeof(buf), 1, 1, args + i);
145: printf(".Fl -%s%s\n.Xc\n.Oc\n", args[i].long_name, buf);
146: }
147: /*
148: if(args[i].type == arg_strings)
149: fprintf (stderr, "...");
150: */
151: }
152: if (extra_string && *extra_string)
153: printf (".Ar %s\n", extra_string);
154: printf(".Sh DESCRIPTION\n");
155: printf("Supported options:\n");
156: printf(".Bl -tag -width Ds\n");
157: for(i = 0; i < num_args; i++){
158: printf(".It Xo\n");
159: if(args[i].short_name){
160: printf(".Fl %c", args[i].short_name);
161: print_arg(buf, sizeof(buf), 1, 0, args + i);
162: printf("%s", buf);
163: if(args[i].long_name)
164: printf(" ,");
165: printf("\n");
166: }
167: if(args[i].long_name){
168: printf(".Fl -%s%s",
169: args[i].type == arg_negative_flag ? "no-" : "",
170: args[i].long_name);
171: print_arg(buf, sizeof(buf), 1, 1, args + i);
172: printf("%s\n", buf);
173: }
174: printf(".Xc\n");
175: if(args[i].help)
176: printf("%s\n", args[i].help);
177: /*
178: if(args[i].type == arg_strings)
179: fprintf (stderr, "...");
180: */
181: }
182: printf(".El\n");
183: printf(".\\\".Sh ENVIRONMENT\n");
184: printf(".\\\".Sh FILES\n");
185: printf(".\\\".Sh EXAMPLES\n");
186: printf(".\\\".Sh DIAGNOSTICS\n");
187: printf(".\\\".Sh SEE ALSO\n");
188: printf(".\\\".Sh STANDARDS\n");
189: printf(".\\\".Sh HISTORY\n");
190: printf(".\\\".Sh AUTHORS\n");
191: printf(".\\\".Sh BUGS\n");
192: }
193: #endif
194:
195: static int
196: check_column(FILE *f, int col, int len, int columns)
197: {
198: if(col + len > columns) {
199: fprintf(f, "\n");
200: col = fprintf(f, " ");
201: }
202: return col;
203: }
204:
205: void
206: arg_printusage (struct getargs *args,
207: size_t num_args,
208: const char *progname,
209: const char *extra_string)
210: {
211: int i;
212: size_t max_len = 0;
213: char buf[128];
214: int col = 0, columns;
215: #if 0
216: struct winsize ws;
217: #endif
218:
219: if (progname == NULL)
220: progname = __progname;
221:
222: #if 0
223: if(getenv("GETARGMANDOC")){
224: mandoc_template(args, num_args, progname, extra_string);
225: return;
226: }
227: #endif
228: #if 0
229: if(get_window_size(2, &ws) == 0)
230: columns = ws.ws_col;
231: else
232: #endif
233: columns = 80;
234: col = 0;
235: col += fprintf (stderr, "Usage: %s", progname);
236: buf[0] = '\0';
237: for (i = 0; i < num_args; ++i) {
238: if(args[i].short_name && ISFLAG(args[i])) {
239: char s[2];
240: if(buf[0] == '\0')
241: strlcpy(buf, "[-", sizeof(buf));
242: s[0] = args[i].short_name;
243: s[1] = '\0';
244: strlcat(buf, s, sizeof(buf));
245: }
246: }
247: if(buf[0] != '\0') {
248: strlcat(buf, "]", sizeof(buf));
249: col = check_column(stderr, col, strlen(buf) + 1, columns);
250: col += fprintf(stderr, " %s", buf);
251: }
252:
253: for (i = 0; i < num_args; ++i) {
254: size_t len = 0;
255:
256: if (args[i].long_name) {
257: buf[0] = '\0';
258: strlcat(buf, "[--", sizeof(buf));
259: len += 2;
260: if(args[i].type == arg_negative_flag) {
261: strlcat(buf, "no-", sizeof(buf));
262: len += 3;
263: }
264: strlcat(buf, args[i].long_name, sizeof(buf));
265: len += strlen(args[i].long_name);
266: len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf),
267: 0, 1, &args[i]);
268: strlcat(buf, "]", sizeof(buf));
269: if(args[i].type == arg_strings)
270: strlcat(buf, "...", sizeof(buf));
271: col = check_column(stderr, col, strlen(buf) + 1, columns);
272: col += fprintf(stderr, " %s", buf);
273: }
274: if (args[i].short_name && !ISFLAG(args[i])) {
275: snprintf(buf, sizeof(buf), "[-%c", args[i].short_name);
276: len += 2;
277: len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf),
278: 0, 0, &args[i]);
279: strlcat(buf, "]", sizeof(buf));
280: if(args[i].type == arg_strings)
281: strlcat(buf, "...", sizeof(buf));
282: col = check_column(stderr, col, strlen(buf) + 1, columns);
283: col += fprintf(stderr, " %s", buf);
284: }
285: if (args[i].long_name && args[i].short_name)
286: len += 2; /* ", " */
287: #if 0
288: max_len = max(max_len, len);
289: #else
290: if(len > max_len)
291: max_len = len;
292: #endif
293: }
294: if (extra_string) {
295: col = check_column(stderr, col, strlen(extra_string) + 1, columns);
296: fprintf (stderr, " %s\n", extra_string);
297: } else
298: fprintf (stderr, "\n");
299: for (i = 0; i < num_args; ++i) {
300: if (args[i].help) {
301: size_t count = 0;
302:
303: if (args[i].short_name) {
304: count += fprintf (stderr, "-%c", args[i].short_name);
305: print_arg (buf, sizeof(buf), 0, 0, &args[i]);
306: count += fprintf(stderr, "%s", buf);
307: }
308: if (args[i].short_name && args[i].long_name)
309: count += fprintf (stderr, ", ");
310: if (args[i].long_name) {
311: count += fprintf (stderr, "--");
312: if (args[i].type == arg_negative_flag)
313: count += fprintf (stderr, "no-");
314: count += fprintf (stderr, "%s", args[i].long_name);
315: print_arg (buf, sizeof(buf), 0, 1, &args[i]);
316: count += fprintf(stderr, "%s", buf);
317: }
318: while(count++ <= max_len)
319: putc (' ', stderr);
320: fprintf (stderr, "%s\n", args[i].help);
321: }
322: }
323: }
324:
325: static void
326: add_string(getarg_strings *s, char *value)
327: {
1.3 deraadt 328: if ((s->strings = realloc(s->strings, (s->num_strings + 1) *
329: sizeof(*s->strings))) == NULL)
330: err(1, "realloc");
1.1 hin 331: s->strings[s->num_strings] = value;
332: s->num_strings++;
333: }
334:
335: static int
336: arg_match_long(struct getargs *args, size_t num_args,
337: char *argv, int argc, char **rargv, int *goptind)
338: {
339: int i;
340: char *goptarg = NULL;
341: int negate = 0;
342: int partial_match = 0;
343: struct getargs *partial = NULL;
344: struct getargs *current = NULL;
345: int argv_len;
346: char *p;
347: int p_len;
348:
349: argv_len = strlen(argv);
350: p = strchr (argv, '=');
351: if (p != NULL)
352: argv_len = p - argv;
353:
354: for (i = 0; i < num_args; ++i) {
355: if(args[i].long_name) {
356: int len = strlen(args[i].long_name);
357: p = argv;
358: p_len = argv_len;
359: negate = 0;
360:
361: for (;;) {
362: if (strncmp (args[i].long_name, p, p_len) == 0) {
363: if(p_len == len)
364: current = &args[i];
365: else {
366: ++partial_match;
367: partial = &args[i];
368: }
369: goptarg = p + p_len;
370: } else if (ISFLAG(args[i]) && strncmp (p, "no-", 3) == 0) {
371: negate = !negate;
372: p += 3;
373: p_len -= 3;
374: continue;
375: }
376: break;
377: }
378: if (current)
379: break;
380: }
381: }
382: if (current == NULL) {
383: if (partial_match == 1)
384: current = partial;
385: else
386: return ARG_ERR_NO_MATCH;
387: }
388:
389: if(*goptarg == '\0'
390: && !ISFLAG(*current)
391: && current->type != arg_collect
392: && current->type != arg_counter)
393: return ARG_ERR_NO_MATCH;
394: switch(current->type){
395: case arg_integer:
396: {
397: int tmp;
398: if(sscanf(goptarg + 1, "%d", &tmp) != 1)
399: return ARG_ERR_BAD_ARG;
400: *(int*)current->value = tmp;
401: return 0;
402: }
403: case arg_string:
404: {
405: *(char**)current->value = goptarg + 1;
406: return 0;
407: }
408: case arg_strings:
409: {
410: add_string((getarg_strings*)current->value, goptarg + 1);
411: return 0;
412: }
413: case arg_flag:
414: case arg_negative_flag:
415: {
416: int *flag = current->value;
417: if(*goptarg == '\0' ||
418: strcmp(goptarg + 1, "yes") == 0 ||
419: strcmp(goptarg + 1, "true") == 0){
420: *flag = !negate;
421: return 0;
422: } else if (*goptarg && strcmp(goptarg + 1, "maybe") == 0) {
1.2 deraadt 423: #ifdef HAVE_ARC4RANDOM
424: *flag = arc4random() & 1;
425: #elif HAVE_RANDOM
1.1 hin 426: *flag = random() & 1;
427: #else
428: *flag = rand() & 1;
429: #endif
430: } else {
431: *flag = negate;
432: return 0;
433: }
434: return ARG_ERR_BAD_ARG;
435: }
436: case arg_counter :
437: {
438: int val;
439:
440: if (*goptarg == '\0')
441: val = 1;
442: else if(sscanf(goptarg + 1, "%d", &val) != 1)
443: return ARG_ERR_BAD_ARG;
444: *(int *)current->value += val;
445: return 0;
446: }
447: case arg_double:
448: {
449: double tmp;
450: if(sscanf(goptarg + 1, "%lf", &tmp) != 1)
451: return ARG_ERR_BAD_ARG;
452: *(double*)current->value = tmp;
453: return 0;
454: }
455: case arg_collect:{
456: struct getarg_collect_info *c = current->value;
457: int o = argv - rargv[*goptind];
458: return (*c->func)(FALSE, argc, rargv, goptind, &o, c->data);
459: }
460:
461: default:
462: abort ();
463: }
464: }
465:
466: static int
467: arg_match_short (struct getargs *args, size_t num_args,
468: char *argv, int argc, char **rargv, int *goptind)
469: {
470: int j, k;
471:
472: for(j = 1; j > 0 && j < strlen(rargv[*goptind]); j++) {
473: for(k = 0; k < num_args; k++) {
474: char *goptarg;
475:
476: if(args[k].short_name == 0)
477: continue;
478: if(argv[j] == args[k].short_name) {
479: if(args[k].type == arg_flag) {
480: *(int*)args[k].value = 1;
481: break;
482: }
483: if(args[k].type == arg_negative_flag) {
484: *(int*)args[k].value = 0;
485: break;
486: }
487: if(args[k].type == arg_counter) {
488: ++*(int *)args[k].value;
489: break;
490: }
491: if(args[k].type == arg_collect) {
492: struct getarg_collect_info *c = args[k].value;
493:
494: if((*c->func)(TRUE, argc, rargv, goptind, &j, c->data))
495: return ARG_ERR_BAD_ARG;
496: break;
497: }
498:
499: if(argv[j + 1])
500: goptarg = &argv[j + 1];
501: else {
502: ++*goptind;
503: goptarg = rargv[*goptind];
504: }
505: if(goptarg == NULL) {
506: --*goptind;
507: return ARG_ERR_NO_ARG;
508: }
509: if(args[k].type == arg_integer) {
510: int tmp;
511: if(sscanf(goptarg, "%d", &tmp) != 1)
512: return ARG_ERR_BAD_ARG;
513: *(int*)args[k].value = tmp;
514: return 0;
515: } else if(args[k].type == arg_string) {
516: *(char**)args[k].value = goptarg;
517: return 0;
518: } else if(args[k].type == arg_strings) {
519: add_string((getarg_strings*)args[k].value, goptarg);
520: return 0;
521: } else if(args[k].type == arg_double) {
522: double tmp;
523: if(sscanf(goptarg, "%lf", &tmp) != 1)
524: return ARG_ERR_BAD_ARG;
525: *(double*)args[k].value = tmp;
526: return 0;
527: }
528: return ARG_ERR_BAD_ARG;
529: }
530: }
531: if (k == num_args)
532: return ARG_ERR_NO_MATCH;
533: }
534: return 0;
535: }
536:
537: int
538: getarg(struct getargs *args, size_t num_args,
539: int argc, char **argv, int *goptind)
540: {
541: int i;
542: int ret = 0;
543:
1.2 deraadt 544: #ifndef HAVE_ARC4RANDOM
545:
1.1 hin 546: #if defined(HAVE_SRANDOMDEV)
547: srandomdev();
548: #elif defined(HAVE_RANDOM)
549: srandom(time(NULL));
550: #else
551: srand (time(NULL));
552: #endif
1.2 deraadt 553:
554: #endif /* HAVE_ARC4RANDOM */
555:
1.1 hin 556: (*goptind)++;
557: for(i = *goptind; i < argc; i++) {
558: if(argv[i][0] != '-')
559: break;
560: if(argv[i][1] == '-'){
561: if(argv[i][2] == 0){
562: i++;
563: break;
564: }
565: ret = arg_match_long (args, num_args, argv[i] + 2,
566: argc, argv, &i);
567: } else {
568: ret = arg_match_short (args, num_args, argv[i],
569: argc, argv, &i);
570: }
571: if(ret)
572: break;
573: }
574: *goptind = i;
575: return ret;
576: }
577:
578: void
579: free_getarg_strings (getarg_strings *s)
580: {
581: free (s->strings);
582: }
583:
584: #if TEST
585: int foo_flag = 2;
586: int flag1 = 0;
587: int flag2 = 0;
588: int bar_int;
589: char *baz_string;
590:
591: struct getargs args[] = {
592: { NULL, '1', arg_flag, &flag1, "one", NULL },
593: { NULL, '2', arg_flag, &flag2, "two", NULL },
594: { "foo", 'f', arg_negative_flag, &foo_flag, "foo", NULL },
595: { "bar", 'b', arg_integer, &bar_int, "bar", "seconds"},
596: { "baz", 'x', arg_string, &baz_string, "baz", "name" },
597: };
598:
599: int main(int argc, char **argv)
600: {
601: int goptind = 0;
602: while(getarg(args, 5, argc, argv, &goptind))
603: printf("Bad arg: %s\n", argv[goptind]);
604: printf("flag1 = %d\n", flag1);
605: printf("flag2 = %d\n", flag2);
606: printf("foo_flag = %d\n", foo_flag);
607: printf("bar_int = %d\n", bar_int);
608: printf("baz_flag = %s\n", baz_string);
609: arg_printusage (args, 5, argv[0], "nothing here");
610: }
611: #endif