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