Home | History | Annotate | Line # | Download | only in roken
getarg.c revision 1.5
      1  1.5  christos /*	$NetBSD: getarg.c,v 1.5 2017/01/29 19:23:28 christos Exp $	*/
      2  1.1     elric 
      3  1.1     elric /*
      4  1.1     elric  * Copyright (c) 1997 - 2002 Kungliga Tekniska Hgskolan
      5  1.1     elric  * (Royal Institute of Technology, Stockholm, Sweden).
      6  1.1     elric  * All rights reserved.
      7  1.1     elric  *
      8  1.1     elric  * Redistribution and use in source and binary forms, with or without
      9  1.1     elric  * modification, are permitted provided that the following conditions
     10  1.1     elric  * are met:
     11  1.1     elric  *
     12  1.1     elric  * 1. Redistributions of source code must retain the above copyright
     13  1.1     elric  *    notice, this list of conditions and the following disclaimer.
     14  1.1     elric  *
     15  1.1     elric  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1     elric  *    notice, this list of conditions and the following disclaimer in the
     17  1.1     elric  *    documentation and/or other materials provided with the distribution.
     18  1.1     elric  *
     19  1.1     elric  * 3. Neither the name of the Institute nor the names of its contributors
     20  1.1     elric  *    may be used to endorse or promote products derived from this software
     21  1.1     elric  *    without specific prior written permission.
     22  1.1     elric  *
     23  1.1     elric  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     24  1.1     elric  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  1.1     elric  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  1.1     elric  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     27  1.1     elric  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  1.1     elric  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  1.1     elric  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  1.1     elric  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  1.1     elric  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  1.1     elric  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  1.1     elric  * SUCH DAMAGE.
     34  1.1     elric  */
     35  1.1     elric 
     36  1.1     elric #include <config.h>
     37  1.1     elric 
     38  1.1     elric #include <stdio.h>
     39  1.1     elric #include <stdlib.h>
     40  1.1     elric #include <string.h>
     41  1.1     elric #include <krb5/roken.h>
     42  1.5  christos #include <getarg.h>
     43  1.1     elric 
     44  1.1     elric #define ISFLAG(X) ((X).type == arg_flag || (X).type == arg_negative_flag)
     45  1.1     elric 
     46  1.1     elric static size_t
     47  1.1     elric print_arg (char *string,
     48  1.1     elric 	   size_t len,
     49  1.1     elric 	   int mdoc,
     50  1.1     elric 	   int longp,
     51  1.1     elric 	   struct getargs *arg,
     52  1.1     elric 	   char *(i18n)(const char *))
     53  1.1     elric {
     54  1.1     elric     const char *s;
     55  1.1     elric 
     56  1.1     elric     *string = '\0';
     57  1.1     elric 
     58  1.1     elric     if (ISFLAG(*arg) || (!longp && arg->type == arg_counter))
     59  1.1     elric 	return 0;
     60  1.1     elric 
     61  1.1     elric     if(mdoc){
     62  1.1     elric 	if(longp)
     63  1.1     elric 	    strlcat(string, "= Ns", len);
     64  1.1     elric 	strlcat(string, " Ar ", len);
     65  1.1     elric     } else {
     66  1.1     elric 	if (longp)
     67  1.1     elric 	    strlcat (string, "=", len);
     68  1.1     elric 	else
     69  1.1     elric 	    strlcat (string, " ", len);
     70  1.1     elric     }
     71  1.1     elric 
     72  1.1     elric     if (arg->arg_help)
     73  1.1     elric 	s = (*i18n)(arg->arg_help);
     74  1.1     elric     else if (arg->type == arg_integer || arg->type == arg_counter)
     75  1.1     elric 	s = "integer";
     76  1.1     elric     else if (arg->type == arg_string)
     77  1.1     elric 	s = "string";
     78  1.1     elric     else if (arg->type == arg_strings)
     79  1.1     elric 	s = "strings";
     80  1.1     elric     else if (arg->type == arg_double)
     81  1.1     elric 	s = "float";
     82  1.1     elric     else
     83  1.1     elric 	s = "<undefined>";
     84  1.1     elric 
     85  1.1     elric     strlcat(string, s, len);
     86  1.1     elric     return 1 + strlen(s);
     87  1.1     elric }
     88  1.1     elric 
     89  1.1     elric static void
     90  1.1     elric mandoc_template(struct getargs *args,
     91  1.1     elric 		size_t num_args,
     92  1.1     elric 		const char *progname,
     93  1.1     elric 		const char *extra_string,
     94  1.1     elric 		char *(i18n)(const char *))
     95  1.1     elric {
     96  1.1     elric     size_t i;
     97  1.1     elric     char timestr[64], cmd[64];
     98  1.1     elric     char buf[128];
     99  1.1     elric     const char *p;
    100  1.1     elric     time_t t;
    101  1.1     elric 
    102  1.1     elric     printf(".\\\" Things to fix:\n");
    103  1.1     elric     printf(".\\\"   * correct section, and operating system\n");
    104  1.1     elric     printf(".\\\"   * remove Op from mandatory flags\n");
    105  1.1     elric     printf(".\\\"   * use better macros for arguments (like .Pa for files)\n");
    106  1.1     elric     printf(".\\\"\n");
    107  1.1     elric     t = time(NULL);
    108  1.1     elric     strftime(timestr, sizeof(timestr), "%B %e, %Y", localtime(&t));
    109  1.1     elric     printf(".Dd %s\n", timestr);
    110  1.1     elric     p = strrchr(progname, '/');
    111  1.1     elric     if(p) p++; else p = progname;
    112  1.1     elric     strlcpy(cmd, p, sizeof(cmd));
    113  1.1     elric     strupr(cmd);
    114  1.1     elric 
    115  1.1     elric     printf(".Dt %s SECTION\n", cmd);
    116  1.1     elric     printf(".Os OPERATING_SYSTEM\n");
    117  1.1     elric     printf(".Sh NAME\n");
    118  1.1     elric     printf(".Nm %s\n", p);
    119  1.3    pettai     printf(".Nd in search of a description\n");
    120  1.1     elric     printf(".Sh SYNOPSIS\n");
    121  1.1     elric     printf(".Nm\n");
    122  1.1     elric     for(i = 0; i < num_args; i++){
    123  1.1     elric 	/* we seem to hit a limit on number of arguments if doing
    124  1.1     elric            short and long flags with arguments -- split on two lines */
    125  1.1     elric 	if(ISFLAG(args[i]) ||
    126  1.1     elric 	   args[i].short_name == 0 || args[i].long_name == NULL) {
    127  1.1     elric 	    printf(".Op ");
    128  1.1     elric 
    129  1.1     elric 	    if(args[i].short_name) {
    130  1.1     elric 		print_arg(buf, sizeof(buf), 1, 0, args + i, i18n);
    131  1.1     elric 		printf("Fl %c%s", args[i].short_name, buf);
    132  1.1     elric 		if(args[i].long_name)
    133  1.1     elric 		    printf(" | ");
    134  1.1     elric 	    }
    135  1.1     elric 	    if(args[i].long_name) {
    136  1.1     elric 		print_arg(buf, sizeof(buf), 1, 1, args + i, i18n);
    137  1.3    pettai 		printf("Fl Fl %s%s%s",
    138  1.1     elric 		       args[i].type == arg_negative_flag ? "no-" : "",
    139  1.1     elric 		       args[i].long_name, buf);
    140  1.1     elric 	    }
    141  1.1     elric 	    printf("\n");
    142  1.1     elric 	} else {
    143  1.1     elric 	    print_arg(buf, sizeof(buf), 1, 0, args + i, i18n);
    144  1.1     elric 	    printf(".Oo Fl %c%s \\*(Ba Xo\n", args[i].short_name, buf);
    145  1.1     elric 	    print_arg(buf, sizeof(buf), 1, 1, args + i, i18n);
    146  1.3    pettai 	    printf(".Fl Fl %s%s\n.Xc\n.Oc\n", args[i].long_name, buf);
    147  1.1     elric 	}
    148  1.1     elric     /*
    149  1.1     elric 	    if(args[i].type == arg_strings)
    150  1.1     elric 		fprintf (stderr, "...");
    151  1.1     elric 		*/
    152  1.1     elric     }
    153  1.1     elric     if (extra_string && *extra_string)
    154  1.1     elric 	printf (".Ar %s\n", extra_string);
    155  1.1     elric     printf(".Sh DESCRIPTION\n");
    156  1.1     elric     printf("Supported options:\n");
    157  1.1     elric     printf(".Bl -tag -width Ds\n");
    158  1.1     elric     for(i = 0; i < num_args; i++){
    159  1.1     elric 	printf(".It Xo\n");
    160  1.1     elric 	if(args[i].short_name){
    161  1.1     elric 	    printf(".Fl %c", args[i].short_name);
    162  1.1     elric 	    print_arg(buf, sizeof(buf), 1, 0, args + i, i18n);
    163  1.1     elric 	    printf("%s", buf);
    164  1.1     elric 	    if(args[i].long_name)
    165  1.1     elric 		printf(" ,");
    166  1.1     elric 	    printf("\n");
    167  1.1     elric 	}
    168  1.1     elric 	if(args[i].long_name){
    169  1.3    pettai 	    printf(".Fl Fl %s%s",
    170  1.1     elric 		   args[i].type == arg_negative_flag ? "no-" : "",
    171  1.1     elric 		   args[i].long_name);
    172  1.1     elric 	    print_arg(buf, sizeof(buf), 1, 1, args + i, i18n);
    173  1.1     elric 	    printf("%s\n", buf);
    174  1.1     elric 	}
    175  1.1     elric 	printf(".Xc\n");
    176  1.1     elric 	if(args[i].help)
    177  1.1     elric 	    printf("%s\n", args[i].help);
    178  1.1     elric     /*
    179  1.1     elric 	    if(args[i].type == arg_strings)
    180  1.1     elric 		fprintf (stderr, "...");
    181  1.1     elric 		*/
    182  1.1     elric     }
    183  1.1     elric     printf(".El\n");
    184  1.1     elric     printf(".\\\".Sh ENVIRONMENT\n");
    185  1.1     elric     printf(".\\\".Sh FILES\n");
    186  1.1     elric     printf(".\\\".Sh EXAMPLES\n");
    187  1.1     elric     printf(".\\\".Sh DIAGNOSTICS\n");
    188  1.1     elric     printf(".\\\".Sh SEE ALSO\n");
    189  1.1     elric     printf(".\\\".Sh STANDARDS\n");
    190  1.1     elric     printf(".\\\".Sh HISTORY\n");
    191  1.1     elric     printf(".\\\".Sh AUTHORS\n");
    192  1.1     elric     printf(".\\\".Sh BUGS\n");
    193  1.1     elric }
    194  1.1     elric 
    195  1.1     elric static int
    196  1.1     elric check_column(FILE *f, int col, int len, int columns)
    197  1.1     elric {
    198  1.1     elric     if(col + len > columns) {
    199  1.1     elric 	fprintf(f, "\n");
    200  1.1     elric 	col = fprintf(f, "  ");
    201  1.1     elric     }
    202  1.1     elric     return col;
    203  1.1     elric }
    204  1.1     elric 
    205  1.1     elric static char *
    206  1.1     elric builtin_i18n(const char *str)
    207  1.1     elric {
    208  1.1     elric     return rk_UNCONST(str);
    209  1.1     elric }
    210  1.1     elric 
    211  1.1     elric ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
    212  1.1     elric arg_printusage (struct getargs *args,
    213  1.1     elric 		size_t num_args,
    214  1.1     elric 		const char *progname,
    215  1.1     elric 		const char *extra_string)
    216  1.1     elric {
    217  1.1     elric     arg_printusage_i18n(args, num_args, "Usage",
    218  1.1     elric 			progname, extra_string, builtin_i18n);
    219  1.1     elric }
    220  1.1     elric 
    221  1.1     elric ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
    222  1.1     elric arg_printusage_i18n (struct getargs *args,
    223  1.1     elric 		     size_t num_args,
    224  1.1     elric 		     const char *usage,
    225  1.1     elric 		     const char *progname,
    226  1.1     elric 		     const char *extra_string,
    227  1.1     elric 		     char *(*i18n)(const char *))
    228  1.1     elric {
    229  1.1     elric     size_t i, max_len = 0;
    230  1.1     elric     char buf[128];
    231  1.1     elric     int col = 0, columns;
    232  1.1     elric 
    233  1.1     elric     if (progname == NULL)
    234  1.1     elric 	progname = getprogname();
    235  1.1     elric 
    236  1.1     elric     if (i18n == NULL)
    237  1.1     elric 	i18n = builtin_i18n;
    238  1.1     elric 
    239  1.1     elric     if(getenv("GETARGMANDOC")){
    240  1.1     elric 	mandoc_template(args, num_args, progname, extra_string, i18n);
    241  1.1     elric 	return;
    242  1.1     elric     }
    243  1.2     elric     if(get_window_size(2, NULL, &columns) == -1)
    244  1.1     elric 	columns = 80;
    245  1.1     elric     col = 0;
    246  1.1     elric     col += fprintf (stderr, "%s: %s", usage, progname);
    247  1.1     elric     buf[0] = '\0';
    248  1.1     elric     for (i = 0; i < num_args; ++i) {
    249  1.1     elric 	if(args[i].short_name && ISFLAG(args[i])) {
    250  1.1     elric 	    char s[2];
    251  1.1     elric 	    if(buf[0] == '\0')
    252  1.1     elric 		strlcpy(buf, "[-", sizeof(buf));
    253  1.1     elric 	    s[0] = args[i].short_name;
    254  1.1     elric 	    s[1] = '\0';
    255  1.1     elric 	    strlcat(buf, s, sizeof(buf));
    256  1.1     elric 	}
    257  1.1     elric     }
    258  1.1     elric     if(buf[0] != '\0') {
    259  1.1     elric 	strlcat(buf, "]", sizeof(buf));
    260  1.1     elric 	col = check_column(stderr, col, strlen(buf) + 1, columns);
    261  1.1     elric 	col += fprintf(stderr, " %s", buf);
    262  1.1     elric     }
    263  1.1     elric 
    264  1.1     elric     for (i = 0; i < num_args; ++i) {
    265  1.1     elric 	size_t len = 0;
    266  1.1     elric 
    267  1.1     elric 	if (args[i].long_name) {
    268  1.1     elric 	    buf[0] = '\0';
    269  1.1     elric 	    strlcat(buf, "[--", sizeof(buf));
    270  1.1     elric 	    len += 2;
    271  1.1     elric 	    if(args[i].type == arg_negative_flag) {
    272  1.1     elric 		strlcat(buf, "no-", sizeof(buf));
    273  1.1     elric 		len += 3;
    274  1.1     elric 	    }
    275  1.1     elric 	    strlcat(buf, args[i].long_name, sizeof(buf));
    276  1.1     elric 	    len += strlen(args[i].long_name);
    277  1.1     elric 	    len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf),
    278  1.1     elric 			     0, 1, &args[i], i18n);
    279  1.1     elric 	    strlcat(buf, "]", sizeof(buf));
    280  1.1     elric 	    if(args[i].type == arg_strings)
    281  1.1     elric 		strlcat(buf, "...", sizeof(buf));
    282  1.1     elric 	    col = check_column(stderr, col, strlen(buf) + 1, columns);
    283  1.1     elric 	    col += fprintf(stderr, " %s", buf);
    284  1.1     elric 	}
    285  1.1     elric 	if (args[i].short_name && !ISFLAG(args[i])) {
    286  1.1     elric 	    snprintf(buf, sizeof(buf), "[-%c", args[i].short_name);
    287  1.1     elric 	    len += 2;
    288  1.1     elric 	    len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf),
    289  1.1     elric 			     0, 0, &args[i], i18n);
    290  1.1     elric 	    strlcat(buf, "]", sizeof(buf));
    291  1.1     elric 	    if(args[i].type == arg_strings)
    292  1.1     elric 		strlcat(buf, "...", sizeof(buf));
    293  1.1     elric 	    col = check_column(stderr, col, strlen(buf) + 1, columns);
    294  1.1     elric 	    col += fprintf(stderr, " %s", buf);
    295  1.1     elric 	}
    296  1.1     elric 	if (args[i].long_name && args[i].short_name)
    297  1.1     elric 	    len += 2; /* ", " */
    298  1.1     elric 	max_len = max(max_len, len);
    299  1.1     elric     }
    300  1.1     elric     if (extra_string) {
    301  1.1     elric 	check_column(stderr, col, strlen(extra_string) + 1, columns);
    302  1.1     elric 	fprintf (stderr, " %s\n", extra_string);
    303  1.1     elric     } else
    304  1.1     elric 	fprintf (stderr, "\n");
    305  1.1     elric     for (i = 0; i < num_args; ++i) {
    306  1.1     elric 	if (args[i].help) {
    307  1.1     elric 	    size_t count = 0;
    308  1.1     elric 
    309  1.1     elric 	    if (args[i].short_name) {
    310  1.1     elric 		count += fprintf (stderr, "-%c", args[i].short_name);
    311  1.1     elric 		print_arg (buf, sizeof(buf), 0, 0, &args[i], i18n);
    312  1.1     elric 		count += fprintf(stderr, "%s", buf);
    313  1.1     elric 	    }
    314  1.1     elric 	    if (args[i].short_name && args[i].long_name)
    315  1.1     elric 		count += fprintf (stderr, ", ");
    316  1.1     elric 	    if (args[i].long_name) {
    317  1.1     elric 		count += fprintf (stderr, "--");
    318  1.1     elric 		if (args[i].type == arg_negative_flag)
    319  1.1     elric 		    count += fprintf (stderr, "no-");
    320  1.1     elric 		count += fprintf (stderr, "%s", args[i].long_name);
    321  1.1     elric 		print_arg (buf, sizeof(buf), 0, 1, &args[i], i18n);
    322  1.1     elric 		count += fprintf(stderr, "%s", buf);
    323  1.1     elric 	    }
    324  1.1     elric 	    while(count++ <= max_len)
    325  1.1     elric 		putc (' ', stderr);
    326  1.1     elric 	    fprintf (stderr, "%s\n", (*i18n)(args[i].help));
    327  1.1     elric 	}
    328  1.1     elric     }
    329  1.1     elric }
    330  1.1     elric 
    331  1.1     elric static int
    332  1.1     elric add_string(getarg_strings *s, char *value)
    333  1.1     elric {
    334  1.1     elric     char **strings;
    335  1.1     elric 
    336  1.1     elric     strings = realloc(s->strings, (s->num_strings + 1) * sizeof(*s->strings));
    337  1.1     elric     if (strings == NULL) {
    338  1.1     elric 	free(s->strings);
    339  1.1     elric 	s->strings = NULL;
    340  1.1     elric 	s->num_strings = 0;
    341  1.1     elric 	return ENOMEM;
    342  1.1     elric     }
    343  1.1     elric     s->strings = strings;
    344  1.1     elric     s->strings[s->num_strings] = value;
    345  1.1     elric     s->num_strings++;
    346  1.1     elric     return 0;
    347  1.1     elric }
    348  1.1     elric 
    349  1.1     elric static int
    350  1.1     elric arg_match_long(struct getargs *args, size_t num_args,
    351  1.1     elric 	       char *argv, int argc, char **rargv, int *goptind)
    352  1.1     elric {
    353  1.3    pettai     size_t i;
    354  1.1     elric     char *goptarg = NULL;
    355  1.1     elric     int negate = 0;
    356  1.1     elric     int partial_match = 0;
    357  1.1     elric     struct getargs *partial = NULL;
    358  1.1     elric     struct getargs *current = NULL;
    359  1.1     elric     int argv_len;
    360  1.1     elric     char *p;
    361  1.1     elric     int p_len;
    362  1.1     elric 
    363  1.1     elric     argv_len = strlen(argv);
    364  1.1     elric     p = strchr (argv, '=');
    365  1.1     elric     if (p != NULL)
    366  1.1     elric 	argv_len = p - argv;
    367  1.1     elric 
    368  1.1     elric     for (i = 0; i < num_args; ++i) {
    369  1.1     elric 	if(args[i].long_name) {
    370  1.1     elric 	    int len = strlen(args[i].long_name);
    371  1.1     elric 	    p = argv;
    372  1.1     elric 	    p_len = argv_len;
    373  1.1     elric 	    negate = 0;
    374  1.1     elric 
    375  1.1     elric 	    for (;;) {
    376  1.1     elric 		if (strncmp (args[i].long_name, p, p_len) == 0) {
    377  1.1     elric 		    if(p_len == len)
    378  1.1     elric 			current = &args[i];
    379  1.1     elric 		    else {
    380  1.1     elric 			++partial_match;
    381  1.1     elric 			partial = &args[i];
    382  1.1     elric 		    }
    383  1.1     elric 		    goptarg  = p + p_len;
    384  1.1     elric 		} else if (ISFLAG(args[i]) && strncmp (p, "no-", 3) == 0) {
    385  1.1     elric 		    negate = !negate;
    386  1.1     elric 		    p += 3;
    387  1.1     elric 		    p_len -= 3;
    388  1.1     elric 		    continue;
    389  1.1     elric 		}
    390  1.1     elric 		break;
    391  1.1     elric 	    }
    392  1.1     elric 	    if (current)
    393  1.1     elric 		break;
    394  1.1     elric 	}
    395  1.1     elric     }
    396  1.1     elric     if (current == NULL) {
    397  1.1     elric 	if (partial_match == 1)
    398  1.1     elric 	    current = partial;
    399  1.1     elric 	else
    400  1.1     elric 	    return ARG_ERR_NO_MATCH;
    401  1.1     elric     }
    402  1.1     elric 
    403  1.1     elric     if(*goptarg == '\0'
    404  1.1     elric        && !ISFLAG(*current)
    405  1.1     elric        && current->type != arg_collect
    406  1.1     elric        && current->type != arg_counter)
    407  1.1     elric 	return ARG_ERR_NO_MATCH;
    408  1.1     elric     switch(current->type){
    409  1.1     elric     case arg_integer:
    410  1.1     elric     {
    411  1.1     elric 	int tmp;
    412  1.1     elric 	if(sscanf(goptarg + 1, "%d", &tmp) != 1)
    413  1.1     elric 	    return ARG_ERR_BAD_ARG;
    414  1.1     elric 	*(int*)current->value = tmp;
    415  1.1     elric 	return 0;
    416  1.1     elric     }
    417  1.1     elric     case arg_string:
    418  1.1     elric     {
    419  1.1     elric 	*(char**)current->value = goptarg + 1;
    420  1.1     elric 	return 0;
    421  1.1     elric     }
    422  1.1     elric     case arg_strings:
    423  1.1     elric     {
    424  1.1     elric 	return add_string((getarg_strings*)current->value, goptarg + 1);
    425  1.1     elric     }
    426  1.1     elric     case arg_flag:
    427  1.1     elric     case arg_negative_flag:
    428  1.1     elric     {
    429  1.1     elric 	int *flag = current->value;
    430  1.1     elric 	if(*goptarg == '\0' ||
    431  1.1     elric 	   strcmp(goptarg + 1, "yes") == 0 ||
    432  1.1     elric 	   strcmp(goptarg + 1, "true") == 0){
    433  1.1     elric 	    *flag = !negate;
    434  1.1     elric 	    return 0;
    435  1.1     elric 	} else if (*goptarg && strcmp(goptarg + 1, "maybe") == 0) {
    436  1.1     elric 	    *flag = rk_random() & 1;
    437  1.1     elric 	} else {
    438  1.1     elric 	    *flag = negate;
    439  1.1     elric 	    return 0;
    440  1.1     elric 	}
    441  1.1     elric 	return ARG_ERR_BAD_ARG;
    442  1.1     elric     }
    443  1.1     elric     case arg_counter :
    444  1.1     elric     {
    445  1.1     elric 	int val;
    446  1.1     elric 
    447  1.1     elric 	if (*goptarg == '\0')
    448  1.1     elric 	    val = 1;
    449  1.1     elric 	else if(sscanf(goptarg + 1, "%d", &val) != 1)
    450  1.1     elric 	    return ARG_ERR_BAD_ARG;
    451  1.1     elric 	*(int *)current->value += val;
    452  1.1     elric 	return 0;
    453  1.1     elric     }
    454  1.1     elric     case arg_double:
    455  1.1     elric     {
    456  1.1     elric 	double tmp;
    457  1.1     elric 	if(sscanf(goptarg + 1, "%lf", &tmp) != 1)
    458  1.1     elric 	    return ARG_ERR_BAD_ARG;
    459  1.1     elric 	*(double*)current->value = tmp;
    460  1.1     elric 	return 0;
    461  1.1     elric     }
    462  1.1     elric     case arg_collect:{
    463  1.1     elric 	struct getarg_collect_info *c = current->value;
    464  1.1     elric 	int o = argv - rargv[*goptind];
    465  1.1     elric 	return (*c->func)(FALSE, argc, rargv, goptind, &o, c->data);
    466  1.1     elric     }
    467  1.1     elric 
    468  1.1     elric     default:
    469  1.1     elric 	abort ();
    470  1.1     elric 	UNREACHABLE(return 0);
    471  1.1     elric     }
    472  1.1     elric }
    473  1.1     elric 
    474  1.1     elric static int
    475  1.1     elric arg_match_short (struct getargs *args, size_t num_args,
    476  1.1     elric 		 char *argv, int argc, char **rargv, int *goptind)
    477  1.1     elric {
    478  1.3    pettai     size_t j, k;
    479  1.1     elric 
    480  1.1     elric     for(j = 1; j > 0 && j < strlen(rargv[*goptind]); j++) {
    481  1.1     elric 	for(k = 0; k < num_args; k++) {
    482  1.1     elric 	    char *goptarg;
    483  1.1     elric 
    484  1.1     elric 	    if(args[k].short_name == 0)
    485  1.1     elric 		continue;
    486  1.1     elric 	    if(argv[j] == args[k].short_name) {
    487  1.1     elric 		if(args[k].type == arg_flag) {
    488  1.1     elric 		    *(int*)args[k].value = 1;
    489  1.1     elric 		    break;
    490  1.1     elric 		}
    491  1.1     elric 		if(args[k].type == arg_negative_flag) {
    492  1.1     elric 		    *(int*)args[k].value = 0;
    493  1.1     elric 		    break;
    494  1.1     elric 		}
    495  1.1     elric 		if(args[k].type == arg_counter) {
    496  1.1     elric 		    ++*(int *)args[k].value;
    497  1.1     elric 		    break;
    498  1.1     elric 		}
    499  1.1     elric 		if(args[k].type == arg_collect) {
    500  1.1     elric 		    struct getarg_collect_info *c = args[k].value;
    501  1.3    pettai 		    int a = (int)j;
    502  1.1     elric 
    503  1.3    pettai 		    if((*c->func)(TRUE, argc, rargv, goptind, &a, c->data))
    504  1.1     elric 			return ARG_ERR_BAD_ARG;
    505  1.3    pettai 		    j = a;
    506  1.1     elric 		    break;
    507  1.1     elric 		}
    508  1.1     elric 
    509  1.1     elric 		if(argv[j + 1])
    510  1.1     elric 		    goptarg = &argv[j + 1];
    511  1.1     elric 		else {
    512  1.1     elric 		    ++*goptind;
    513  1.1     elric 		    goptarg = rargv[*goptind];
    514  1.1     elric 		}
    515  1.1     elric 		if(goptarg == NULL) {
    516  1.1     elric 		    --*goptind;
    517  1.1     elric 		    return ARG_ERR_NO_ARG;
    518  1.1     elric 		}
    519  1.1     elric 		if(args[k].type == arg_integer) {
    520  1.1     elric 		    int tmp;
    521  1.1     elric 		    if(sscanf(goptarg, "%d", &tmp) != 1)
    522  1.1     elric 			return ARG_ERR_BAD_ARG;
    523  1.1     elric 		    *(int*)args[k].value = tmp;
    524  1.1     elric 		    return 0;
    525  1.1     elric 		} else if(args[k].type == arg_string) {
    526  1.1     elric 		    *(char**)args[k].value = goptarg;
    527  1.1     elric 		    return 0;
    528  1.1     elric 		} else if(args[k].type == arg_strings) {
    529  1.1     elric 		    return add_string((getarg_strings*)args[k].value, goptarg);
    530  1.1     elric 		} else if(args[k].type == arg_double) {
    531  1.1     elric 		    double tmp;
    532  1.1     elric 		    if(sscanf(goptarg, "%lf", &tmp) != 1)
    533  1.1     elric 			return ARG_ERR_BAD_ARG;
    534  1.1     elric 		    *(double*)args[k].value = tmp;
    535  1.1     elric 		    return 0;
    536  1.1     elric 		}
    537  1.1     elric 		return ARG_ERR_BAD_ARG;
    538  1.1     elric 	    }
    539  1.1     elric 	}
    540  1.1     elric 	if (k == num_args)
    541  1.1     elric 	    return ARG_ERR_NO_MATCH;
    542  1.1     elric     }
    543  1.1     elric     return 0;
    544  1.1     elric }
    545  1.1     elric 
    546  1.1     elric ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
    547  1.1     elric getarg(struct getargs *args, size_t num_args,
    548  1.1     elric        int argc, char **argv, int *goptind)
    549  1.1     elric {
    550  1.1     elric     int i;
    551  1.1     elric     int ret = 0;
    552  1.1     elric 
    553  1.1     elric     rk_random_init();
    554  1.1     elric     (*goptind)++;
    555  1.1     elric     for(i = *goptind; i < argc; i++) {
    556  1.1     elric 	if(argv[i][0] != '-')
    557  1.1     elric 	    break;
    558  1.1     elric 	if(argv[i][1] == '-'){
    559  1.1     elric 	    if(argv[i][2] == 0){
    560  1.1     elric 		i++;
    561  1.1     elric 		break;
    562  1.1     elric 	    }
    563  1.1     elric 	    ret = arg_match_long (args, num_args, argv[i] + 2,
    564  1.1     elric 				  argc, argv, &i);
    565  1.1     elric 	} else {
    566  1.1     elric 	    ret = arg_match_short (args, num_args, argv[i],
    567  1.1     elric 				   argc, argv, &i);
    568  1.1     elric 	}
    569  1.1     elric 	if(ret)
    570  1.1     elric 	    break;
    571  1.1     elric     }
    572  1.1     elric     *goptind = i;
    573  1.1     elric     return ret;
    574  1.1     elric }
    575  1.1     elric 
    576  1.1     elric ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
    577  1.1     elric free_getarg_strings (getarg_strings *s)
    578  1.1     elric {
    579  1.1     elric     free (s->strings);
    580  1.1     elric }
    581  1.1     elric 
    582  1.1     elric #if TEST
    583  1.1     elric int foo_flag = 2;
    584  1.1     elric int flag1 = 0;
    585  1.1     elric int flag2 = 0;
    586  1.1     elric int bar_int;
    587  1.1     elric char *baz_string;
    588  1.1     elric 
    589  1.1     elric struct getargs args[] = {
    590  1.1     elric     { NULL, '1', arg_flag, &flag1, "one", NULL },
    591  1.1     elric     { NULL, '2', arg_flag, &flag2, "two", NULL },
    592  1.1     elric     { "foo", 'f', arg_negative_flag, &foo_flag, "foo", NULL },
    593  1.1     elric     { "bar", 'b', arg_integer, &bar_int, "bar", "seconds"},
    594  1.1     elric     { "baz", 'x', arg_string, &baz_string, "baz", "name" },
    595  1.1     elric };
    596  1.1     elric 
    597  1.1     elric int main(int argc, char **argv)
    598  1.1     elric {
    599  1.1     elric     int goptind = 0;
    600  1.4  christos     while (getarg(args, 5, argc, argv, &goptind))
    601  1.1     elric 	printf("Bad arg: %s\n", argv[goptind]);
    602  1.1     elric     printf("flag1 = %d\n", flag1);
    603  1.1     elric     printf("flag2 = %d\n", flag2);
    604  1.1     elric     printf("foo_flag = %d\n", foo_flag);
    605  1.1     elric     printf("bar_int = %d\n", bar_int);
    606  1.1     elric     printf("baz_flag = %s\n", baz_string);
    607  1.1     elric     arg_printusage (args, 5, argv[0], "nothing here");
    608  1.1     elric }
    609  1.1     elric #endif
    610