150880Smarkm/* 250880Smarkm * Copyright (c) 1997, 1998 Kungliga Tekniska H�gskolan 350880Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 450880Smarkm * All rights reserved. 550880Smarkm * 650880Smarkm * Redistribution and use in source and binary forms, with or without 750880Smarkm * modification, are permitted provided that the following conditions 850880Smarkm * are met: 950880Smarkm * 1050880Smarkm * 1. Redistributions of source code must retain the above copyright 1150880Smarkm * notice, this list of conditions and the following disclaimer. 1250880Smarkm * 1350880Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1450880Smarkm * notice, this list of conditions and the following disclaimer in the 1550880Smarkm * documentation and/or other materials provided with the distribution. 1650880Smarkm * 1750880Smarkm * 3. All advertising materials mentioning features or use of this software 1850880Smarkm * must display the following acknowledgement: 1950880Smarkm * This product includes software developed by Kungliga Tekniska 2050880Smarkm * H�gskolan and its contributors. 2150880Smarkm * 2250880Smarkm * 4. Neither the name of the Institute nor the names of its contributors 2350880Smarkm * may be used to endorse or promote products derived from this software 2450880Smarkm * without specific prior written permission. 2550880Smarkm * 2650880Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2750880Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2850880Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2950880Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 3050880Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3150880Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3250880Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3350880Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3450880Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3550880Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3650880Smarkm * SUCH DAMAGE. 37108950Speter * 38108950Speter * $FreeBSD$ 3950880Smarkm */ 4050880Smarkm 4150880Smarkm#if 0 4250880SmarkmRCSID("$Id: getarg.c,v 1.25 1998/11/22 09:45:05 assar Exp $"); 4350880Smarkm#endif 4450880Smarkm 4550880Smarkm#include <sys/ttycom.h> 4650880Smarkm#include <time.h> 4750880Smarkm#include <stdio.h> 48108950Speter#include <stdlib.h> 4950880Smarkm#include "getarg.h" 5050880Smarkm 5150880Smarkm#define ISFLAG(X) ((X).type == arg_flag || (X).type == arg_negative_flag) 5250880Smarkm 5350880Smarkmstatic size_t 5450880Smarkmprint_arg (char *string, size_t len, int mdoc, int longp, struct getargs *arg) 5550880Smarkm{ 5650880Smarkm const char *s; 5750880Smarkm 5850880Smarkm *string = '\0'; 5950880Smarkm 6050880Smarkm if (ISFLAG(*arg)) 6150880Smarkm return 0; 6250880Smarkm 6350880Smarkm if(mdoc){ 6450880Smarkm if(longp) 6550880Smarkm strncat(string, "= Ns", len); 6650880Smarkm strncat(string, " Ar ", len); 6750880Smarkm }else 6850880Smarkm if (longp) 6950880Smarkm strncat (string, "=", len); 7050880Smarkm else 7150880Smarkm strncat (string, " ", len); 7250880Smarkm 7350880Smarkm if (arg->arg_help) 7450880Smarkm s = arg->arg_help; 7550880Smarkm else if (arg->type == arg_integer) 7650880Smarkm s = "number"; 7750880Smarkm else if (arg->type == arg_string) 7850880Smarkm s = "string"; 7950880Smarkm else 8050880Smarkm s = "<undefined>"; 8150880Smarkm 8250880Smarkm strncat(string, s, len); 8350880Smarkm return 1 + strlen(s); 8450880Smarkm} 8550880Smarkm 8650880Smarkmstatic int 8750880Smarkmcheck_column(FILE *f, int col, int len, int columns) 8850880Smarkm{ 8950880Smarkm if(col + len > columns) { 9050880Smarkm fprintf(f, "\n"); 9150880Smarkm col = fprintf(f, " "); 9250880Smarkm } 9350880Smarkm return col; 9450880Smarkm} 9550880Smarkm 9650880Smarkmvoid 9750880Smarkmarg_printusage (struct getargs *args, 9850880Smarkm size_t num_args, 9950880Smarkm const char *progname, 10050880Smarkm const char *extra_string) 10150880Smarkm{ 10250880Smarkm int i; 10350880Smarkm size_t max_len = 0; 10450880Smarkm char buf[128]; 10550880Smarkm int col = 0, columns; 10650880Smarkm struct winsize ws; 10750880Smarkm 10850880Smarkm columns = 80; 10950880Smarkm col = 0; 11050880Smarkm col += fprintf (stderr, "Usage: %s", progname); 11150880Smarkm for (i = 0; i < num_args; ++i) { 11250880Smarkm size_t len = 0; 11350880Smarkm 11450880Smarkm if (args[i].long_name) { 11550880Smarkm buf[0] = '\0'; 11650880Smarkm strncat(buf, "[--", sizeof(buf)); 11750880Smarkm len += 2; 11850880Smarkm if(args[i].type == arg_negative_flag) { 11950880Smarkm strncat(buf, "no-", sizeof(buf)); 12050880Smarkm len += 3; 12150880Smarkm } 12250880Smarkm strncat(buf, args[i].long_name, sizeof(buf)); 12350880Smarkm len += strlen(args[i].long_name); 12450880Smarkm len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf), 12550880Smarkm 0, 1, &args[i]); 12650880Smarkm strncat(buf, "]", sizeof(buf)); 12750880Smarkm if(args[i].type == arg_strings) 12850880Smarkm strncat(buf, "...", sizeof(buf)); 12950880Smarkm col = check_column(stderr, col, strlen(buf) + 1, columns); 13050880Smarkm col += fprintf(stderr, " %s", buf); 13150880Smarkm } 13250880Smarkm if (args[i].short_name) { 13350880Smarkm snprintf(buf, sizeof(buf), "[-%c", args[i].short_name); 13450880Smarkm len += 2; 13550880Smarkm len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf), 13650880Smarkm 0, 0, &args[i]); 13750880Smarkm strncat(buf, "]", sizeof(buf)); 13850880Smarkm if(args[i].type == arg_strings) 13950880Smarkm strncat(buf, "...", sizeof(buf)); 14050880Smarkm col = check_column(stderr, col, strlen(buf) + 1, columns); 14150880Smarkm col += fprintf(stderr, " %s", buf); 14250880Smarkm } 14350880Smarkm if (args[i].long_name && args[i].short_name) 14450880Smarkm len += 2; /* ", " */ 14550880Smarkm max_len = max(max_len, len); 14650880Smarkm } 14750880Smarkm if (extra_string) { 14850880Smarkm col = check_column(stderr, col, strlen(extra_string) + 1, columns); 14950880Smarkm fprintf (stderr, " %s\n", extra_string); 15050880Smarkm } else 15150880Smarkm fprintf (stderr, "\n"); 15250880Smarkm for (i = 0; i < num_args; ++i) { 15350880Smarkm if (args[i].help) { 15450880Smarkm size_t count = 0; 15550880Smarkm 15650880Smarkm if (args[i].short_name) { 15750880Smarkm count += fprintf (stderr, "-%c", args[i].short_name); 15850880Smarkm print_arg (buf, sizeof(buf), 0, 0, &args[i]); 15950880Smarkm count += fprintf(stderr, "%s", buf); 16050880Smarkm } 16150880Smarkm if (args[i].short_name && args[i].long_name) 16250880Smarkm count += fprintf (stderr, ", "); 16350880Smarkm if (args[i].long_name) { 16450880Smarkm count += fprintf (stderr, "--"); 16550880Smarkm if (args[i].type == arg_negative_flag) 16650880Smarkm count += fprintf (stderr, "no-"); 16750880Smarkm count += fprintf (stderr, "%s", args[i].long_name); 16850880Smarkm print_arg (buf, sizeof(buf), 0, 1, &args[i]); 16950880Smarkm count += fprintf(stderr, "%s", buf); 17050880Smarkm } 17150880Smarkm while(count++ <= max_len) 17250880Smarkm putc (' ', stderr); 17350880Smarkm fprintf (stderr, "%s\n", args[i].help); 17450880Smarkm } 17550880Smarkm } 17650880Smarkm} 17750880Smarkm 17850880Smarkmstatic void 17950880Smarkmadd_string(getarg_strings *s, char *value) 18050880Smarkm{ 18150880Smarkm s->strings = realloc(s->strings, (s->num_strings + 1) * sizeof(*s->strings)); 18250880Smarkm s->strings[s->num_strings] = value; 18350880Smarkm s->num_strings++; 18450880Smarkm} 18550880Smarkm 18650880Smarkmstatic int 18750880Smarkmarg_match_long(struct getargs *args, size_t num_args, 18850880Smarkm char *argv) 18950880Smarkm{ 19050880Smarkm int i; 19150880Smarkm char *optarg = NULL; 19250880Smarkm int negate = 0; 19350880Smarkm int partial_match = 0; 19450880Smarkm struct getargs *partial = NULL; 19550880Smarkm struct getargs *current = NULL; 19650880Smarkm int argv_len; 19750880Smarkm char *p; 19850880Smarkm 19950880Smarkm argv_len = strlen(argv); 20050880Smarkm p = strchr (argv, '='); 20150880Smarkm if (p != NULL) 20250880Smarkm argv_len = p - argv; 20350880Smarkm 20450880Smarkm for (i = 0; i < num_args; ++i) { 20550880Smarkm if(args[i].long_name) { 20650880Smarkm int len = strlen(args[i].long_name); 20750880Smarkm char *p = argv; 20850880Smarkm int p_len = argv_len; 20950880Smarkm negate = 0; 21050880Smarkm 21150880Smarkm for (;;) { 21250880Smarkm if (strncmp (args[i].long_name, p, p_len) == 0) { 21350880Smarkm if(p_len == len) 21450880Smarkm current = &args[i]; 21550880Smarkm else { 21650880Smarkm ++partial_match; 21750880Smarkm partial = &args[i]; 21850880Smarkm } 21950880Smarkm optarg = p + p_len; 22050880Smarkm } else if (ISFLAG(args[i]) && strncmp (p, "no-", 3) == 0) { 22150880Smarkm negate = !negate; 22250880Smarkm p += 3; 22350880Smarkm p_len -= 3; 22450880Smarkm continue; 22550880Smarkm } 22650880Smarkm break; 22750880Smarkm } 22850880Smarkm if (current) 22950880Smarkm break; 23050880Smarkm } 23150880Smarkm } 23250880Smarkm if (current == NULL) { 23350880Smarkm if (partial_match == 1) 23450880Smarkm current = partial; 23550880Smarkm else 23650880Smarkm return ARG_ERR_NO_MATCH; 23750880Smarkm } 23850880Smarkm 23950880Smarkm if(*optarg == '\0' && !ISFLAG(*current)) 24050880Smarkm return ARG_ERR_NO_MATCH; 24150880Smarkm switch(current->type){ 24250880Smarkm case arg_integer: 24350880Smarkm { 24450880Smarkm int tmp; 24550880Smarkm if(sscanf(optarg + 1, "%d", &tmp) != 1) 24650880Smarkm return ARG_ERR_BAD_ARG; 24750880Smarkm *(int*)current->value = tmp; 24850880Smarkm return 0; 24950880Smarkm } 25050880Smarkm case arg_string: 25150880Smarkm { 25250880Smarkm *(char**)current->value = optarg + 1; 25350880Smarkm return 0; 25450880Smarkm } 25550880Smarkm case arg_strings: 25650880Smarkm { 25750880Smarkm add_string((getarg_strings*)current->value, optarg + 1); 25850880Smarkm return 0; 25950880Smarkm } 26050880Smarkm case arg_flag: 26150880Smarkm case arg_negative_flag: 26250880Smarkm { 26350880Smarkm int *flag = current->value; 26450880Smarkm if(*optarg == '\0' || 26550880Smarkm strcmp(optarg + 1, "yes") == 0 || 26650880Smarkm strcmp(optarg + 1, "true") == 0){ 26750880Smarkm *flag = !negate; 26850880Smarkm return 0; 26950880Smarkm } else if (*optarg && strcmp(optarg + 1, "maybe") == 0) { 27050880Smarkm *flag = rand() & 1; 27150880Smarkm } else { 27250880Smarkm *flag = negate; 27350880Smarkm return 0; 27450880Smarkm } 27550880Smarkm return ARG_ERR_BAD_ARG; 27650880Smarkm } 27750880Smarkm default: 27850880Smarkm abort (); 27950880Smarkm } 28050880Smarkm} 28150880Smarkm 28250880Smarkmint 28350880Smarkmgetarg(struct getargs *args, size_t num_args, 28450880Smarkm int argc, char **argv, int *optind) 28550880Smarkm{ 28650880Smarkm int i, j, k; 28750880Smarkm int ret = 0; 28850880Smarkm 28950880Smarkm srand (time(NULL)); 29050880Smarkm (*optind)++; 29150880Smarkm for(i = *optind; i < argc; i++) { 29250880Smarkm if(argv[i][0] != '-') 29350880Smarkm break; 29450880Smarkm if(argv[i][1] == '-'){ 29550880Smarkm if(argv[i][2] == 0){ 29650880Smarkm i++; 29750880Smarkm break; 29850880Smarkm } 29950880Smarkm ret = arg_match_long (args, num_args, argv[i] + 2); 30050880Smarkm if(ret) 30150880Smarkm return ret; 30250880Smarkm }else{ 30350880Smarkm for(j = 1; argv[i][j]; j++) { 30450880Smarkm for(k = 0; k < num_args; k++) { 30550880Smarkm char *optarg; 30650880Smarkm if(args[k].short_name == 0) 30750880Smarkm continue; 30850880Smarkm if(argv[i][j] == args[k].short_name){ 30950880Smarkm if(args[k].type == arg_flag){ 31050880Smarkm *(int*)args[k].value = 1; 31150880Smarkm break; 31250880Smarkm } 31350880Smarkm if(args[k].type == arg_negative_flag){ 31450880Smarkm *(int*)args[k].value = 0; 31550880Smarkm break; 31650880Smarkm } 31750880Smarkm if(argv[i][j + 1]) 31850880Smarkm optarg = &argv[i][j + 1]; 31950880Smarkm else{ 32050880Smarkm i++; 32150880Smarkm optarg = argv[i]; 32250880Smarkm } 32350880Smarkm if(optarg == NULL) 32450880Smarkm return ARG_ERR_NO_ARG; 32550880Smarkm if(args[k].type == arg_integer){ 32650880Smarkm int tmp; 32750880Smarkm if(sscanf(optarg, "%d", &tmp) != 1) 32850880Smarkm return ARG_ERR_BAD_ARG; 32950880Smarkm *(int*)args[k].value = tmp; 33050880Smarkm goto out; 33150880Smarkm }else if(args[k].type == arg_string){ 33250880Smarkm *(char**)args[k].value = optarg; 33350880Smarkm goto out; 33450880Smarkm }else if(args[k].type == arg_strings){ 33550880Smarkm add_string((getarg_strings*)args[k].value, optarg); 33650880Smarkm goto out; 33750880Smarkm } 33850880Smarkm return ARG_ERR_BAD_ARG; 33950880Smarkm } 34050880Smarkm 34150880Smarkm } 34250880Smarkm if (k == num_args) 34350880Smarkm return ARG_ERR_NO_MATCH; 34450880Smarkm } 34550880Smarkm out:; 34650880Smarkm } 34750880Smarkm } 34850880Smarkm *optind = i; 34950880Smarkm return 0; 35050880Smarkm} 35150880Smarkm 35250880Smarkm#if TEST 35350880Smarkmint foo_flag = 2; 35450880Smarkmint flag1 = 0; 35550880Smarkmint flag2 = 0; 35650880Smarkmint bar_int; 35750880Smarkmchar *baz_string; 35850880Smarkm 35950880Smarkmstruct getargs args[] = { 36050880Smarkm { NULL, '1', arg_flag, &flag1, "one", NULL }, 36150880Smarkm { NULL, '2', arg_flag, &flag2, "two", NULL }, 36250880Smarkm { "foo", 'f', arg_negative_flag, &foo_flag, "foo", NULL }, 36350880Smarkm { "bar", 'b', arg_integer, &bar_int, "bar", "seconds"}, 36450880Smarkm { "baz", 'x', arg_string, &baz_string, "baz", "name" }, 36550880Smarkm}; 36650880Smarkm 36750880Smarkmint main(int argc, char **argv) 36850880Smarkm{ 36950880Smarkm int optind = 0; 37050880Smarkm while(getarg(args, 5, argc, argv, &optind)) 37150880Smarkm printf("Bad arg: %s\n", argv[optind]); 37250880Smarkm printf("flag1 = %d\n", flag1); 37350880Smarkm printf("flag2 = %d\n", flag2); 37450880Smarkm printf("foo_flag = %d\n", foo_flag); 37550880Smarkm printf("bar_int = %d\n", bar_int); 37650880Smarkm printf("baz_flag = %s\n", baz_string); 37750880Smarkm arg_printusage (args, 5, argv[0], "nothing here"); 37850880Smarkm} 37950880Smarkm#endif 380