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>