2 * cmdline.c -- parse a command line using getopt, environment and defaults
4 * Copyright (c) 1999 Alessandro Rubini (rubini@gnu.org)
5 * Copyright (c) 1999 Prosa Srl. (prosa@prosa.it)
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22 * Michele Comitini (mcm@glisco.it): better handling of numeric type args.
31 #include "compat/getopt.h"
38 /* In case of error, print help string and return error (-1) */
39 int commandline_errormsg(FILE *f, struct commandline *args,
40 char *prgname, char *messagehead)
45 struct commandline *ptr;
48 fprintf(f,"%s: Error in cmdline\nPossible options:\n",prgname);
50 fprintf(f,"%s: %s",prgname,messagehead);
53 for (ptr = args; ptr->option; ptr++) {
55 len = strlen(ptr->descrip);
56 len += ptr->default_v ? strlen(ptr->default_v) : 6;
57 len += ptr->env ? strlen(ptr->env) : 6;
58 buffer2 = malloc(len+3); /* 3 to be safe :) */
63 sprintf(buffer2, ptr->descrip,
64 ptr->default_v ? ptr->default_v : "(none)",
65 ptr->env ? ptr->env : "(none)");
66 sprintf(buffer, " -%c %s %s", ptr->option,
67 ptr->type ? "<arg>" : " ", buffer2);
68 fprintf(f, "%s\n",buffer);
79 * Associate formats to type.
82 enum option_type type;
85 static struct type_fmt formats[] = {
86 {CMDLINE_I, "%i%s"}, /* the trailing "%s" is used for error check */
92 {0, NULL} /* If we get here, it's CMDLINE_S: no sscanf buf strcpy() */
96 /* Parse one argument (default or provided) */
97 static int commandline_oneopt(struct commandline *ptr, char *value)
99 struct type_fmt *tptr;
100 char *trash = value ? strdup(value) : NULL;
102 /* convert it, if needed */
103 if ((ptr->type != CMDLINE_NONE) && ptr->result) {
104 for (tptr = formats; tptr->type; tptr++)
105 if (tptr->type == ptr->type)
107 if (!tptr->type) /* not found: it is a string */
108 *(char **)(ptr->result) = value;
110 if (sscanf(value, tptr->fmt, ptr->result, trash)!=1) {
118 if ((ptr->type == CMDLINE_NONE) && ptr->result) /* no type, just count */
119 (*(int *)(ptr->result))++;
121 /* call the function, if needed */
124 if (ptr->result) return ptr->fun(ptr->result); /* converted */
125 return ptr->fun(value); /* type, but not converted */
127 return ptr->fun(NULL); /* no type: just call it */
132 /* The main function */
133 int commandline(struct commandline *args, int argc, char **argv,
136 struct commandline *ptr;
137 char *getopt_desc = (char *)calloc(512, 1);
142 /* Build getopt string and process defaults values */
143 for (ptr = args; ptr->option; ptr++) {
144 getopt_desc[desc_offset++] = ptr->option;
145 if (ptr->type) getopt_desc[desc_offset++] = ':';
149 value = getenv(ptr->env);
151 value = ptr->default_v;
152 if (value && (retval = commandline_oneopt(ptr, value))) {
154 * if the function returns a specific (not -1) value, it already
155 * printed its message, so avoid the generic help
158 commandline_errormsg(stderr, args, argv[0], errorhead);
163 /* Run getopt and process material */
164 while ((opt = getopt(argc, argv, getopt_desc)) != -1) {
165 for (ptr = args; ptr->option; ptr++)
166 if (opt == ptr->option)
168 if (!ptr->option) /* unknown option */
169 return commandline_errormsg(stderr, args, argv[0], errorhead);
170 if ( (retval = commandline_oneopt(ptr, optarg)) ) { /* wrong arg */
172 commandline_errormsg(stderr, args, argv[0], errorhead);