File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / hping2 / antigetopt.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:11:37 2012 UTC (12 years, 3 months ago) by misho
Branches: hping2, MAIN
CVS tags: v2_0_0rc3p7, v2_0_0rc3p5, v2_0_0rc3p4, v2_0_0rc3p0, v2_0_0rc3, HEAD
hping2

    1: /* antigetopt -- a getopt replacement
    2:  * Copyright(C) 2001 Salvatore Sanfilippo <antirez@invece.org>
    3:  * This software is released under the GPL license
    4:  * see the COPYING file for more information */
    5: 
    6: /* TODO:
    7:  * argument list sanity check */
    8: 
    9: #include <stdlib.h>
   10: #include <string.h>
   11: #include <stdio.h>
   12: 
   13: #include "antigetopt.h"
   14: 
   15: /* global vars */
   16: char *ago_optarg = NULL;
   17: char *ago_optname = NULL;
   18: char ago_optchar = '\0';
   19: 
   20: /* static vars */
   21: static struct ago_exception {
   22: 	int (*tester)(void);
   23: 	char *msg;
   24: } ago_exceptions[3] = {
   25: 	{ NULL, NULL },
   26: 	{ NULL, NULL },
   27: 	{ NULL, NULL }
   28: };
   29: 
   30: static int ago_exception_bits[] = { AGO_EXCEPT0, AGO_EXCEPT1, AGO_EXCEPT2 };
   31: 
   32: /* static functions */
   33: static struct ago_optlist
   34: *ago_lookup(struct ago_optlist *list, char *arg, int *islong, int *amb);
   35: static int strinitcmp(char *a, char *b);
   36: 
   37: /*----------------------------- implementation ------------------------------ */
   38: 
   39: int antigetopt(int argc, char **argv, struct ago_optlist *list)
   40: {
   41: 	static char **save_argv = NULL;
   42: 	static char *chain = NULL;
   43: 	static int endoptions = 0;
   44: 	struct ago_optlist *opt;
   45: 	int islong;
   46: 
   47: 	/* Reset */
   48: 	if (argv == NULL) {
   49: 		save_argv = NULL;
   50: 		chain = NULL;
   51: 		endoptions = 0;
   52: 		return AGO_RESET;
   53: 	} else {
   54: 		if (save_argv == NULL) {
   55: 			save_argv = argv+1; /* skips the argv[0] */
   56: 			/* XXX: argument list sanity check */
   57: 		}
   58: 	}
   59: 
   60: chain_start:
   61: 	if (chain) {
   62: 		if (*chain == '\0')
   63: 			chain = NULL;
   64: 		else {
   65: 			if ((opt = ago_lookup(list, chain, &islong, NULL))
   66: 			    == NULL)
   67: 				return AGO_UNKNOWN;
   68: 			if (!(opt->ao_flags & AGO_NOARG)) {
   69: 				/* the if expression maybe false if the
   70: 				 * argument is optional */
   71: 				if (chain[1] == '\0' && *save_argv)
   72: 					ago_optarg = *save_argv++;
   73: 				/* while it is mandatory for the NEEDARG type */
   74: 				else if (opt->ao_flags & AGO_NEEDARG)
   75: 					return AGO_REQARG;
   76: 			}
   77: 			chain++;
   78: 			return opt->ao_id;
   79: 		}
   80: 	}
   81: 
   82: 	argv = save_argv;
   83: 
   84: 	/* handle the "--" special option */
   85: 	if (*argv && strcmp(*argv, "--") == 0) {
   86: 		endoptions = 1;
   87: 		argv++;
   88: 		save_argv++;
   89: 	}
   90: 
   91: 	while(*argv) {
   92: 		/* The option must start with '-' */
   93: 		if (!endoptions && argv[0][0] == '-' && argv[0][1] != '\0') {
   94: 			int amb;
   95: 
   96: 			/* note: ago_lookup also sets ago_optname */
   97: 			if ((opt = ago_lookup(list, argv[0], &islong, &amb))
   98: 			    == NULL)
   99: 				return amb ? AGO_AMBIG : AGO_UNKNOWN;
  100: 
  101: 			/* handle the collapsed short options */
  102: 			if (!islong && argv[0][2] != '\0') {
  103: 				chain = argv[0]+1;
  104: 				save_argv++;
  105: 				goto chain_start;
  106: 			}
  107: 
  108: 			/* if the option require or may have an argument */
  109: 			ago_optarg = NULL;
  110: 			/* If the argument is needed we get the next argv[]
  111: 			 * element without care about what it contains */
  112: 			if (opt->ao_flags & AGO_NEEDARG) {
  113: 				if (argv[1] == NULL)
  114: 					return AGO_REQARG;
  115: 				ago_optarg = argv[1];
  116: 				argv++;
  117: 			}
  118: 			/* If the argument is optional we only recognize it
  119: 			 * as argument if it does not starts with '-' */
  120: 			else if (opt->ao_flags & AGO_OPTARG) {
  121: 				if (argv[1] && argv[1][0] != '-') {
  122: 					ago_optarg = argv[1];
  123: 					argv++;
  124: 				}
  125: 			}
  126: 			save_argv = argv+1;
  127: 			return opt->ao_id;
  128: 		} else {
  129: 			save_argv = argv+1;
  130: 			ago_optarg = argv[0];
  131: 			ago_optchar = '\0';
  132: 			ago_optname = NULL;
  133: 			return AGO_ALONE;
  134: 		}
  135: 	}
  136: 	return AGO_EOF;
  137: }
  138: 
  139: #define UNK_SHORT_ERRSTRING "invalid option -- %c\n"
  140: #define UNK_LONG_ERRSTRING "unrecognized option `--%s'\n"
  141: #define ARG_SHORT_ERRSTRING "option requires an argument -- %c\n"
  142: #define ARG_LONG_ERRSTRING "option `--%s' requires an argument\n"
  143: #define AMB_ERRSTRING "option `--%s' is ambiguos\n"
  144: #define IERR_ERRSTRING "internal error. ago_gnu_error() called with " \
  145: 			   "a bad error code (%d)\n"
  146: void ago_gnu_error(char *pname, int error)
  147: {
  148: 	if (pname)
  149: 		fprintf(stderr, "%s: ", pname);
  150: 	switch(error) {
  151: 		case AGO_UNKNOWN:
  152: 			if (ago_optname)
  153: 				fprintf(stderr, UNK_LONG_ERRSTRING,
  154: 						ago_optname);
  155: 			else
  156: 				fprintf(stderr, UNK_SHORT_ERRSTRING,
  157: 						ago_optchar);
  158: 			break;
  159: 		case AGO_REQARG:
  160: 			if (ago_optname)
  161: 				fprintf(stderr, ARG_LONG_ERRSTRING,
  162: 						ago_optname);
  163: 			else
  164: 				fprintf(stderr, ARG_SHORT_ERRSTRING,
  165: 						ago_optchar);
  166: 			break;
  167: 		case AGO_AMBIG:
  168: 			fprintf(stderr, AMB_ERRSTRING, ago_optname);
  169: 			break;
  170: 		default:
  171: 			fprintf(stderr, IERR_ERRSTRING, error);
  172: 			break;
  173: 	}
  174: }
  175: 
  176: int ago_set_exception(int except_nr, int (*tester)(void), char *msg)
  177: {
  178: 	if (tester == NULL || msg == NULL || except_nr < 0 || except_nr >= 3)
  179: 		return -1;
  180: 	ago_exceptions[except_nr].tester = tester;
  181: 	ago_exceptions[except_nr].msg = msg;
  182: 	return 0;
  183: }
  184: 
  185: /*-------------------------- static functions ------------------------------- */
  186: 
  187: struct ago_optlist
  188: *ago_lookup(struct ago_optlist *list, char *arg, int *islong, int *amb)
  189: {
  190: 	int i;
  191: 
  192: 	/* ago_lookup can be receive as `arg' a pointer to a
  193: 	 * long argument, like --option, a pointer to a short
  194: 	 * argument like -O, or just a pointer to a char sequence
  195: 	 * in the case of collapsed short arguments like -abcde. */
  196: 
  197: 	/* Clear the 'ambiguos' flag, used to report the caller
  198: 	 * an ambiguos option abbreviation error */
  199: 	if (amb) *amb = 0;
  200: 
  201: 	if (*arg == '-') /* skips the first - if any */
  202: 		arg++;
  203: 
  204: 	switch(*arg) {
  205: 	case '\0':
  206: 		return NULL;
  207: 	case '-':
  208: 		*islong = 1;
  209: 		arg++; /* skip the last - */
  210: 		break;
  211: 	default:
  212: 		*islong = 0;
  213: 		break;
  214: 	}
  215: 
  216: 	/* search the argument in the list */
  217: 	if (*islong) {
  218: 		int retval;
  219: 		struct ago_optlist *last = NULL;
  220: 
  221: 		while(!(list->ao_flags & AGO_ENDOFLIST)) {
  222: 			ago_optname = arg;
  223: 			ago_optchar = '\0';
  224: 			if ((retval = strinitcmp(arg, list->ao_long)) != 0) {
  225: 				switch(retval) {
  226: 				case 1:
  227: 					if (last) {
  228: 						if (amb) *amb = 1;
  229: 						return NULL;
  230: 					}
  231: 					last = list;
  232: 					break;
  233: 				case 2:
  234: 					goto ok;
  235: 				}
  236: 			}
  237: 			list++;
  238: 		}
  239: 		if (last) {
  240: 			ago_optname = last->ao_long;
  241: 			list = last;
  242: 			goto ok;
  243: 		}
  244: 	} else {
  245: 		ago_optchar = *arg;
  246: 		ago_optname = NULL;
  247: 		while(!(list->ao_flags & AGO_ENDOFLIST)) {
  248: 			if (*arg == list->ao_short)
  249: 				goto ok;
  250: 			list++;
  251: 		}
  252: 	}
  253: 	return NULL;
  254: ok:
  255: 	/* handle the exceptions if any */
  256: 	for (i = 0; i < 3; i++) {
  257: 		if ((list->ao_flags & ago_exception_bits[i]) &&
  258: 		    ago_exceptions[i].tester)
  259: 		{
  260: 			if (ago_exceptions[i].tester()) {
  261: 				if (ago_optname) {
  262: 					fprintf(stderr, "%s `--%s'\n",
  263: 						ago_exceptions[i].msg,
  264: 						ago_optname);
  265: 				} else {
  266: 					fprintf(stderr, "%s `-%c'\n",
  267: 						ago_exceptions[i].msg,
  268: 						ago_optchar);
  269: 				}
  270: 				exit(1);
  271: 			}
  272: 		}
  273: 	}
  274: 	return list;
  275: }
  276: 
  277: /* Given two strings this function returns:
  278:  * 1, if the strings are the same for the len of the first string (abc, abcde)
  279:  * 2, if the strings are exactly the same: (abcd, abcd)
  280:  * otherwise zero is returned (abcde, abcd) ... (djf, 293492) */
  281: int strinitcmp(char *a, char *b)
  282: {
  283: 	if (!a || !b)
  284: 		return 0;
  285: 	while (*a && *b) {
  286: 		if (*a != *b)
  287: 			return 0;
  288: 		a++; b++;
  289: 	}
  290: 	if (*a)
  291: 		return 0;
  292: 	if (*a == *b)
  293: 		return 2;
  294: 	return 1;
  295: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>