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