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>