155682Smarkm/*
2233294Sstas * Copyright (c) 1997 - 2002 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
955682Smarkm *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
2055682Smarkm *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include <config.h>
3555682Smarkm
3655682Smarkm#include <stdio.h>
3772445Sassar#include <stdlib.h>
3872445Sassar#include <string.h>
39178825Sdfr#include "roken.h"
4055682Smarkm#include "getarg.h"
4155682Smarkm
4255682Smarkm#define ISFLAG(X) ((X).type == arg_flag || (X).type == arg_negative_flag)
4355682Smarkm
4455682Smarkmstatic size_t
45233294Sstasprint_arg (char *string,
46233294Sstas	   size_t len,
47233294Sstas	   int mdoc,
48233294Sstas	   int longp,
49233294Sstas	   struct getargs *arg,
50233294Sstas	   char *(i18n)(const char *))
5155682Smarkm{
5255682Smarkm    const char *s;
5355682Smarkm
5455682Smarkm    *string = '\0';
5555682Smarkm
5655682Smarkm    if (ISFLAG(*arg) || (!longp && arg->type == arg_counter))
5755682Smarkm	return 0;
5855682Smarkm
5955682Smarkm    if(mdoc){
6055682Smarkm	if(longp)
6155682Smarkm	    strlcat(string, "= Ns", len);
6255682Smarkm	strlcat(string, " Ar ", len);
6372445Sassar    } else {
6455682Smarkm	if (longp)
6555682Smarkm	    strlcat (string, "=", len);
6655682Smarkm	else
6755682Smarkm	    strlcat (string, " ", len);
6872445Sassar    }
6955682Smarkm
7055682Smarkm    if (arg->arg_help)
71233294Sstas	s = (*i18n)(arg->arg_help);
7255682Smarkm    else if (arg->type == arg_integer || arg->type == arg_counter)
7355682Smarkm	s = "integer";
7455682Smarkm    else if (arg->type == arg_string)
7555682Smarkm	s = "string";
7672445Sassar    else if (arg->type == arg_strings)
7772445Sassar	s = "strings";
7855682Smarkm    else if (arg->type == arg_double)
7955682Smarkm	s = "float";
8055682Smarkm    else
8155682Smarkm	s = "<undefined>";
8255682Smarkm
8355682Smarkm    strlcat(string, s, len);
8455682Smarkm    return 1 + strlen(s);
8555682Smarkm}
8655682Smarkm
8755682Smarkmstatic void
8855682Smarkmmandoc_template(struct getargs *args,
8955682Smarkm		size_t num_args,
9055682Smarkm		const char *progname,
91233294Sstas		const char *extra_string,
92233294Sstas		char *(i18n)(const char *))
9355682Smarkm{
94233294Sstas    size_t i;
9555682Smarkm    char timestr[64], cmd[64];
9655682Smarkm    char buf[128];
9755682Smarkm    const char *p;
9855682Smarkm    time_t t;
9955682Smarkm
10055682Smarkm    printf(".\\\" Things to fix:\n");
10155682Smarkm    printf(".\\\"   * correct section, and operating system\n");
10255682Smarkm    printf(".\\\"   * remove Op from mandatory flags\n");
10355682Smarkm    printf(".\\\"   * use better macros for arguments (like .Pa for files)\n");
10455682Smarkm    printf(".\\\"\n");
10555682Smarkm    t = time(NULL);
10655682Smarkm    strftime(timestr, sizeof(timestr), "%B %e, %Y", localtime(&t));
10755682Smarkm    printf(".Dd %s\n", timestr);
10855682Smarkm    p = strrchr(progname, '/');
10955682Smarkm    if(p) p++; else p = progname;
11055682Smarkm    strlcpy(cmd, p, sizeof(cmd));
11155682Smarkm    strupr(cmd);
112233294Sstas
11355682Smarkm    printf(".Dt %s SECTION\n", cmd);
11455682Smarkm    printf(".Os OPERATING_SYSTEM\n");
11555682Smarkm    printf(".Sh NAME\n");
11655682Smarkm    printf(".Nm %s\n", p);
117233294Sstas    printf(".Nd in search of a description\n");
11855682Smarkm    printf(".Sh SYNOPSIS\n");
11955682Smarkm    printf(".Nm\n");
12055682Smarkm    for(i = 0; i < num_args; i++){
12155682Smarkm	/* we seem to hit a limit on number of arguments if doing
12255682Smarkm           short and long flags with arguments -- split on two lines */
123233294Sstas	if(ISFLAG(args[i]) ||
12455682Smarkm	   args[i].short_name == 0 || args[i].long_name == NULL) {
12555682Smarkm	    printf(".Op ");
12655682Smarkm
12755682Smarkm	    if(args[i].short_name) {
128233294Sstas		print_arg(buf, sizeof(buf), 1, 0, args + i, i18n);
12955682Smarkm		printf("Fl %c%s", args[i].short_name, buf);
13055682Smarkm		if(args[i].long_name)
13155682Smarkm		    printf(" | ");
13255682Smarkm	    }
13355682Smarkm	    if(args[i].long_name) {
134233294Sstas		print_arg(buf, sizeof(buf), 1, 1, args + i, i18n);
135233294Sstas		printf("Fl Fl %s%s%s",
13657419Smarkm		       args[i].type == arg_negative_flag ? "no-" : "",
13757419Smarkm		       args[i].long_name, buf);
13855682Smarkm	    }
13955682Smarkm	    printf("\n");
14055682Smarkm	} else {
141233294Sstas	    print_arg(buf, sizeof(buf), 1, 0, args + i, i18n);
14255682Smarkm	    printf(".Oo Fl %c%s \\*(Ba Xo\n", args[i].short_name, buf);
143233294Sstas	    print_arg(buf, sizeof(buf), 1, 1, args + i, i18n);
144233294Sstas	    printf(".Fl Fl %s%s\n.Xc\n.Oc\n", args[i].long_name, buf);
14555682Smarkm	}
14655682Smarkm    /*
14755682Smarkm	    if(args[i].type == arg_strings)
14855682Smarkm		fprintf (stderr, "...");
14955682Smarkm		*/
15055682Smarkm    }
15155682Smarkm    if (extra_string && *extra_string)
15255682Smarkm	printf (".Ar %s\n", extra_string);
15355682Smarkm    printf(".Sh DESCRIPTION\n");
15455682Smarkm    printf("Supported options:\n");
15555682Smarkm    printf(".Bl -tag -width Ds\n");
15655682Smarkm    for(i = 0; i < num_args; i++){
15755682Smarkm	printf(".It Xo\n");
15855682Smarkm	if(args[i].short_name){
15955682Smarkm	    printf(".Fl %c", args[i].short_name);
160233294Sstas	    print_arg(buf, sizeof(buf), 1, 0, args + i, i18n);
16155682Smarkm	    printf("%s", buf);
16255682Smarkm	    if(args[i].long_name)
163102644Snectar		printf(" ,");
16455682Smarkm	    printf("\n");
16555682Smarkm	}
16655682Smarkm	if(args[i].long_name){
167233294Sstas	    printf(".Fl Fl %s%s",
16857419Smarkm		   args[i].type == arg_negative_flag ? "no-" : "",
16957419Smarkm		   args[i].long_name);
170233294Sstas	    print_arg(buf, sizeof(buf), 1, 1, args + i, i18n);
17155682Smarkm	    printf("%s\n", buf);
17255682Smarkm	}
17355682Smarkm	printf(".Xc\n");
17455682Smarkm	if(args[i].help)
17555682Smarkm	    printf("%s\n", args[i].help);
17655682Smarkm    /*
17755682Smarkm	    if(args[i].type == arg_strings)
17855682Smarkm		fprintf (stderr, "...");
17955682Smarkm		*/
18055682Smarkm    }
18155682Smarkm    printf(".El\n");
18255682Smarkm    printf(".\\\".Sh ENVIRONMENT\n");
18355682Smarkm    printf(".\\\".Sh FILES\n");
18455682Smarkm    printf(".\\\".Sh EXAMPLES\n");
18555682Smarkm    printf(".\\\".Sh DIAGNOSTICS\n");
18655682Smarkm    printf(".\\\".Sh SEE ALSO\n");
18755682Smarkm    printf(".\\\".Sh STANDARDS\n");
18855682Smarkm    printf(".\\\".Sh HISTORY\n");
18955682Smarkm    printf(".\\\".Sh AUTHORS\n");
19055682Smarkm    printf(".\\\".Sh BUGS\n");
19155682Smarkm}
19255682Smarkm
19355682Smarkmstatic int
19455682Smarkmcheck_column(FILE *f, int col, int len, int columns)
19555682Smarkm{
19655682Smarkm    if(col + len > columns) {
19755682Smarkm	fprintf(f, "\n");
19855682Smarkm	col = fprintf(f, "  ");
19955682Smarkm    }
20055682Smarkm    return col;
20155682Smarkm}
20255682Smarkm
203233294Sstasstatic char *
204233294Sstasbuiltin_i18n(const char *str)
205233294Sstas{
206233294Sstas    return rk_UNCONST(str);
207233294Sstas}
208233294Sstas
209233294SstasROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
21055682Smarkmarg_printusage (struct getargs *args,
21155682Smarkm		size_t num_args,
21255682Smarkm		const char *progname,
21355682Smarkm		const char *extra_string)
21455682Smarkm{
215233294Sstas    arg_printusage_i18n(args, num_args, "Usage",
216233294Sstas			progname, extra_string, builtin_i18n);
217233294Sstas}
218233294Sstas
219233294SstasROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
220233294Sstasarg_printusage_i18n (struct getargs *args,
221233294Sstas		     size_t num_args,
222233294Sstas		     const char *usage,
223233294Sstas		     const char *progname,
224233294Sstas		     const char *extra_string,
225233294Sstas		     char *(*i18n)(const char *))
226233294Sstas{
227233294Sstas    size_t i, max_len = 0;
22855682Smarkm    char buf[128];
22955682Smarkm    int col = 0, columns;
23055682Smarkm
23155682Smarkm    if (progname == NULL)
23278527Sassar	progname = getprogname();
23355682Smarkm
234233294Sstas    if (i18n == NULL)
235233294Sstas	i18n = builtin_i18n;
236233294Sstas
23755682Smarkm    if(getenv("GETARGMANDOC")){
238233294Sstas	mandoc_template(args, num_args, progname, extra_string, i18n);
23955682Smarkm	return;
24055682Smarkm    }
241233294Sstas    if(get_window_size(2, NULL, &columns) == -1)
24255682Smarkm	columns = 80;
24355682Smarkm    col = 0;
244233294Sstas    col += fprintf (stderr, "%s: %s", usage, progname);
24578527Sassar    buf[0] = '\0';
24655682Smarkm    for (i = 0; i < num_args; ++i) {
24778527Sassar	if(args[i].short_name && ISFLAG(args[i])) {
24878527Sassar	    char s[2];
24978527Sassar	    if(buf[0] == '\0')
25078527Sassar		strlcpy(buf, "[-", sizeof(buf));
25178527Sassar	    s[0] = args[i].short_name;
25278527Sassar	    s[1] = '\0';
25378527Sassar	    strlcat(buf, s, sizeof(buf));
25478527Sassar	}
25578527Sassar    }
25678527Sassar    if(buf[0] != '\0') {
25778527Sassar	strlcat(buf, "]", sizeof(buf));
25878527Sassar	col = check_column(stderr, col, strlen(buf) + 1, columns);
25978527Sassar	col += fprintf(stderr, " %s", buf);
26078527Sassar    }
26178527Sassar
26278527Sassar    for (i = 0; i < num_args; ++i) {
26355682Smarkm	size_t len = 0;
26455682Smarkm
26555682Smarkm	if (args[i].long_name) {
26655682Smarkm	    buf[0] = '\0';
26755682Smarkm	    strlcat(buf, "[--", sizeof(buf));
26855682Smarkm	    len += 2;
26955682Smarkm	    if(args[i].type == arg_negative_flag) {
27055682Smarkm		strlcat(buf, "no-", sizeof(buf));
27155682Smarkm		len += 3;
27255682Smarkm	    }
27355682Smarkm	    strlcat(buf, args[i].long_name, sizeof(buf));
27455682Smarkm	    len += strlen(args[i].long_name);
275233294Sstas	    len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf),
276233294Sstas			     0, 1, &args[i], i18n);
27755682Smarkm	    strlcat(buf, "]", sizeof(buf));
27855682Smarkm	    if(args[i].type == arg_strings)
27955682Smarkm		strlcat(buf, "...", sizeof(buf));
28055682Smarkm	    col = check_column(stderr, col, strlen(buf) + 1, columns);
28155682Smarkm	    col += fprintf(stderr, " %s", buf);
28255682Smarkm	}
28378527Sassar	if (args[i].short_name && !ISFLAG(args[i])) {
28455682Smarkm	    snprintf(buf, sizeof(buf), "[-%c", args[i].short_name);
28555682Smarkm	    len += 2;
286233294Sstas	    len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf),
287233294Sstas			     0, 0, &args[i], i18n);
28855682Smarkm	    strlcat(buf, "]", sizeof(buf));
28955682Smarkm	    if(args[i].type == arg_strings)
29055682Smarkm		strlcat(buf, "...", sizeof(buf));
29155682Smarkm	    col = check_column(stderr, col, strlen(buf) + 1, columns);
29255682Smarkm	    col += fprintf(stderr, " %s", buf);
29355682Smarkm	}
29455682Smarkm	if (args[i].long_name && args[i].short_name)
29555682Smarkm	    len += 2; /* ", " */
29655682Smarkm	max_len = max(max_len, len);
29755682Smarkm    }
29855682Smarkm    if (extra_string) {
299233294Sstas	check_column(stderr, col, strlen(extra_string) + 1, columns);
30055682Smarkm	fprintf (stderr, " %s\n", extra_string);
30155682Smarkm    } else
30255682Smarkm	fprintf (stderr, "\n");
30355682Smarkm    for (i = 0; i < num_args; ++i) {
30455682Smarkm	if (args[i].help) {
30555682Smarkm	    size_t count = 0;
30655682Smarkm
30755682Smarkm	    if (args[i].short_name) {
30855682Smarkm		count += fprintf (stderr, "-%c", args[i].short_name);
309233294Sstas		print_arg (buf, sizeof(buf), 0, 0, &args[i], i18n);
31055682Smarkm		count += fprintf(stderr, "%s", buf);
31155682Smarkm	    }
31255682Smarkm	    if (args[i].short_name && args[i].long_name)
31355682Smarkm		count += fprintf (stderr, ", ");
31455682Smarkm	    if (args[i].long_name) {
31555682Smarkm		count += fprintf (stderr, "--");
31655682Smarkm		if (args[i].type == arg_negative_flag)
31755682Smarkm		    count += fprintf (stderr, "no-");
31855682Smarkm		count += fprintf (stderr, "%s", args[i].long_name);
319233294Sstas		print_arg (buf, sizeof(buf), 0, 1, &args[i], i18n);
32055682Smarkm		count += fprintf(stderr, "%s", buf);
32155682Smarkm	    }
32255682Smarkm	    while(count++ <= max_len)
32355682Smarkm		putc (' ', stderr);
324233294Sstas	    fprintf (stderr, "%s\n", (*i18n)(args[i].help));
32555682Smarkm	}
32655682Smarkm    }
32755682Smarkm}
32855682Smarkm
329178825Sdfrstatic int
33055682Smarkmadd_string(getarg_strings *s, char *value)
33155682Smarkm{
332178825Sdfr    char **strings;
333178825Sdfr
334178825Sdfr    strings = realloc(s->strings, (s->num_strings + 1) * sizeof(*s->strings));
335178825Sdfr    if (strings == NULL) {
336178825Sdfr	free(s->strings);
337178825Sdfr	s->strings = NULL;
338178825Sdfr	s->num_strings = 0;
339178825Sdfr	return ENOMEM;
340178825Sdfr    }
341178825Sdfr    s->strings = strings;
34255682Smarkm    s->strings[s->num_strings] = value;
34355682Smarkm    s->num_strings++;
344178825Sdfr    return 0;
34555682Smarkm}
34655682Smarkm
34755682Smarkmstatic int
34855682Smarkmarg_match_long(struct getargs *args, size_t num_args,
349102644Snectar	       char *argv, int argc, char **rargv, int *goptind)
35055682Smarkm{
351233294Sstas    size_t i;
352102644Snectar    char *goptarg = NULL;
35355682Smarkm    int negate = 0;
35455682Smarkm    int partial_match = 0;
35555682Smarkm    struct getargs *partial = NULL;
35655682Smarkm    struct getargs *current = NULL;
35755682Smarkm    int argv_len;
35855682Smarkm    char *p;
359102644Snectar    int p_len;
36055682Smarkm
36155682Smarkm    argv_len = strlen(argv);
36255682Smarkm    p = strchr (argv, '=');
36355682Smarkm    if (p != NULL)
36455682Smarkm	argv_len = p - argv;
36555682Smarkm
36655682Smarkm    for (i = 0; i < num_args; ++i) {
36755682Smarkm	if(args[i].long_name) {
36855682Smarkm	    int len = strlen(args[i].long_name);
369102644Snectar	    p = argv;
370102644Snectar	    p_len = argv_len;
37155682Smarkm	    negate = 0;
37255682Smarkm
37355682Smarkm	    for (;;) {
37455682Smarkm		if (strncmp (args[i].long_name, p, p_len) == 0) {
37555682Smarkm		    if(p_len == len)
37655682Smarkm			current = &args[i];
37755682Smarkm		    else {
37855682Smarkm			++partial_match;
37955682Smarkm			partial = &args[i];
38055682Smarkm		    }
381102644Snectar		    goptarg  = p + p_len;
38255682Smarkm		} else if (ISFLAG(args[i]) && strncmp (p, "no-", 3) == 0) {
38355682Smarkm		    negate = !negate;
38455682Smarkm		    p += 3;
38555682Smarkm		    p_len -= 3;
38655682Smarkm		    continue;
38755682Smarkm		}
38855682Smarkm		break;
38955682Smarkm	    }
39055682Smarkm	    if (current)
39155682Smarkm		break;
39255682Smarkm	}
39355682Smarkm    }
39455682Smarkm    if (current == NULL) {
39555682Smarkm	if (partial_match == 1)
39655682Smarkm	    current = partial;
39755682Smarkm	else
39855682Smarkm	    return ARG_ERR_NO_MATCH;
39955682Smarkm    }
400233294Sstas
401102644Snectar    if(*goptarg == '\0'
40255682Smarkm       && !ISFLAG(*current)
40355682Smarkm       && current->type != arg_collect
40455682Smarkm       && current->type != arg_counter)
40555682Smarkm	return ARG_ERR_NO_MATCH;
40655682Smarkm    switch(current->type){
40755682Smarkm    case arg_integer:
40855682Smarkm    {
40955682Smarkm	int tmp;
410102644Snectar	if(sscanf(goptarg + 1, "%d", &tmp) != 1)
41155682Smarkm	    return ARG_ERR_BAD_ARG;
41255682Smarkm	*(int*)current->value = tmp;
41355682Smarkm	return 0;
41455682Smarkm    }
41555682Smarkm    case arg_string:
41655682Smarkm    {
417102644Snectar	*(char**)current->value = goptarg + 1;
41855682Smarkm	return 0;
41955682Smarkm    }
42055682Smarkm    case arg_strings:
42155682Smarkm    {
422178825Sdfr	return add_string((getarg_strings*)current->value, goptarg + 1);
42355682Smarkm    }
42455682Smarkm    case arg_flag:
42555682Smarkm    case arg_negative_flag:
42655682Smarkm    {
42755682Smarkm	int *flag = current->value;
428102644Snectar	if(*goptarg == '\0' ||
429233294Sstas	   strcmp(goptarg + 1, "yes") == 0 ||
430102644Snectar	   strcmp(goptarg + 1, "true") == 0){
43155682Smarkm	    *flag = !negate;
43255682Smarkm	    return 0;
433102644Snectar	} else if (*goptarg && strcmp(goptarg + 1, "maybe") == 0) {
434233294Sstas	    *flag = rk_random() & 1;
43555682Smarkm	} else {
43655682Smarkm	    *flag = negate;
43755682Smarkm	    return 0;
43855682Smarkm	}
43955682Smarkm	return ARG_ERR_BAD_ARG;
44055682Smarkm    }
44155682Smarkm    case arg_counter :
44255682Smarkm    {
44355682Smarkm	int val;
44455682Smarkm
445102644Snectar	if (*goptarg == '\0')
44655682Smarkm	    val = 1;
447102644Snectar	else if(sscanf(goptarg + 1, "%d", &val) != 1)
44890926Snectar	    return ARG_ERR_BAD_ARG;
44955682Smarkm	*(int *)current->value += val;
45055682Smarkm	return 0;
45155682Smarkm    }
45255682Smarkm    case arg_double:
45355682Smarkm    {
45455682Smarkm	double tmp;
455102644Snectar	if(sscanf(goptarg + 1, "%lf", &tmp) != 1)
45655682Smarkm	    return ARG_ERR_BAD_ARG;
45755682Smarkm	*(double*)current->value = tmp;
45855682Smarkm	return 0;
45955682Smarkm    }
46055682Smarkm    case arg_collect:{
46155682Smarkm	struct getarg_collect_info *c = current->value;
462102644Snectar	int o = argv - rargv[*goptind];
463102644Snectar	return (*c->func)(FALSE, argc, rargv, goptind, &o, c->data);
46455682Smarkm    }
46555682Smarkm
46655682Smarkm    default:
46755682Smarkm	abort ();
468233294Sstas	UNREACHABLE(return 0);
46955682Smarkm    }
47055682Smarkm}
47155682Smarkm
47255682Smarkmstatic int
47355682Smarkmarg_match_short (struct getargs *args, size_t num_args,
474102644Snectar		 char *argv, int argc, char **rargv, int *goptind)
47555682Smarkm{
476233294Sstas    size_t j, k;
47755682Smarkm
478102644Snectar    for(j = 1; j > 0 && j < strlen(rargv[*goptind]); j++) {
47955682Smarkm	for(k = 0; k < num_args; k++) {
480102644Snectar	    char *goptarg;
48155682Smarkm
48255682Smarkm	    if(args[k].short_name == 0)
48355682Smarkm		continue;
48455682Smarkm	    if(argv[j] == args[k].short_name) {
48555682Smarkm		if(args[k].type == arg_flag) {
48655682Smarkm		    *(int*)args[k].value = 1;
48755682Smarkm		    break;
48855682Smarkm		}
48955682Smarkm		if(args[k].type == arg_negative_flag) {
49055682Smarkm		    *(int*)args[k].value = 0;
49155682Smarkm		    break;
492233294Sstas		}
49355682Smarkm		if(args[k].type == arg_counter) {
49455682Smarkm		    ++*(int *)args[k].value;
49555682Smarkm		    break;
49655682Smarkm		}
49755682Smarkm		if(args[k].type == arg_collect) {
49855682Smarkm		    struct getarg_collect_info *c = args[k].value;
499233294Sstas		    int a = (int)j;
50055682Smarkm
501233294Sstas		    if((*c->func)(TRUE, argc, rargv, goptind, &a, c->data))
50255682Smarkm			return ARG_ERR_BAD_ARG;
503233294Sstas		    j = a;
50455682Smarkm		    break;
50555682Smarkm		}
50655682Smarkm
50755682Smarkm		if(argv[j + 1])
508102644Snectar		    goptarg = &argv[j + 1];
50955682Smarkm		else {
510102644Snectar		    ++*goptind;
511102644Snectar		    goptarg = rargv[*goptind];
51255682Smarkm		}
513102644Snectar		if(goptarg == NULL) {
514102644Snectar		    --*goptind;
51555682Smarkm		    return ARG_ERR_NO_ARG;
51672445Sassar		}
51755682Smarkm		if(args[k].type == arg_integer) {
51855682Smarkm		    int tmp;
519102644Snectar		    if(sscanf(goptarg, "%d", &tmp) != 1)
52055682Smarkm			return ARG_ERR_BAD_ARG;
52155682Smarkm		    *(int*)args[k].value = tmp;
52255682Smarkm		    return 0;
52355682Smarkm		} else if(args[k].type == arg_string) {
524102644Snectar		    *(char**)args[k].value = goptarg;
52555682Smarkm		    return 0;
52655682Smarkm		} else if(args[k].type == arg_strings) {
527178825Sdfr		    return add_string((getarg_strings*)args[k].value, goptarg);
52855682Smarkm		} else if(args[k].type == arg_double) {
52955682Smarkm		    double tmp;
530102644Snectar		    if(sscanf(goptarg, "%lf", &tmp) != 1)
53155682Smarkm			return ARG_ERR_BAD_ARG;
53255682Smarkm		    *(double*)args[k].value = tmp;
53355682Smarkm		    return 0;
53455682Smarkm		}
53555682Smarkm		return ARG_ERR_BAD_ARG;
53655682Smarkm	    }
53755682Smarkm	}
53855682Smarkm	if (k == num_args)
53955682Smarkm	    return ARG_ERR_NO_MATCH;
54055682Smarkm    }
54155682Smarkm    return 0;
54255682Smarkm}
54355682Smarkm
544233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
545233294Sstasgetarg(struct getargs *args, size_t num_args,
546102644Snectar       int argc, char **argv, int *goptind)
54755682Smarkm{
54855682Smarkm    int i;
54955682Smarkm    int ret = 0;
55055682Smarkm
551233294Sstas    rk_random_init();
552102644Snectar    (*goptind)++;
553102644Snectar    for(i = *goptind; i < argc; i++) {
55455682Smarkm	if(argv[i][0] != '-')
55555682Smarkm	    break;
55655682Smarkm	if(argv[i][1] == '-'){
55755682Smarkm	    if(argv[i][2] == 0){
55855682Smarkm		i++;
55955682Smarkm		break;
56055682Smarkm	    }
561233294Sstas	    ret = arg_match_long (args, num_args, argv[i] + 2,
56255682Smarkm				  argc, argv, &i);
56355682Smarkm	} else {
56455682Smarkm	    ret = arg_match_short (args, num_args, argv[i],
56555682Smarkm				   argc, argv, &i);
56655682Smarkm	}
56755682Smarkm	if(ret)
56855682Smarkm	    break;
56955682Smarkm    }
570102644Snectar    *goptind = i;
57155682Smarkm    return ret;
57255682Smarkm}
57355682Smarkm
574233294SstasROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
57578527Sassarfree_getarg_strings (getarg_strings *s)
57678527Sassar{
57778527Sassar    free (s->strings);
57878527Sassar}
57978527Sassar
58055682Smarkm#if TEST
58155682Smarkmint foo_flag = 2;
58255682Smarkmint flag1 = 0;
58355682Smarkmint flag2 = 0;
58455682Smarkmint bar_int;
58555682Smarkmchar *baz_string;
58655682Smarkm
58755682Smarkmstruct getargs args[] = {
58855682Smarkm    { NULL, '1', arg_flag, &flag1, "one", NULL },
58955682Smarkm    { NULL, '2', arg_flag, &flag2, "two", NULL },
59055682Smarkm    { "foo", 'f', arg_negative_flag, &foo_flag, "foo", NULL },
59155682Smarkm    { "bar", 'b', arg_integer, &bar_int, "bar", "seconds"},
59255682Smarkm    { "baz", 'x', arg_string, &baz_string, "baz", "name" },
59355682Smarkm};
59455682Smarkm
59555682Smarkmint main(int argc, char **argv)
59655682Smarkm{
597102644Snectar    int goptind = 0;
598102644Snectar    while(getarg(args, 5, argc, argv, &goptind))
599102644Snectar	printf("Bad arg: %s\n", argv[goptind]);
600233294Sstas    printf("flag1 = %d\n", flag1);
601233294Sstas    printf("flag2 = %d\n", flag2);
602233294Sstas    printf("foo_flag = %d\n", foo_flag);
60355682Smarkm    printf("bar_int = %d\n", bar_int);
60455682Smarkm    printf("baz_flag = %s\n", baz_string);
60555682Smarkm    arg_printusage (args, 5, argv[0], "nothing here");
60655682Smarkm}
60755682Smarkm#endif
608