2 * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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
36 RCSID("$Id: getarg.c,v 1.32 1999/12/02 16:58:46 joda Exp $");
43 #define ISFLAG(X) ((X).type == arg_flag || (X).type == arg_negative_flag)
46 print_arg (char *string, size_t len, int mdoc, int longp, struct getargs *arg)
52 if (ISFLAG(*arg) || (!longp && arg->type == arg_counter))
57 strlcat(string, "= Ns", len);
58 strlcat(string, " Ar ", len);
61 strlcat (string, "=", len);
63 strlcat (string, " ", len);
67 else if (arg->type == arg_integer || arg->type == arg_counter)
69 else if (arg->type == arg_string)
71 else if (arg->type == arg_double)
76 strlcat(string, s, len);
81 mandoc_template(struct getargs *args,
84 const char *extra_string)
87 char timestr[64], cmd[64];
92 printf(".\\\" Things to fix:\n");
93 printf(".\\\" * correct section, and operating system\n");
94 printf(".\\\" * remove Op from mandatory flags\n");
95 printf(".\\\" * use better macros for arguments (like .Pa for files)\n");
98 strftime(timestr, sizeof(timestr), "%B %e, %Y", localtime(&t));
99 printf(".Dd %s\n", timestr);
100 p = strrchr(progname, '/');
101 if(p) p++; else p = progname;
102 strlcpy(cmd, p, sizeof(cmd));
105 printf(".Dt %s SECTION\n", cmd);
106 printf(".Os OPERATING_SYSTEM\n");
107 printf(".Sh NAME\n");
108 printf(".Nm %s\n", p);
110 printf("in search of a description\n");
111 printf(".Sh SYNOPSIS\n");
113 for(i = 0; i < num_args; i++){
114 /* we seem to hit a limit on number of arguments if doing
115 short and long flags with arguments -- split on two lines */
116 if(ISFLAG(args[i]) ||
117 args[i].short_name == 0 || args[i].long_name == NULL) {
120 if(args[i].short_name) {
121 print_arg(buf, sizeof(buf), 1, 0, args + i);
122 printf("Fl %c%s", args[i].short_name, buf);
123 if(args[i].long_name)
126 if(args[i].long_name) {
127 print_arg(buf, sizeof(buf), 1, 1, args + i);
128 printf("Fl -%s%s", args[i].long_name, buf);
132 print_arg(buf, sizeof(buf), 1, 0, args + i);
133 printf(".Oo Fl %c%s \\*(Ba Xo\n", args[i].short_name, buf);
134 print_arg(buf, sizeof(buf), 1, 1, args + i);
135 printf(".Fl -%s%s Oc\n.Xc\n", args[i].long_name, buf);
138 if(args[i].type == arg_strings)
139 fprintf (stderr, "...");
142 if (extra_string && *extra_string)
143 printf (".Ar %s\n", extra_string);
144 printf(".Sh DESCRIPTION\n");
145 printf("Supported options:\n");
146 printf(".Bl -tag -width Ds\n");
147 for(i = 0; i < num_args; i++){
149 if(args[i].short_name){
150 printf(".Fl %c", args[i].short_name);
151 print_arg(buf, sizeof(buf), 1, 0, args + i);
153 if(args[i].long_name)
157 if(args[i].long_name){
158 printf(".Fl -%s", args[i].long_name);
159 print_arg(buf, sizeof(buf), 1, 1, args + i);
164 printf("%s\n", args[i].help);
166 if(args[i].type == arg_strings)
167 fprintf (stderr, "...");
171 printf(".\\\".Sh ENVIRONMENT\n");
172 printf(".\\\".Sh FILES\n");
173 printf(".\\\".Sh EXAMPLES\n");
174 printf(".\\\".Sh DIAGNOSTICS\n");
175 printf(".\\\".Sh SEE ALSO\n");
176 printf(".\\\".Sh STANDARDS\n");
177 printf(".\\\".Sh HISTORY\n");
178 printf(".\\\".Sh AUTHORS\n");
179 printf(".\\\".Sh BUGS\n");
183 check_column(FILE *f, int col, int len, int columns)
185 if(col + len > columns) {
187 col = fprintf(f, " ");
193 arg_printusage (struct getargs *args,
195 const char *progname,
196 const char *extra_string)
201 int col = 0, columns;
204 if (progname == NULL)
205 progname = __progname;
207 if(getenv("GETARGMANDOC")){
208 mandoc_template(args, num_args, progname, extra_string);
211 if(get_window_size(2, &ws) == 0)
216 col += fprintf (stderr, "Usage: %s", progname);
217 for (i = 0; i < num_args; ++i) {
220 if (args[i].long_name) {
222 strlcat(buf, "[--", sizeof(buf));
224 if(args[i].type == arg_negative_flag) {
225 strlcat(buf, "no-", sizeof(buf));
228 strlcat(buf, args[i].long_name, sizeof(buf));
229 len += strlen(args[i].long_name);
230 len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf),
232 strlcat(buf, "]", sizeof(buf));
233 if(args[i].type == arg_strings)
234 strlcat(buf, "...", sizeof(buf));
235 col = check_column(stderr, col, strlen(buf) + 1, columns);
236 col += fprintf(stderr, " %s", buf);
238 if (args[i].short_name) {
239 snprintf(buf, sizeof(buf), "[-%c", args[i].short_name);
241 len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf),
243 strlcat(buf, "]", sizeof(buf));
244 if(args[i].type == arg_strings)
245 strlcat(buf, "...", sizeof(buf));
246 col = check_column(stderr, col, strlen(buf) + 1, columns);
247 col += fprintf(stderr, " %s", buf);
249 if (args[i].long_name && args[i].short_name)
251 max_len = max(max_len, len);
254 col = check_column(stderr, col, strlen(extra_string) + 1, columns);
255 fprintf (stderr, " %s\n", extra_string);
257 fprintf (stderr, "\n");
258 for (i = 0; i < num_args; ++i) {
262 if (args[i].short_name) {
263 count += fprintf (stderr, "-%c", args[i].short_name);
264 print_arg (buf, sizeof(buf), 0, 0, &args[i]);
265 count += fprintf(stderr, "%s", buf);
267 if (args[i].short_name && args[i].long_name)
268 count += fprintf (stderr, ", ");
269 if (args[i].long_name) {
270 count += fprintf (stderr, "--");
271 if (args[i].type == arg_negative_flag)
272 count += fprintf (stderr, "no-");
273 count += fprintf (stderr, "%s", args[i].long_name);
274 print_arg (buf, sizeof(buf), 0, 1, &args[i]);
275 count += fprintf(stderr, "%s", buf);
277 while(count++ <= max_len)
279 fprintf (stderr, "%s\n", args[i].help);
285 add_string(getarg_strings *s, char *value)
287 s->strings = realloc(s->strings, (s->num_strings + 1) * sizeof(*s->strings));
288 s->strings[s->num_strings] = value;
293 arg_match_long(struct getargs *args, size_t num_args,
294 char *argv, int argc, char **rargv, int *optind)
299 int partial_match = 0;
300 struct getargs *partial = NULL;
301 struct getargs *current = NULL;
305 argv_len = strlen(argv);
306 p = strchr (argv, '=');
310 for (i = 0; i < num_args; ++i) {
311 if(args[i].long_name) {
312 int len = strlen(args[i].long_name);
314 int p_len = argv_len;
318 if (strncmp (args[i].long_name, p, p_len) == 0) {
326 } else if (ISFLAG(args[i]) && strncmp (p, "no-", 3) == 0) {
338 if (current == NULL) {
339 if (partial_match == 1)
342 return ARG_ERR_NO_MATCH;
347 && current->type != arg_collect
348 && current->type != arg_counter)
349 return ARG_ERR_NO_MATCH;
350 switch(current->type){
354 if(sscanf(optarg + 1, "%d", &tmp) != 1)
355 return ARG_ERR_BAD_ARG;
356 *(int*)current->value = tmp;
361 *(char**)current->value = optarg + 1;
366 add_string((getarg_strings*)current->value, optarg + 1);
370 case arg_negative_flag:
372 int *flag = current->value;
373 if(*optarg == '\0' ||
374 strcmp(optarg + 1, "yes") == 0 ||
375 strcmp(optarg + 1, "true") == 0){
378 } else if (*optarg && strcmp(optarg + 1, "maybe") == 0) {
384 return ARG_ERR_BAD_ARG;
395 val = strtol (optarg, &endstr, 0);
396 if (endstr == optarg)
397 return ARG_ERR_BAD_ARG;
399 *(int *)current->value += val;
405 if(sscanf(optarg + 1, "%lf", &tmp) != 1)
406 return ARG_ERR_BAD_ARG;
407 *(double*)current->value = tmp;
411 struct getarg_collect_info *c = current->value;
412 int o = argv - rargv[*optind];
413 return (*c->func)(FALSE, argc, rargv, optind, &o, c->data);
422 arg_match_short (struct getargs *args, size_t num_args,
423 char *argv, int argc, char **rargv, int *optind)
427 for(j = 1; j > 0 && j < strlen(rargv[*optind]); j++) {
428 for(k = 0; k < num_args; k++) {
431 if(args[k].short_name == 0)
433 if(argv[j] == args[k].short_name) {
434 if(args[k].type == arg_flag) {
435 *(int*)args[k].value = 1;
438 if(args[k].type == arg_negative_flag) {
439 *(int*)args[k].value = 0;
442 if(args[k].type == arg_counter) {
443 ++*(int *)args[k].value;
446 if(args[k].type == arg_collect) {
447 struct getarg_collect_info *c = args[k].value;
449 if((*c->func)(TRUE, argc, rargv, optind, &j, c->data))
450 return ARG_ERR_BAD_ARG;
455 optarg = &argv[j + 1];
458 optarg = rargv[*optind];
461 return ARG_ERR_NO_ARG;
462 if(args[k].type == arg_integer) {
464 if(sscanf(optarg, "%d", &tmp) != 1)
465 return ARG_ERR_BAD_ARG;
466 *(int*)args[k].value = tmp;
468 } else if(args[k].type == arg_string) {
469 *(char**)args[k].value = optarg;
471 } else if(args[k].type == arg_strings) {
472 add_string((getarg_strings*)args[k].value, optarg);
474 } else if(args[k].type == arg_double) {
476 if(sscanf(optarg, "%lf", &tmp) != 1)
477 return ARG_ERR_BAD_ARG;
478 *(double*)args[k].value = tmp;
481 return ARG_ERR_BAD_ARG;
485 return ARG_ERR_NO_MATCH;
491 getarg(struct getargs *args, size_t num_args,
492 int argc, char **argv, int *optind)
499 for(i = *optind; i < argc; i++) {
500 if(argv[i][0] != '-')
502 if(argv[i][1] == '-'){
507 ret = arg_match_long (args, num_args, argv[i] + 2,
510 ret = arg_match_short (args, num_args, argv[i],
527 struct getargs args[] = {
528 { NULL, '1', arg_flag, &flag1, "one", NULL },
529 { NULL, '2', arg_flag, &flag2, "two", NULL },
530 { "foo", 'f', arg_negative_flag, &foo_flag, "foo", NULL },
531 { "bar", 'b', arg_integer, &bar_int, "bar", "seconds"},
532 { "baz", 'x', arg_string, &baz_string, "baz", "name" },
535 int main(int argc, char **argv)
538 while(getarg(args, 5, argc, argv, &optind))
539 printf("Bad arg: %s\n", argv[optind]);
540 printf("flag1 = %d\n", flag1);
541 printf("flag2 = %d\n", flag2);
542 printf("foo_flag = %d\n", foo_flag);
543 printf("bar_int = %d\n", bar_int);
544 printf("baz_flag = %s\n", baz_string);
545 arg_printusage (args, 5, argv[0], "nothing here");