1 /* $NetBSD: getarg.c,v 1.3 2014/04/24 13:45:34 pettai Exp $ */
4 * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 #include <krb5/roken.h>
42 #include <krb5/getarg.h>
44 #define ISFLAG(X) ((X).type == arg_flag || (X).type == arg_negative_flag)
47 print_arg (char *string
,
52 char *(i18n
)(const char *))
58 if (ISFLAG(*arg
) || (!longp
&& arg
->type
== arg_counter
))
63 strlcat(string
, "= Ns", len
);
64 strlcat(string
, " Ar ", len
);
67 strlcat (string
, "=", len
);
69 strlcat (string
, " ", len
);
73 s
= (*i18n
)(arg
->arg_help
);
74 else if (arg
->type
== arg_integer
|| arg
->type
== arg_counter
)
76 else if (arg
->type
== arg_string
)
78 else if (arg
->type
== arg_strings
)
80 else if (arg
->type
== arg_double
)
85 strlcat(string
, s
, len
);
90 mandoc_template(struct getargs
*args
,
93 const char *extra_string
,
94 char *(i18n
)(const char *))
97 char timestr
[64], cmd
[64];
102 printf(".\\\" Things to fix:\n");
103 printf(".\\\" * correct section, and operating system\n");
104 printf(".\\\" * remove Op from mandatory flags\n");
105 printf(".\\\" * use better macros for arguments (like .Pa for files)\n");
108 strftime(timestr
, sizeof(timestr
), "%B %e, %Y", localtime(&t
));
109 printf(".Dd %s\n", timestr
);
110 p
= strrchr(progname
, '/');
111 if(p
) p
++; else p
= progname
;
112 strlcpy(cmd
, p
, sizeof(cmd
));
115 printf(".Dt %s SECTION\n", cmd
);
116 printf(".Os OPERATING_SYSTEM\n");
117 printf(".Sh NAME\n");
118 printf(".Nm %s\n", p
);
119 printf(".Nd in search of a description\n");
120 printf(".Sh SYNOPSIS\n");
122 for(i
= 0; i
< num_args
; i
++){
123 /* we seem to hit a limit on number of arguments if doing
124 short and long flags with arguments -- split on two lines */
125 if(ISFLAG(args
[i
]) ||
126 args
[i
].short_name
== 0 || args
[i
].long_name
== NULL
) {
129 if(args
[i
].short_name
) {
130 print_arg(buf
, sizeof(buf
), 1, 0, args
+ i
, i18n
);
131 printf("Fl %c%s", args
[i
].short_name
, buf
);
132 if(args
[i
].long_name
)
135 if(args
[i
].long_name
) {
136 print_arg(buf
, sizeof(buf
), 1, 1, args
+ i
, i18n
);
137 printf("Fl Fl %s%s%s",
138 args
[i
].type
== arg_negative_flag
? "no-" : "",
139 args
[i
].long_name
, buf
);
143 print_arg(buf
, sizeof(buf
), 1, 0, args
+ i
, i18n
);
144 printf(".Oo Fl %c%s \\*(Ba Xo\n", args
[i
].short_name
, buf
);
145 print_arg(buf
, sizeof(buf
), 1, 1, args
+ i
, i18n
);
146 printf(".Fl Fl %s%s\n.Xc\n.Oc\n", args
[i
].long_name
, buf
);
149 if(args[i].type == arg_strings)
150 fprintf (stderr, "...");
153 if (extra_string
&& *extra_string
)
154 printf (".Ar %s\n", extra_string
);
155 printf(".Sh DESCRIPTION\n");
156 printf("Supported options:\n");
157 printf(".Bl -tag -width Ds\n");
158 for(i
= 0; i
< num_args
; i
++){
160 if(args
[i
].short_name
){
161 printf(".Fl %c", args
[i
].short_name
);
162 print_arg(buf
, sizeof(buf
), 1, 0, args
+ i
, i18n
);
164 if(args
[i
].long_name
)
168 if(args
[i
].long_name
){
169 printf(".Fl Fl %s%s",
170 args
[i
].type
== arg_negative_flag
? "no-" : "",
172 print_arg(buf
, sizeof(buf
), 1, 1, args
+ i
, i18n
);
177 printf("%s\n", args
[i
].help
);
179 if(args[i].type == arg_strings)
180 fprintf (stderr, "...");
184 printf(".\\\".Sh ENVIRONMENT\n");
185 printf(".\\\".Sh FILES\n");
186 printf(".\\\".Sh EXAMPLES\n");
187 printf(".\\\".Sh DIAGNOSTICS\n");
188 printf(".\\\".Sh SEE ALSO\n");
189 printf(".\\\".Sh STANDARDS\n");
190 printf(".\\\".Sh HISTORY\n");
191 printf(".\\\".Sh AUTHORS\n");
192 printf(".\\\".Sh BUGS\n");
196 check_column(FILE *f
, int col
, int len
, int columns
)
198 if(col
+ len
> columns
) {
200 col
= fprintf(f
, " ");
206 builtin_i18n(const char *str
)
208 return rk_UNCONST(str
);
211 ROKEN_LIB_FUNCTION
void ROKEN_LIB_CALL
212 arg_printusage (struct getargs
*args
,
214 const char *progname
,
215 const char *extra_string
)
217 arg_printusage_i18n(args
, num_args
, "Usage",
218 progname
, extra_string
, builtin_i18n
);
221 ROKEN_LIB_FUNCTION
void ROKEN_LIB_CALL
222 arg_printusage_i18n (struct getargs
*args
,
225 const char *progname
,
226 const char *extra_string
,
227 char *(*i18n
)(const char *))
229 size_t i
, max_len
= 0;
231 int col
= 0, columns
;
233 if (progname
== NULL
)
234 progname
= getprogname();
239 if(getenv("GETARGMANDOC")){
240 mandoc_template(args
, num_args
, progname
, extra_string
, i18n
);
243 if(get_window_size(2, NULL
, &columns
) == -1)
246 col
+= fprintf (stderr
, "%s: %s", usage
, progname
);
248 for (i
= 0; i
< num_args
; ++i
) {
249 if(args
[i
].short_name
&& ISFLAG(args
[i
])) {
252 strlcpy(buf
, "[-", sizeof(buf
));
253 s
[0] = args
[i
].short_name
;
255 strlcat(buf
, s
, sizeof(buf
));
259 strlcat(buf
, "]", sizeof(buf
));
260 col
= check_column(stderr
, col
, strlen(buf
) + 1, columns
);
261 col
+= fprintf(stderr
, " %s", buf
);
264 for (i
= 0; i
< num_args
; ++i
) {
267 if (args
[i
].long_name
) {
269 strlcat(buf
, "[--", sizeof(buf
));
271 if(args
[i
].type
== arg_negative_flag
) {
272 strlcat(buf
, "no-", sizeof(buf
));
275 strlcat(buf
, args
[i
].long_name
, sizeof(buf
));
276 len
+= strlen(args
[i
].long_name
);
277 len
+= print_arg(buf
+ strlen(buf
), sizeof(buf
) - strlen(buf
),
278 0, 1, &args
[i
], i18n
);
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
);
285 if (args
[i
].short_name
&& !ISFLAG(args
[i
])) {
286 snprintf(buf
, sizeof(buf
), "[-%c", args
[i
].short_name
);
288 len
+= print_arg(buf
+ strlen(buf
), sizeof(buf
) - strlen(buf
),
289 0, 0, &args
[i
], i18n
);
290 strlcat(buf
, "]", sizeof(buf
));
291 if(args
[i
].type
== arg_strings
)
292 strlcat(buf
, "...", sizeof(buf
));
293 col
= check_column(stderr
, col
, strlen(buf
) + 1, columns
);
294 col
+= fprintf(stderr
, " %s", buf
);
296 if (args
[i
].long_name
&& args
[i
].short_name
)
298 max_len
= max(max_len
, len
);
301 check_column(stderr
, col
, strlen(extra_string
) + 1, columns
);
302 fprintf (stderr
, " %s\n", extra_string
);
304 fprintf (stderr
, "\n");
305 for (i
= 0; i
< num_args
; ++i
) {
309 if (args
[i
].short_name
) {
310 count
+= fprintf (stderr
, "-%c", args
[i
].short_name
);
311 print_arg (buf
, sizeof(buf
), 0, 0, &args
[i
], i18n
);
312 count
+= fprintf(stderr
, "%s", buf
);
314 if (args
[i
].short_name
&& args
[i
].long_name
)
315 count
+= fprintf (stderr
, ", ");
316 if (args
[i
].long_name
) {
317 count
+= fprintf (stderr
, "--");
318 if (args
[i
].type
== arg_negative_flag
)
319 count
+= fprintf (stderr
, "no-");
320 count
+= fprintf (stderr
, "%s", args
[i
].long_name
);
321 print_arg (buf
, sizeof(buf
), 0, 1, &args
[i
], i18n
);
322 count
+= fprintf(stderr
, "%s", buf
);
324 while(count
++ <= max_len
)
326 fprintf (stderr
, "%s\n", (*i18n
)(args
[i
].help
));
332 add_string(getarg_strings
*s
, char *value
)
336 strings
= realloc(s
->strings
, (s
->num_strings
+ 1) * sizeof(*s
->strings
));
337 if (strings
== NULL
) {
343 s
->strings
= strings
;
344 s
->strings
[s
->num_strings
] = value
;
350 arg_match_long(struct getargs
*args
, size_t num_args
,
351 char *argv
, int argc
, char **rargv
, int *goptind
)
354 char *goptarg
= NULL
;
356 int partial_match
= 0;
357 struct getargs
*partial
= NULL
;
358 struct getargs
*current
= NULL
;
363 argv_len
= strlen(argv
);
364 p
= strchr (argv
, '=');
368 for (i
= 0; i
< num_args
; ++i
) {
369 if(args
[i
].long_name
) {
370 int len
= strlen(args
[i
].long_name
);
376 if (strncmp (args
[i
].long_name
, p
, p_len
) == 0) {
384 } else if (ISFLAG(args
[i
]) && strncmp (p
, "no-", 3) == 0) {
396 if (current
== NULL
) {
397 if (partial_match
== 1)
400 return ARG_ERR_NO_MATCH
;
405 && current
->type
!= arg_collect
406 && current
->type
!= arg_counter
)
407 return ARG_ERR_NO_MATCH
;
408 switch(current
->type
){
412 if(sscanf(goptarg
+ 1, "%d", &tmp
) != 1)
413 return ARG_ERR_BAD_ARG
;
414 *(int*)current
->value
= tmp
;
419 *(char**)current
->value
= goptarg
+ 1;
424 return add_string((getarg_strings
*)current
->value
, goptarg
+ 1);
427 case arg_negative_flag
:
429 int *flag
= current
->value
;
430 if(*goptarg
== '\0' ||
431 strcmp(goptarg
+ 1, "yes") == 0 ||
432 strcmp(goptarg
+ 1, "true") == 0){
435 } else if (*goptarg
&& strcmp(goptarg
+ 1, "maybe") == 0) {
436 *flag
= rk_random() & 1;
441 return ARG_ERR_BAD_ARG
;
447 if (*goptarg
== '\0')
449 else if(sscanf(goptarg
+ 1, "%d", &val
) != 1)
450 return ARG_ERR_BAD_ARG
;
451 *(int *)current
->value
+= val
;
457 if(sscanf(goptarg
+ 1, "%lf", &tmp
) != 1)
458 return ARG_ERR_BAD_ARG
;
459 *(double*)current
->value
= tmp
;
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
);
470 UNREACHABLE(return 0);
475 arg_match_short (struct getargs
*args
, size_t num_args
,
476 char *argv
, int argc
, char **rargv
, int *goptind
)
480 for(j
= 1; j
> 0 && j
< strlen(rargv
[*goptind
]); j
++) {
481 for(k
= 0; k
< num_args
; k
++) {
484 if(args
[k
].short_name
== 0)
486 if(argv
[j
] == args
[k
].short_name
) {
487 if(args
[k
].type
== arg_flag
) {
488 *(int*)args
[k
].value
= 1;
491 if(args
[k
].type
== arg_negative_flag
) {
492 *(int*)args
[k
].value
= 0;
495 if(args
[k
].type
== arg_counter
) {
496 ++*(int *)args
[k
].value
;
499 if(args
[k
].type
== arg_collect
) {
500 struct getarg_collect_info
*c
= args
[k
].value
;
503 if((*c
->func
)(TRUE
, argc
, rargv
, goptind
, &a
, c
->data
))
504 return ARG_ERR_BAD_ARG
;
510 goptarg
= &argv
[j
+ 1];
513 goptarg
= rargv
[*goptind
];
515 if(goptarg
== NULL
) {
517 return ARG_ERR_NO_ARG
;
519 if(args
[k
].type
== arg_integer
) {
521 if(sscanf(goptarg
, "%d", &tmp
) != 1)
522 return ARG_ERR_BAD_ARG
;
523 *(int*)args
[k
].value
= tmp
;
525 } else if(args
[k
].type
== arg_string
) {
526 *(char**)args
[k
].value
= goptarg
;
528 } else if(args
[k
].type
== arg_strings
) {
529 return add_string((getarg_strings
*)args
[k
].value
, goptarg
);
530 } else if(args
[k
].type
== arg_double
) {
532 if(sscanf(goptarg
, "%lf", &tmp
) != 1)
533 return ARG_ERR_BAD_ARG
;
534 *(double*)args
[k
].value
= tmp
;
537 return ARG_ERR_BAD_ARG
;
541 return ARG_ERR_NO_MATCH
;
546 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
547 getarg(struct getargs
*args
, size_t num_args
,
548 int argc
, char **argv
, int *goptind
)
555 for(i
= *goptind
; i
< argc
; i
++) {
556 if(argv
[i
][0] != '-')
558 if(argv
[i
][1] == '-'){
563 ret
= arg_match_long (args
, num_args
, argv
[i
] + 2,
566 ret
= arg_match_short (args
, num_args
, argv
[i
],
576 ROKEN_LIB_FUNCTION
void ROKEN_LIB_CALL
577 free_getarg_strings (getarg_strings
*s
)
589 struct getargs args
[] = {
590 { NULL
, '1', arg_flag
, &flag1
, "one", NULL
},
591 { NULL
, '2', arg_flag
, &flag2
, "two", NULL
},
592 { "foo", 'f', arg_negative_flag
, &foo_flag
, "foo", NULL
},
593 { "bar", 'b', arg_integer
, &bar_int
, "bar", "seconds"},
594 { "baz", 'x', arg_string
, &baz_string
, "baz", "name" },
597 int main(int argc
, char **argv
)
600 while(getarg(args
, 5, argc
, argv
, &goptind
))
601 printf("Bad arg: %s\n", argv
[goptind
]);
602 printf("flag1 = %d\n", flag1
);
603 printf("flag2 = %d\n", flag2
);
604 printf("foo_flag = %d\n", foo_flag
);
605 printf("bar_int = %d\n", bar_int
);
606 printf("baz_flag = %s\n", baz_string
);
607 arg_printusage (args
, 5, argv
[0], "nothing here");