Annotation of embedaddon/hping2/antigetopt.c, revision 1.1
1.1 ! misho 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>