Annotation of src/usr.bin/lex/scanopt.c, Revision 1.3
1.3 ! mmcc 1: /* $OpenBSD: scanopt.c,v 1.2 2015/11/19 22:16:43 tedu Exp $ */
1.1 tedu 2:
3: /* flex - tool to generate fast lexical analyzers */
4:
5: /* Copyright (c) 1990 The Regents of the University of California. */
6: /* All rights reserved. */
7:
8: /* This code is derived from software contributed to Berkeley by */
9: /* Vern Paxson. */
10:
11: /* The United States Government has rights in this work pursuant */
12: /* to contract no. DE-AC03-76SF00098 between the United States */
13: /* Department of Energy and the University of California. */
14:
15: /* This file is part of flex. */
16:
17: /* Redistribution and use in source and binary forms, with or without */
18: /* modification, are permitted provided that the following conditions */
19: /* are met: */
20:
21: /* 1. Redistributions of source code must retain the above copyright */
22: /* notice, this list of conditions and the following disclaimer. */
23: /* 2. Redistributions in binary form must reproduce the above copyright */
24: /* notice, this list of conditions and the following disclaimer in the */
25: /* documentation and/or other materials provided with the distribution. */
26:
27: /* Neither the name of the University nor the names of its contributors */
28: /* may be used to endorse or promote products derived from this software */
29: /* without specific prior written permission. */
30:
31: /* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR */
32: /* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
33: /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
34: /* PURPOSE. */
35:
36: #include "flexdef.h"
37: #include "scanopt.h"
38:
39:
40: /* Internal structures */
41:
42: #ifdef HAVE_STRCASECMP
43: #define STRCASECMP(a,b) strcasecmp(a,b)
44: #else
45: static int STRCASECMP PROTO ((const char *, const char *));
46:
47: static int STRCASECMP (a, b)
48: const char *a;
49: const char *b;
50: {
51: while (tolower (*a++) == tolower (*b++)) ;
52: return b - a;
53: }
54: #endif
55:
56: #define ARG_NONE 0x01
57: #define ARG_REQ 0x02
58: #define ARG_OPT 0x04
59: #define IS_LONG 0x08
60:
61: struct _aux {
62: int flags; /* The above hex flags. */
63: int namelen; /* Length of the actual option word, e.g., "--file[=foo]" is 4 */
64: int printlen; /* Length of entire string, e.g., "--file[=foo]" is 12 */
65: };
66:
67:
68: struct _scanopt_t {
69: const optspec_t *options; /* List of options. */
70: struct _aux *aux; /* Auxiliary data about options. */
71: int optc; /* Number of options. */
72: int argc; /* Number of args. */
73: char **argv; /* Array of strings. */
74: int index; /* Used as: argv[index][subscript]. */
75: int subscript;
76: char no_err_msg; /* If true, do not print errors. */
77: char has_long;
78: char has_short;
79: };
80:
81: /* Accessor functions. These WOULD be one-liners, but portability calls. */
82: static const char *NAME PROTO ((struct _scanopt_t *, int));
83: static int PRINTLEN PROTO ((struct _scanopt_t *, int));
84: static int RVAL PROTO ((struct _scanopt_t *, int));
85: static int FLAGS PROTO ((struct _scanopt_t *, int));
86: static const char *DESC PROTO ((struct _scanopt_t *, int));
87: static int scanopt_err PROTO ((struct _scanopt_t *, int, int, int));
88: static int matchlongopt PROTO ((char *, char **, int *, char **, int *));
89: static int find_opt
90: PROTO ((struct _scanopt_t *, int, char *, int, int *, int *opt_offset));
91:
92: static const char *NAME (s, i)
93: struct _scanopt_t *s;
94: int i;
95: {
96: return s->options[i].opt_fmt +
97: ((s->aux[i].flags & IS_LONG) ? 2 : 1);
98: }
99:
100: static int PRINTLEN (s, i)
101: struct _scanopt_t *s;
102: int i;
103: {
104: return s->aux[i].printlen;
105: }
106:
107: static int RVAL (s, i)
108: struct _scanopt_t *s;
109: int i;
110: {
111: return s->options[i].r_val;
112: }
113:
114: static int FLAGS (s, i)
115: struct _scanopt_t *s;
116: int i;
117: {
118: return s->aux[i].flags;
119: }
120:
121: static const char *DESC (s, i)
122: struct _scanopt_t *s;
123: int i;
124: {
125: return s->options[i].desc ? s->options[i].desc : "";
126: }
127:
128: #ifndef NO_SCANOPT_USAGE
129: static int get_cols PROTO ((void));
130:
131: static int get_cols ()
132: {
133: char *env;
134: int cols = 80; /* default */
135:
136: #ifdef HAVE_NCURSES_H
137: initscr ();
138: endwin ();
139: if (COLS > 0)
140: return COLS;
141: #endif
142:
143: if ((env = getenv ("COLUMNS")) != NULL)
144: cols = atoi (env);
145:
146: return cols;
147: }
148: #endif
149:
150: /* Macro to check for NULL before assigning a value. */
151: #define SAFE_ASSIGN(ptr,val) \
152: do{ \
153: if((ptr)!=NULL) \
154: *(ptr) = val; \
155: }while(0)
156:
157: /* Macro to assure we reset subscript whenever we adjust s->index.*/
158: #define INC_INDEX(s,n) \
159: do{ \
160: (s)->index += (n); \
161: (s)->subscript= 0; \
162: }while(0)
163:
164: scanopt_t *scanopt_init (options, argc, argv, flags)
165: const optspec_t *options;
166: int argc;
167: char **argv;
168: int flags;
169: {
170: int i;
171: struct _scanopt_t *s;
172: s = (struct _scanopt_t *) malloc (sizeof (struct _scanopt_t));
173:
174: s->options = options;
175: s->optc = 0;
176: s->argc = argc;
177: s->argv = (char **) argv;
178: s->index = 1;
179: s->subscript = 0;
180: s->no_err_msg = (flags & SCANOPT_NO_ERR_MSG);
181: s->has_long = 0;
182: s->has_short = 0;
183:
184: /* Determine option count. (Find entry with all zeros). */
185: s->optc = 0;
186: while (options[s->optc].opt_fmt
187: || options[s->optc].r_val || options[s->optc].desc)
188: s->optc++;
189:
190: /* Build auxiliary data */
191: s->aux = (struct _aux *) malloc (s->optc * sizeof (struct _aux));
192:
193: for (i = 0; i < s->optc; i++) {
1.3 ! mmcc 194: const u_char *p, *pname;
1.1 tedu 195: const struct optspec_t *opt;
196: struct _aux *aux;
197:
198: opt = s->options + i;
199: aux = s->aux + i;
200:
201: aux->flags = ARG_NONE;
202:
203: if (opt->opt_fmt[0] == '-' && opt->opt_fmt[1] == '-') {
204: aux->flags |= IS_LONG;
1.3 ! mmcc 205: pname = (const u_char *)(opt->opt_fmt + 2);
1.1 tedu 206: s->has_long = 1;
207: }
208: else {
1.3 ! mmcc 209: pname = (const u_char *)(opt->opt_fmt + 1);
1.1 tedu 210: s->has_short = 1;
211: }
212: aux->printlen = strlen (opt->opt_fmt);
213:
214: aux->namelen = 0;
215: for (p = pname + 1; *p; p++) {
216: /* detect required arg */
217: if (*p == '=' || isspace (*p)
218: || !(aux->flags & IS_LONG)) {
219: if (aux->namelen == 0)
220: aux->namelen = p - pname;
221: aux->flags |= ARG_REQ;
222: aux->flags &= ~ARG_NONE;
223: }
224: /* detect optional arg. This overrides required arg. */
225: if (*p == '[') {
226: if (aux->namelen == 0)
227: aux->namelen = p - pname;
228: aux->flags &= ~(ARG_REQ | ARG_NONE);
229: aux->flags |= ARG_OPT;
230: break;
231: }
232: }
233: if (aux->namelen == 0)
234: aux->namelen = p - pname;
235: }
236: return (scanopt_t *) s;
237: }
238:
239: #ifndef NO_SCANOPT_USAGE
240: /* these structs are for scanopt_usage(). */
241: struct usg_elem {
242: int idx;
243: struct usg_elem *next;
244: struct usg_elem *alias;
245: };
246: typedef struct usg_elem usg_elem;
247:
248:
249: /* Prints a usage message based on contents of optlist.
250: * Parameters:
251: * scanner - The scanner, already initialized with scanopt_init().
252: * fp - The file stream to write to.
253: * usage - Text to be prepended to option list.
254: * Return: Always returns 0 (zero).
255: * The output looks something like this:
256:
257: [indent][option, alias1, alias2...][indent][description line1
258: description line2...]
259: */
260: int scanopt_usage (scanner, fp, usage)
261: scanopt_t *scanner;
262: FILE *fp;
263: const char *usage;
264: {
265: struct _scanopt_t *s;
266: int i, columns, indent = 2;
267: usg_elem *byr_val = NULL; /* option indices sorted by r_val */
268: usg_elem *store; /* array of preallocated elements. */
269: int store_idx = 0;
270: usg_elem *ue;
271: int maxlen[2];
272: int desccol = 0;
273: int print_run = 0;
274:
275: maxlen[0] = 0;
276: maxlen[1] = 0;
277:
278: s = (struct _scanopt_t *) scanner;
279:
280: if (usage) {
281: fprintf (fp, "%s\n", usage);
282: }
283: else {
284: /* Find the basename of argv[0] */
285: const char *p;
286:
287: p = s->argv[0] + strlen (s->argv[0]);
288: while (p != s->argv[0] && *p != '/')
289: --p;
290: if (*p == '/')
291: p++;
292:
293: fprintf (fp, _("Usage: %s [OPTIONS]...\n"), p);
294: }
295: fprintf (fp, "\n");
296:
297: /* Sort by r_val and string. Yes, this is O(n*n), but n is small. */
298: store = (usg_elem *) malloc (s->optc * sizeof (usg_elem));
299: for (i = 0; i < s->optc; i++) {
300:
301: /* grab the next preallocate node. */
302: ue = store + store_idx++;
303: ue->idx = i;
304: ue->next = ue->alias = NULL;
305:
306: /* insert into list. */
307: if (!byr_val)
308: byr_val = ue;
309: else {
310: int found_alias = 0;
311: usg_elem **ue_curr, **ptr_if_no_alias = NULL;
312:
313: ue_curr = &byr_val;
314: while (*ue_curr) {
315: if (RVAL (s, (*ue_curr)->idx) ==
316: RVAL (s, ue->idx)) {
317: /* push onto the alias list. */
318: ue_curr = &((*ue_curr)->alias);
319: found_alias = 1;
320: break;
321: }
322: if (!ptr_if_no_alias
323: &&
324: STRCASECMP (NAME (s, (*ue_curr)->idx),
325: NAME (s, ue->idx)) > 0) {
326: ptr_if_no_alias = ue_curr;
327: }
328: ue_curr = &((*ue_curr)->next);
329: }
330: if (!found_alias && ptr_if_no_alias)
331: ue_curr = ptr_if_no_alias;
332: ue->next = *ue_curr;
333: *ue_curr = ue;
334: }
335: }
336:
337: #if 0
338: if (1) {
339: printf ("ORIGINAL:\n");
340: for (i = 0; i < s->optc; i++)
341: printf ("%2d: %s\n", i, NAME (s, i));
342: printf ("SORTED:\n");
343: ue = byr_val;
344: while (ue) {
345: usg_elem *ue2;
346:
347: printf ("%2d: %s\n", ue->idx, NAME (s, ue->idx));
348: for (ue2 = ue->alias; ue2; ue2 = ue2->next)
349: printf (" +---> %2d: %s\n", ue2->idx,
350: NAME (s, ue2->idx));
351: ue = ue->next;
352: }
353: }
354: #endif
355:
356: /* Now build each row of output. */
357:
358: /* first pass calculate how much room we need. */
359: for (ue = byr_val; ue; ue = ue->next) {
360: usg_elem *ap;
361: int len = 0;
362: int nshort = 0, nlong = 0;
363:
364:
365: #define CALC_LEN(i) do {\
366: if(FLAGS(s,i) & IS_LONG) \
367: len += (nlong++||nshort) ? 2+PRINTLEN(s,i) : PRINTLEN(s,i);\
368: else\
369: len += (nshort++||nlong)? 2+PRINTLEN(s,i) : PRINTLEN(s,i);\
370: }while(0)
371:
372: if (!(FLAGS (s, ue->idx) & IS_LONG))
373: CALC_LEN (ue->idx);
374:
375: /* do short aliases first. */
376: for (ap = ue->alias; ap; ap = ap->next) {
377: if (FLAGS (s, ap->idx) & IS_LONG)
378: continue;
379: CALC_LEN (ap->idx);
380: }
381:
382: if (FLAGS (s, ue->idx) & IS_LONG)
383: CALC_LEN (ue->idx);
384:
385: /* repeat the above loop, this time for long aliases. */
386: for (ap = ue->alias; ap; ap = ap->next) {
387: if (!(FLAGS (s, ap->idx) & IS_LONG))
388: continue;
389: CALC_LEN (ap->idx);
390: }
391:
392: if (len > maxlen[0])
393: maxlen[0] = len;
394:
395: /* It's much easier to calculate length for description column! */
396: len = strlen (DESC (s, ue->idx));
397: if (len > maxlen[1])
398: maxlen[1] = len;
399: }
400:
401: /* Determine how much room we have, and how much we will allocate to each col.
402: * Do not address pathological cases. Output will just be ugly. */
403: columns = get_cols () - 1;
404: if (maxlen[0] + maxlen[1] + indent * 2 > columns) {
405: /* col 0 gets whatever it wants. we'll wrap the desc col. */
406: maxlen[1] = columns - (maxlen[0] + indent * 2);
407: if (maxlen[1] < 14) /* 14 is arbitrary lower limit on desc width. */
408: maxlen[1] = INT_MAX;
409: }
410: desccol = maxlen[0] + indent * 2;
411:
412: #define PRINT_SPACES(fp,n)\
413: do{\
414: int _n;\
415: _n=(n);\
416: while(_n-- > 0)\
417: fputc(' ',(fp));\
418: }while(0)
419:
420:
421: /* Second pass (same as above loop), this time we print. */
422: /* Sloppy hack: We iterate twice. The first time we print short and long options.
423: The second time we print those lines that have ONLY long options. */
424: while (print_run++ < 2) {
425: for (ue = byr_val; ue; ue = ue->next) {
426: usg_elem *ap;
427: int nwords = 0, nchars = 0, has_short = 0;
428:
429: /* TODO: get has_short schtick to work */
430: has_short = !(FLAGS (s, ue->idx) & IS_LONG);
431: for (ap = ue->alias; ap; ap = ap->next) {
432: if (!(FLAGS (s, ap->idx) & IS_LONG)) {
433: has_short = 1;
434: break;
435: }
436: }
437: if ((print_run == 1 && !has_short) ||
438: (print_run == 2 && has_short))
439: continue;
440:
441: PRINT_SPACES (fp, indent);
442: nchars += indent;
443:
444: /* Print, adding a ", " between aliases. */
445: #define PRINT_IT(i) do{\
446: if(nwords++)\
447: nchars+=fprintf(fp,", ");\
448: nchars+=fprintf(fp,"%s",s->options[i].opt_fmt);\
449: }while(0)
450:
451: if (!(FLAGS (s, ue->idx) & IS_LONG))
452: PRINT_IT (ue->idx);
453:
454: /* print short aliases first. */
455: for (ap = ue->alias; ap; ap = ap->next) {
456: if (!(FLAGS (s, ap->idx) & IS_LONG))
457: PRINT_IT (ap->idx);
458: }
459:
460:
461: if (FLAGS (s, ue->idx) & IS_LONG)
462: PRINT_IT (ue->idx);
463:
464: /* repeat the above loop, this time for long aliases. */
465: for (ap = ue->alias; ap; ap = ap->next) {
466: if (FLAGS (s, ap->idx) & IS_LONG)
467: PRINT_IT (ap->idx);
468: }
469:
470: /* pad to desccol */
471: PRINT_SPACES (fp, desccol - nchars);
472:
473: /* Print description, wrapped to maxlen[1] columns. */
474: if (1) {
475: const char *pstart;
476:
477: pstart = DESC (s, ue->idx);
478: while (1) {
479: int n = 0;
480: const char *lastws = NULL, *p;
481:
482: p = pstart;
483:
484: while (*p && n < maxlen[1]
485: && *p != '\n') {
1.3 ! mmcc 486: if (isspace ((u_char)(*p))
1.1 tedu 487: || *p == '-') lastws =
488: p;
489: n++;
490: p++;
491: }
492:
493: if (!*p) { /* hit end of desc. done. */
494: fprintf (fp, "%s\n",
495: pstart);
496: break;
497: }
498: else if (*p == '\n') { /* print everything up to here then wrap. */
499: fprintf (fp, "%.*s\n", n,
500: pstart);
501: PRINT_SPACES (fp, desccol);
502: pstart = p + 1;
503: continue;
504: }
505: else { /* we hit the edge of the screen. wrap at space if possible. */
506: if (lastws) {
507: fprintf (fp,
508: "%.*s\n",
509: (int)(lastws - pstart),
510: pstart);
511: pstart =
512: lastws + 1;
513: }
514: else {
515: fprintf (fp,
516: "%.*s\n",
517: n,
518: pstart);
519: pstart = p + 1;
520: }
521: PRINT_SPACES (fp, desccol);
522: continue;
523: }
524: }
525: }
526: }
527: } /* end while */
528: free (store);
529: return 0;
530: }
531: #endif /* no scanopt_usage */
532:
533:
534: static int scanopt_err (s, opt_offset, is_short, err)
535: struct _scanopt_t *s;
536: int opt_offset;
537: int is_short;
538: int err;
539: {
540: const char *optname = "";
541: char optchar[2];
542: const optspec_t *opt = NULL;
543:
544: if (opt_offset >= 0)
545: opt = s->options + opt_offset;
546:
547: if (!s->no_err_msg) {
548:
549: if (s->index > 0 && s->index < s->argc) {
550: if (is_short) {
551: optchar[0] =
552: s->argv[s->index][s->subscript];
553: optchar[1] = '\0';
554: optname = optchar;
555: }
556: else {
557: optname = s->argv[s->index];
558: }
559: }
560:
561: fprintf (stderr, "%s: ", s->argv[0]);
562: switch (err) {
563: case SCANOPT_ERR_ARG_NOT_ALLOWED:
564: fprintf (stderr,
565: _
566: ("option `%s' doesn't allow an argument\n"),
567: optname);
568: break;
569: case SCANOPT_ERR_ARG_NOT_FOUND:
570: fprintf (stderr,
571: _("option `%s' requires an argument\n"),
572: optname);
573: break;
574: case SCANOPT_ERR_OPT_AMBIGUOUS:
575: fprintf (stderr, _("option `%s' is ambiguous\n"),
576: optname);
577: break;
578: case SCANOPT_ERR_OPT_UNRECOGNIZED:
579: fprintf (stderr, _("Unrecognized option `%s'\n"),
580: optname);
581: break;
582: default:
583: fprintf (stderr, _("Unknown error=(%d)\n"), err);
584: break;
585: }
586: }
587: return err;
588: }
589:
590:
591: /* Internal. Match str against the regex ^--([^=]+)(=(.*))?
592: * return 1 if *looks* like a long option.
593: * 'str' is the only input argument, the rest of the arguments are output only.
594: * optname will point to str + 2
595: *
596: */
597: static int matchlongopt (str, optname, optlen, arg, arglen)
598: char *str;
599: char **optname;
600: int *optlen;
601: char **arg;
602: int *arglen;
603: {
604: char *p;
605:
606: *optname = *arg = (char *) 0;
607: *optlen = *arglen = 0;
608:
609: /* Match regex /--./ */
610: p = str;
611: if (p[0] != '-' || p[1] != '-' || !p[2])
612: return 0;
613:
614: p += 2;
615: *optname = (char *) p;
616:
617: /* find the end of optname */
618: while (*p && *p != '=')
619: ++p;
620:
621: *optlen = p - *optname;
622:
623: if (!*p)
624: /* an option with no '=...' part. */
625: return 1;
626:
627:
628: /* We saw an '=' char. The rest of p is the arg. */
629: p++;
630: *arg = p;
631: while (*p)
632: ++p;
633: *arglen = p - *arg;
634:
635: return 1;
636: }
637:
638:
639: /* Internal. Look up long or short option by name.
640: * Long options must match a non-ambiguous prefix, or exact match.
641: * Short options must be exact.
642: * Return boolean true if found and no error.
643: * Error stored in err_code or zero if no error. */
644: static int find_opt (s, lookup_long, optstart, len, err_code, opt_offset)
645: struct _scanopt_t *s;
646: int lookup_long;
647: char *optstart;
648: int len;
649: int *err_code;
650: int *opt_offset;
651: {
652: int nmatch = 0, lastr_val = 0, i;
653:
654: *err_code = 0;
655: *opt_offset = -1;
656:
657: if (!optstart)
658: return 0;
659:
660: for (i = 0; i < s->optc; i++) {
661: char *optname;
662:
663: optname =
664: (char *) (s->options[i].opt_fmt +
665: (lookup_long ? 2 : 1));
666:
667: if (lookup_long && (s->aux[i].flags & IS_LONG)) {
668: if (len > s->aux[i].namelen)
669: continue;
670:
671: if (strncmp (optname, optstart, len) == 0) {
672: nmatch++;
673: *opt_offset = i;
674:
675: /* exact match overrides all. */
676: if (len == s->aux[i].namelen) {
677: nmatch = 1;
678: break;
679: }
680:
681: /* ambiguity is ok between aliases. */
682: if (lastr_val
683: && lastr_val ==
684: s->options[i].r_val) nmatch--;
685: lastr_val = s->options[i].r_val;
686: }
687: }
688: else if (!lookup_long && !(s->aux[i].flags & IS_LONG)) {
689: if (optname[0] == optstart[0]) {
690: nmatch++;
691: *opt_offset = i;
692: }
693: }
694: }
695:
696: if (nmatch == 0) {
697: *err_code = SCANOPT_ERR_OPT_UNRECOGNIZED;
698: *opt_offset = -1;
699: }
700: else if (nmatch > 1) {
701: *err_code = SCANOPT_ERR_OPT_AMBIGUOUS;
702: *opt_offset = -1;
703: }
704:
705: return *err_code ? 0 : 1;
706: }
707:
708:
709: int scanopt (svoid, arg, optindex)
710: scanopt_t *svoid;
711: char **arg;
712: int *optindex;
713: {
714: char *optname = NULL, *optarg = NULL, *pstart;
715: int namelen = 0, arglen = 0;
716: int errcode = 0, has_next;
717: const optspec_t *optp;
718: struct _scanopt_t *s;
719: struct _aux *auxp;
720: int is_short;
721: int opt_offset = -1;
722:
723: s = (struct _scanopt_t *) svoid;
724:
725: /* Normalize return-parameters. */
726: SAFE_ASSIGN (arg, NULL);
727: SAFE_ASSIGN (optindex, s->index);
728:
729: if (s->index >= s->argc)
730: return 0;
731:
732: /* pstart always points to the start of our current scan. */
733: pstart = s->argv[s->index] + s->subscript;
734: if (!pstart)
735: return 0;
736:
737: if (s->subscript == 0) {
738:
739: /* test for exact match of "--" */
740: if (pstart[0] == '-' && pstart[1] == '-' && !pstart[2]) {
741: SAFE_ASSIGN (optindex, s->index + 1);
742: INC_INDEX (s, 1);
743: return 0;
744: }
745:
746: /* Match an opt. */
747: if (matchlongopt
748: (pstart, &optname, &namelen, &optarg, &arglen)) {
749:
750: /* it LOOKS like an opt, but is it one?! */
751: if (!find_opt
752: (s, 1, optname, namelen, &errcode,
753: &opt_offset)) {
754: scanopt_err (s, opt_offset, 0, errcode);
755: return errcode;
756: }
757: /* We handle this below. */
758: is_short = 0;
759:
760: /* Check for short opt. */
761: }
762: else if (pstart[0] == '-' && pstart[1]) {
763: /* Pass through to below. */
764: is_short = 1;
765: s->subscript++;
766: pstart++;
767: }
768:
769: else {
770: /* It's not an option. We're done. */
771: return 0;
772: }
773: }
774:
775: /* We have to re-check the subscript status because it
776: * may have changed above. */
777:
778: if (s->subscript != 0) {
779:
780: /* we are somewhere in a run of short opts,
781: * e.g., at the 'z' in `tar -xzf` */
782:
783: optname = pstart;
784: namelen = 1;
785: is_short = 1;
786:
787: if (!find_opt
788: (s, 0, pstart, namelen, &errcode, &opt_offset)) {
789: return scanopt_err (s, opt_offset, 1, errcode);
790: }
791:
792: optarg = pstart + 1;
793: if (!*optarg) {
794: optarg = NULL;
795: arglen = 0;
796: }
797: else
798: arglen = strlen (optarg);
799: }
800:
801: /* At this point, we have a long or short option matched at opt_offset into
802: * the s->options array (and corresponding aux array).
803: * A trailing argument is in {optarg,arglen}, if any.
804: */
805:
806: /* Look ahead in argv[] to see if there is something
807: * that we can use as an argument (if needed). */
808: has_next = s->index + 1 < s->argc
809: && strcmp ("--", s->argv[s->index + 1]) != 0;
810:
811: optp = s->options + opt_offset;
812: auxp = s->aux + opt_offset;
813:
814: /* case: no args allowed */
815: if (auxp->flags & ARG_NONE) {
816: if (optarg && !is_short) {
817: scanopt_err (s, opt_offset, is_short, errcode =
818: SCANOPT_ERR_ARG_NOT_ALLOWED);
819: INC_INDEX (s, 1);
820: return errcode;
821: }
822: else if (!optarg)
823: INC_INDEX (s, 1);
824: else
825: s->subscript++;
826: return optp->r_val;
827: }
828:
829: /* case: required */
830: if (auxp->flags & ARG_REQ) {
831: if (!optarg && !has_next)
832: return scanopt_err (s, opt_offset, is_short,
833: SCANOPT_ERR_ARG_NOT_FOUND);
834:
835: if (!optarg) {
836: /* Let the next argv element become the argument. */
837: SAFE_ASSIGN (arg, s->argv[s->index + 1]);
838: INC_INDEX (s, 2);
839: }
840: else {
841: SAFE_ASSIGN (arg, (char *) optarg);
842: INC_INDEX (s, 1);
843: }
844: return optp->r_val;
845: }
846:
847: /* case: optional */
848: if (auxp->flags & ARG_OPT) {
849: SAFE_ASSIGN (arg, optarg);
850: INC_INDEX (s, 1);
851: return optp->r_val;
852: }
853:
854:
855: /* Should not reach here. */
856: return 0;
857: }
858:
859:
860: int scanopt_destroy (svoid)
861: scanopt_t *svoid;
862: {
863: struct _scanopt_t *s;
864:
865: s = (struct _scanopt_t *) svoid;
866: if (s) {
867: if (s->aux)
868: free (s->aux);
869: free (s);
870: }
871: return 0;
872: }