Merge commit 'crater/master'
[dragonfly.git] / contrib / com_err / getarg.c
blob6978176cd0eb6fa5957a8bac3b2ee417d0568346
1 /*
2 * Copyright (c) 1997, 1998 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Kungliga Tekniska
20 * Högskolan and its contributors.
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
39 #if 0
40 RCSID("$Id: getarg.c,v 1.25 1998/11/22 09:45:05 assar Exp $");
41 #endif
43 #include <sys/ttycom.h>
44 #include <time.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include "getarg.h"
50 #define ISFLAG(X) ((X).type == arg_flag || (X).type == arg_negative_flag)
52 static size_t
53 print_arg (char *string, size_t len, int mdoc, int longp, struct getargs *arg)
55 const char *s;
57 *string = '\0';
59 if (ISFLAG(*arg))
60 return 0;
62 if(mdoc){
63 if(longp)
64 strncat(string, "= Ns", len);
65 strncat(string, " Ar ", len);
66 }else
67 if (longp)
68 strncat (string, "=", len);
69 else
70 strncat (string, " ", len);
72 if (arg->arg_help)
73 s = arg->arg_help;
74 else if (arg->type == arg_integer)
75 s = "number";
76 else if (arg->type == arg_string)
77 s = "string";
78 else
79 s = "<undefined>";
81 strncat(string, s, len);
82 return 1 + strlen(s);
85 static int
86 check_column(FILE *f, int col, int len, int columns)
88 if(col + len > columns) {
89 fprintf(f, "\n");
90 col = fprintf(f, " ");
92 return col;
95 void
96 arg_printusage (struct getargs *args,
97 size_t num_args,
98 const char *progname,
99 const char *extra_string)
101 int i;
102 size_t max_len = 0;
103 char buf[128];
104 int col = 0, columns;
105 struct winsize ws;
107 columns = 80;
108 col = 0;
109 col += fprintf (stderr, "Usage: %s", progname);
110 for (i = 0; i < num_args; ++i) {
111 size_t len = 0;
113 if (args[i].long_name) {
114 buf[0] = '\0';
115 strncat(buf, "[--", sizeof(buf));
116 len += 2;
117 if(args[i].type == arg_negative_flag) {
118 strncat(buf, "no-", sizeof(buf));
119 len += 3;
121 strncat(buf, args[i].long_name, sizeof(buf));
122 len += strlen(args[i].long_name);
123 len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf),
124 0, 1, &args[i]);
125 strncat(buf, "]", sizeof(buf));
126 if(args[i].type == arg_strings)
127 strncat(buf, "...", sizeof(buf));
128 col = check_column(stderr, col, strlen(buf) + 1, columns);
129 col += fprintf(stderr, " %s", buf);
131 if (args[i].short_name) {
132 snprintf(buf, sizeof(buf), "[-%c", args[i].short_name);
133 len += 2;
134 len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf),
135 0, 0, &args[i]);
136 strncat(buf, "]", sizeof(buf));
137 if(args[i].type == arg_strings)
138 strncat(buf, "...", sizeof(buf));
139 col = check_column(stderr, col, strlen(buf) + 1, columns);
140 col += fprintf(stderr, " %s", buf);
142 if (args[i].long_name && args[i].short_name)
143 len += 2; /* ", " */
144 max_len = max(max_len, len);
146 if (extra_string) {
147 col = check_column(stderr, col, strlen(extra_string) + 1, columns);
148 fprintf (stderr, " %s\n", extra_string);
149 } else
150 fprintf (stderr, "\n");
151 for (i = 0; i < num_args; ++i) {
152 if (args[i].help) {
153 size_t count = 0;
155 if (args[i].short_name) {
156 count += fprintf (stderr, "-%c", args[i].short_name);
157 print_arg (buf, sizeof(buf), 0, 0, &args[i]);
158 count += fprintf(stderr, "%s", buf);
160 if (args[i].short_name && args[i].long_name)
161 count += fprintf (stderr, ", ");
162 if (args[i].long_name) {
163 count += fprintf (stderr, "--");
164 if (args[i].type == arg_negative_flag)
165 count += fprintf (stderr, "no-");
166 count += fprintf (stderr, "%s", args[i].long_name);
167 print_arg (buf, sizeof(buf), 0, 1, &args[i]);
168 count += fprintf(stderr, "%s", buf);
170 while(count++ <= max_len)
171 putc (' ', stderr);
172 fprintf (stderr, "%s\n", args[i].help);
177 static void
178 add_string(getarg_strings *s, char *value)
180 s->strings = realloc(s->strings,
181 (s->num_strings + 1) * sizeof(*s->strings));
182 s->strings[s->num_strings] = value;
183 s->num_strings++;
186 static int
187 arg_match_long(struct getargs *args, size_t num_args,
188 char *argv)
190 int i;
191 char *optarg = NULL;
192 int negate = 0;
193 int partial_match = 0;
194 struct getargs *partial = NULL;
195 struct getargs *current = NULL;
196 int argv_len;
197 char *p;
199 argv_len = strlen(argv);
200 p = strchr (argv, '=');
201 if (p != NULL)
202 argv_len = p - argv;
204 for (i = 0; i < num_args; ++i) {
205 if(args[i].long_name) {
206 int len = strlen(args[i].long_name);
207 char *p = argv;
208 int p_len = argv_len;
209 negate = 0;
211 for (;;) {
212 if (strncmp (args[i].long_name, p, p_len) == 0) {
213 if(p_len == len)
214 current = &args[i];
215 else {
216 ++partial_match;
217 partial = &args[i];
219 optarg = p + p_len;
220 } else if (ISFLAG(args[i]) && strncmp (p, "no-", 3) == 0) {
221 negate = !negate;
222 p += 3;
223 p_len -= 3;
224 continue;
226 break;
228 if (current)
229 break;
232 if (current == NULL) {
233 if (partial_match == 1)
234 current = partial;
235 else
236 return ARG_ERR_NO_MATCH;
239 if(*optarg == '\0' && !ISFLAG(*current))
240 return ARG_ERR_NO_MATCH;
241 switch(current->type){
242 case arg_integer:
244 int tmp;
245 if(sscanf(optarg + 1, "%d", &tmp) != 1)
246 return ARG_ERR_BAD_ARG;
247 *(int*)current->value = tmp;
248 return 0;
250 case arg_string:
252 *(char**)current->value = optarg + 1;
253 return 0;
255 case arg_strings:
257 add_string((getarg_strings*)current->value, optarg + 1);
258 return 0;
260 case arg_flag:
261 case arg_negative_flag:
263 int *flag = current->value;
264 if(*optarg == '\0' ||
265 strcmp(optarg + 1, "yes") == 0 ||
266 strcmp(optarg + 1, "true") == 0){
267 *flag = !negate;
268 return 0;
269 } else if (*optarg && strcmp(optarg + 1, "maybe") == 0) {
270 *flag = rand() & 1;
271 } else {
272 *flag = negate;
273 return 0;
275 return ARG_ERR_BAD_ARG;
277 default:
278 abort ();
283 getarg(struct getargs *args, size_t num_args,
284 int argc, char **argv, int *optind)
286 int i, j, k;
287 int ret = 0;
289 srand (time(NULL));
290 (*optind)++;
291 for(i = *optind; i < argc; i++) {
292 if(argv[i][0] != '-')
293 break;
294 if(argv[i][1] == '-'){
295 if(argv[i][2] == 0){
296 i++;
297 break;
299 ret = arg_match_long (args, num_args, argv[i] + 2);
300 if(ret)
301 return ret;
302 }else{
303 for(j = 1; argv[i][j]; j++) {
304 for(k = 0; k < num_args; k++) {
305 char *optarg;
306 if(args[k].short_name == 0)
307 continue;
308 if(argv[i][j] == args[k].short_name){
309 if(args[k].type == arg_flag){
310 *(int*)args[k].value = 1;
311 break;
313 if(args[k].type == arg_negative_flag){
314 *(int*)args[k].value = 0;
315 break;
317 if(argv[i][j + 1])
318 optarg = &argv[i][j + 1];
319 else{
320 i++;
321 optarg = argv[i];
323 if(optarg == NULL)
324 return ARG_ERR_NO_ARG;
325 if(args[k].type == arg_integer){
326 int tmp;
327 if(sscanf(optarg, "%d", &tmp) != 1)
328 return ARG_ERR_BAD_ARG;
329 *(int*)args[k].value = tmp;
330 goto out;
331 }else if(args[k].type == arg_string){
332 *(char**)args[k].value = optarg;
333 goto out;
334 }else if(args[k].type == arg_strings){
335 add_string((getarg_strings*)args[k].value, optarg);
336 goto out;
338 return ARG_ERR_BAD_ARG;
342 if (k == num_args)
343 return ARG_ERR_NO_MATCH;
345 out:;
348 *optind = i;
349 return 0;
352 #if TEST
353 int foo_flag = 2;
354 int flag1 = 0;
355 int flag2 = 0;
356 int bar_int;
357 char *baz_string;
359 struct getargs args[] = {
360 { NULL, '1', arg_flag, &flag1, "one", NULL },
361 { NULL, '2', arg_flag, &flag2, "two", NULL },
362 { "foo", 'f', arg_negative_flag, &foo_flag, "foo", NULL },
363 { "bar", 'b', arg_integer, &bar_int, "bar", "seconds"},
364 { "baz", 'x', arg_string, &baz_string, "baz", "name" },
367 int main(int argc, char **argv)
369 int optind = 0;
370 while(getarg(args, 5, argc, argv, &optind))
371 printf("Bad arg: %s\n", argv[optind]);
372 printf("flag1 = %d\n", flag1);
373 printf("flag2 = %d\n", flag2);
374 printf("foo_flag = %d\n", foo_flag);
375 printf("bar_int = %d\n", bar_int);
376 printf("baz_flag = %s\n", baz_string);
377 arg_printusage (args, 5, argv[0], "nothing here");
379 #endif