]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/com_err/getarg.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / com_err / getarg.c
1 /*
2  * Copyright (c) 1997, 1998 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. 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. 
21  *
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. 
25  *
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. 
37  *
38  * $FreeBSD$
39  */
40
41 #if 0
42 RCSID("$Id: getarg.c,v 1.25 1998/11/22 09:45:05 assar Exp $");
43 #endif
44
45 #include <sys/ttycom.h>
46 #include <time.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include "getarg.h"
50
51 #define ISFLAG(X) ((X).type == arg_flag || (X).type == arg_negative_flag)
52
53 static size_t
54 print_arg (char *string, size_t len, int mdoc, int longp, struct getargs *arg)
55 {
56     const char *s;
57
58     *string = '\0';
59
60     if (ISFLAG(*arg))
61         return 0;
62
63     if(mdoc){
64         if(longp)
65             strncat(string, "= Ns", len);
66         strncat(string, " Ar ", len);
67     }else
68         if (longp)
69             strncat (string, "=", len);
70         else
71             strncat (string, " ", len);
72
73     if (arg->arg_help)
74         s = arg->arg_help;
75     else if (arg->type == arg_integer)
76         s = "number";
77     else if (arg->type == arg_string)
78         s = "string";
79     else
80         s = "<undefined>";
81
82     strncat(string, s, len);
83     return 1 + strlen(s);
84 }
85
86 static int
87 check_column(FILE *f, int col, int len, int columns)
88 {
89     if(col + len > columns) {
90         fprintf(f, "\n");
91         col = fprintf(f, "  ");
92     }
93     return col;
94 }
95
96 void
97 arg_printusage (struct getargs *args,
98                 size_t num_args,
99                 const char *progname,
100                 const char *extra_string)
101 {
102     int i;
103     size_t max_len = 0;
104     char buf[128];
105     int col = 0, columns;
106     struct winsize ws;
107
108     columns = 80;
109     col = 0;
110     col += fprintf (stderr, "Usage: %s", progname);
111     for (i = 0; i < num_args; ++i) {
112         size_t len = 0;
113
114         if (args[i].long_name) {
115             buf[0] = '\0';
116             strncat(buf, "[--", sizeof(buf));
117             len += 2;
118             if(args[i].type == arg_negative_flag) {
119                 strncat(buf, "no-", sizeof(buf));
120                 len += 3;
121             }
122             strncat(buf, args[i].long_name, sizeof(buf));
123             len += strlen(args[i].long_name);
124             len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf), 
125                              0, 1, &args[i]);
126             strncat(buf, "]", sizeof(buf));
127             if(args[i].type == arg_strings)
128                 strncat(buf, "...", sizeof(buf));
129             col = check_column(stderr, col, strlen(buf) + 1, columns);
130             col += fprintf(stderr, " %s", buf);
131         }
132         if (args[i].short_name) {
133             snprintf(buf, sizeof(buf), "[-%c", args[i].short_name);
134             len += 2;
135             len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf), 
136                              0, 0, &args[i]);
137             strncat(buf, "]", sizeof(buf));
138             if(args[i].type == arg_strings)
139                 strncat(buf, "...", sizeof(buf));
140             col = check_column(stderr, col, strlen(buf) + 1, columns);
141             col += fprintf(stderr, " %s", buf);
142         }
143         if (args[i].long_name && args[i].short_name)
144             len += 2; /* ", " */
145         max_len = max(max_len, len);
146     }
147     if (extra_string) {
148         col = check_column(stderr, col, strlen(extra_string) + 1, columns);
149         fprintf (stderr, " %s\n", extra_string);
150     } else
151         fprintf (stderr, "\n");
152     for (i = 0; i < num_args; ++i) {
153         if (args[i].help) {
154             size_t count = 0;
155
156             if (args[i].short_name) {
157                 count += fprintf (stderr, "-%c", args[i].short_name);
158                 print_arg (buf, sizeof(buf), 0, 0, &args[i]);
159                 count += fprintf(stderr, "%s", buf);
160             }
161             if (args[i].short_name && args[i].long_name)
162                 count += fprintf (stderr, ", ");
163             if (args[i].long_name) {
164                 count += fprintf (stderr, "--");
165                 if (args[i].type == arg_negative_flag)
166                     count += fprintf (stderr, "no-");
167                 count += fprintf (stderr, "%s", args[i].long_name);
168                 print_arg (buf, sizeof(buf), 0, 1, &args[i]);
169                 count += fprintf(stderr, "%s", buf);
170             }
171             while(count++ <= max_len)
172                 putc (' ', stderr);
173             fprintf (stderr, "%s\n", args[i].help);
174         }
175     }
176 }
177
178 static void
179 add_string(getarg_strings *s, char *value)
180 {
181     s->strings = realloc(s->strings, (s->num_strings + 1) * sizeof(*s->strings));
182     s->strings[s->num_strings] = value;
183     s->num_strings++;
184 }
185
186 static int
187 arg_match_long(struct getargs *args, size_t num_args,
188                char *argv)
189 {
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;
198
199     argv_len = strlen(argv);
200     p = strchr (argv, '=');
201     if (p != NULL)
202         argv_len = p - argv;
203
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;
210
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];
218                     }
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;
225                 }
226                 break;
227             }
228             if (current)
229                 break;
230         }
231     }
232     if (current == NULL) {
233         if (partial_match == 1)
234             current = partial;
235         else
236             return ARG_ERR_NO_MATCH;
237     }
238     
239     if(*optarg == '\0' && !ISFLAG(*current))
240         return ARG_ERR_NO_MATCH;
241     switch(current->type){
242     case arg_integer:
243     {
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;
249     }
250     case arg_string:
251     {
252         *(char**)current->value = optarg + 1;
253         return 0;
254     }
255     case arg_strings:
256     {
257         add_string((getarg_strings*)current->value, optarg + 1);
258         return 0;
259     }
260     case arg_flag:
261     case arg_negative_flag:
262     {
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;
274         }
275         return ARG_ERR_BAD_ARG;
276     }
277     default:
278         abort ();
279     }
280 }
281
282 int
283 getarg(struct getargs *args, size_t num_args, 
284        int argc, char **argv, int *optind)
285 {
286     int i, j, k;
287     int ret = 0;
288
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;
298             }
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;
312                         }
313                         if(args[k].type == arg_negative_flag){
314                             *(int*)args[k].value = 0;
315                             break;
316                         }
317                         if(argv[i][j + 1])
318                             optarg = &argv[i][j + 1];
319                         else{
320                             i++;
321                             optarg = argv[i];
322                         }
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;
337                         }
338                         return ARG_ERR_BAD_ARG;
339                     }
340                         
341                 }
342                 if (k == num_args)
343                     return ARG_ERR_NO_MATCH;
344             }
345         out:;
346         }
347     }
348     *optind = i;
349     return 0;
350 }
351
352 #if TEST
353 int foo_flag = 2;
354 int flag1 = 0;
355 int flag2 = 0;
356 int bar_int;
357 char *baz_string;
358
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" },
365 };
366
367 int main(int argc, char **argv)
368 {
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");
378 }
379 #endif