Annotation of src/usr.bin/asn1_compile/getarg.c, Revision 1.5
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>
1.5 ! biorn 36: RCSID("$KTH: getarg.c,v 1.48 2005/04/12 11:28:43 lha Exp $");
1.1 hin 37: #endif
38:
39: #include <stdio.h>
40: #include <stdlib.h>
41: #include <string.h>
1.5 ! biorn 42: #include <errno.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:
1.5 ! biorn 205: void ROKEN_LIB_FUNCTION
1.1 hin 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:
1.5 ! biorn 325: static int
1.1 hin 326: add_string(getarg_strings *s, char *value)
327: {
1.5 ! biorn 328: char **strings;
! 329:
! 330: strings = realloc(s->strings, (s->num_strings + 1) * sizeof(*s->strings));
! 331: if (strings == NULL) {
! 332: free(s->strings);
! 333: s->strings = NULL;
! 334: s->num_strings = 0;
! 335: return ENOMEM;
! 336: }
! 337: s->strings = strings;
1.1 hin 338: s->strings[s->num_strings] = value;
339: s->num_strings++;
1.5 ! biorn 340: return 0;
1.1 hin 341: }
342:
343: static int
344: arg_match_long(struct getargs *args, size_t num_args,
345: char *argv, int argc, char **rargv, int *goptind)
346: {
347: int i;
348: char *goptarg = NULL;
349: int negate = 0;
350: int partial_match = 0;
351: struct getargs *partial = NULL;
352: struct getargs *current = NULL;
353: int argv_len;
354: char *p;
355: int p_len;
356:
357: argv_len = strlen(argv);
358: p = strchr (argv, '=');
359: if (p != NULL)
360: argv_len = p - argv;
361:
362: for (i = 0; i < num_args; ++i) {
363: if(args[i].long_name) {
364: int len = strlen(args[i].long_name);
365: p = argv;
366: p_len = argv_len;
367: negate = 0;
368:
369: for (;;) {
370: if (strncmp (args[i].long_name, p, p_len) == 0) {
371: if(p_len == len)
372: current = &args[i];
373: else {
374: ++partial_match;
375: partial = &args[i];
376: }
377: goptarg = p + p_len;
378: } else if (ISFLAG(args[i]) && strncmp (p, "no-", 3) == 0) {
379: negate = !negate;
380: p += 3;
381: p_len -= 3;
382: continue;
383: }
384: break;
385: }
386: if (current)
387: break;
388: }
389: }
390: if (current == NULL) {
391: if (partial_match == 1)
392: current = partial;
393: else
394: return ARG_ERR_NO_MATCH;
395: }
396:
397: if(*goptarg == '\0'
398: && !ISFLAG(*current)
399: && current->type != arg_collect
400: && current->type != arg_counter)
401: return ARG_ERR_NO_MATCH;
402: switch(current->type){
403: case arg_integer:
404: {
405: int tmp;
406: if(sscanf(goptarg + 1, "%d", &tmp) != 1)
407: return ARG_ERR_BAD_ARG;
408: *(int*)current->value = tmp;
409: return 0;
410: }
411: case arg_string:
412: {
413: *(char**)current->value = goptarg + 1;
414: return 0;
415: }
416: case arg_strings:
417: {
1.5 ! biorn 418: return add_string((getarg_strings*)current->value, goptarg + 1);
1.1 hin 419: }
420: case arg_flag:
421: case arg_negative_flag:
422: {
423: int *flag = current->value;
424: if(*goptarg == '\0' ||
425: strcmp(goptarg + 1, "yes") == 0 ||
426: strcmp(goptarg + 1, "true") == 0){
427: *flag = !negate;
428: return 0;
429: } else if (*goptarg && strcmp(goptarg + 1, "maybe") == 0) {
1.2 deraadt 430: #ifdef HAVE_ARC4RANDOM
431: *flag = arc4random() & 1;
432: #elif HAVE_RANDOM
1.1 hin 433: *flag = random() & 1;
434: #else
435: *flag = rand() & 1;
436: #endif
437: } else {
438: *flag = negate;
439: return 0;
440: }
441: return ARG_ERR_BAD_ARG;
442: }
443: case arg_counter :
444: {
445: int val;
446:
447: if (*goptarg == '\0')
448: val = 1;
449: else if(sscanf(goptarg + 1, "%d", &val) != 1)
450: return ARG_ERR_BAD_ARG;
451: *(int *)current->value += val;
452: return 0;
453: }
454: case arg_double:
455: {
456: double tmp;
457: if(sscanf(goptarg + 1, "%lf", &tmp) != 1)
458: return ARG_ERR_BAD_ARG;
459: *(double*)current->value = tmp;
460: return 0;
461: }
462: case arg_collect:{
463: struct getarg_collect_info *c = current->value;
464: int o = argv - rargv[*goptind];
465: return (*c->func)(FALSE, argc, rargv, goptind, &o, c->data);
466: }
467:
468: default:
469: abort ();
470: }
471: }
472:
473: static int
474: arg_match_short (struct getargs *args, size_t num_args,
475: char *argv, int argc, char **rargv, int *goptind)
476: {
477: int j, k;
478:
479: for(j = 1; j > 0 && j < strlen(rargv[*goptind]); j++) {
480: for(k = 0; k < num_args; k++) {
481: char *goptarg;
482:
483: if(args[k].short_name == 0)
484: continue;
485: if(argv[j] == args[k].short_name) {
486: if(args[k].type == arg_flag) {
487: *(int*)args[k].value = 1;
488: break;
489: }
490: if(args[k].type == arg_negative_flag) {
491: *(int*)args[k].value = 0;
492: break;
493: }
494: if(args[k].type == arg_counter) {
495: ++*(int *)args[k].value;
496: break;
497: }
498: if(args[k].type == arg_collect) {
499: struct getarg_collect_info *c = args[k].value;
500:
501: if((*c->func)(TRUE, argc, rargv, goptind, &j, c->data))
502: return ARG_ERR_BAD_ARG;
503: break;
504: }
505:
506: if(argv[j + 1])
507: goptarg = &argv[j + 1];
508: else {
509: ++*goptind;
510: goptarg = rargv[*goptind];
511: }
512: if(goptarg == NULL) {
513: --*goptind;
514: return ARG_ERR_NO_ARG;
515: }
516: if(args[k].type == arg_integer) {
517: int tmp;
518: if(sscanf(goptarg, "%d", &tmp) != 1)
519: return ARG_ERR_BAD_ARG;
520: *(int*)args[k].value = tmp;
521: return 0;
522: } else if(args[k].type == arg_string) {
523: *(char**)args[k].value = goptarg;
524: return 0;
525: } else if(args[k].type == arg_strings) {
1.5 ! biorn 526: return add_string((getarg_strings*)args[k].value, goptarg);
1.1 hin 527: } else if(args[k].type == arg_double) {
528: double tmp;
529: if(sscanf(goptarg, "%lf", &tmp) != 1)
530: return ARG_ERR_BAD_ARG;
531: *(double*)args[k].value = tmp;
532: return 0;
533: }
534: return ARG_ERR_BAD_ARG;
535: }
536: }
537: if (k == num_args)
538: return ARG_ERR_NO_MATCH;
539: }
540: return 0;
541: }
542:
1.5 ! biorn 543: int ROKEN_LIB_FUNCTION
1.1 hin 544: getarg(struct getargs *args, size_t num_args,
545: int argc, char **argv, int *goptind)
546: {
547: int i;
548: int ret = 0;
549:
1.2 deraadt 550: #ifndef HAVE_ARC4RANDOM
551:
1.1 hin 552: #if defined(HAVE_SRANDOMDEV)
553: srandomdev();
554: #elif defined(HAVE_RANDOM)
555: srandom(time(NULL));
556: #else
557: srand (time(NULL));
558: #endif
1.2 deraadt 559:
560: #endif /* HAVE_ARC4RANDOM */
561:
1.1 hin 562: (*goptind)++;
563: for(i = *goptind; i < argc; i++) {
564: if(argv[i][0] != '-')
565: break;
566: if(argv[i][1] == '-'){
567: if(argv[i][2] == 0){
568: i++;
569: break;
570: }
571: ret = arg_match_long (args, num_args, argv[i] + 2,
572: argc, argv, &i);
573: } else {
574: ret = arg_match_short (args, num_args, argv[i],
575: argc, argv, &i);
576: }
577: if(ret)
578: break;
579: }
580: *goptind = i;
581: return ret;
582: }
583:
1.5 ! biorn 584: void ROKEN_LIB_FUNCTION
1.1 hin 585: free_getarg_strings (getarg_strings *s)
586: {
587: free (s->strings);
588: }
589:
590: #if TEST
591: int foo_flag = 2;
592: int flag1 = 0;
593: int flag2 = 0;
594: int bar_int;
595: char *baz_string;
596:
597: struct getargs args[] = {
598: { NULL, '1', arg_flag, &flag1, "one", NULL },
599: { NULL, '2', arg_flag, &flag2, "two", NULL },
600: { "foo", 'f', arg_negative_flag, &foo_flag, "foo", NULL },
601: { "bar", 'b', arg_integer, &bar_int, "bar", "seconds"},
602: { "baz", 'x', arg_string, &baz_string, "baz", "name" },
603: };
604:
605: int main(int argc, char **argv)
606: {
607: int goptind = 0;
608: while(getarg(args, 5, argc, argv, &goptind))
609: printf("Bad arg: %s\n", argv[goptind]);
610: printf("flag1 = %d\n", flag1);
611: printf("flag2 = %d\n", flag2);
612: printf("foo_flag = %d\n", foo_flag);
613: printf("bar_int = %d\n", bar_int);
614: printf("baz_flag = %s\n", baz_string);
615: arg_printusage (args, 5, argv[0], "nothing here");
616: }
617: #endif