| 1 | /* bashgetopt.c -- `getopt' for use by the builtins. */
|
|---|
| 2 |
|
|---|
| 3 | /* Copyright (C) 1992-2002 Free Software Foundation, Inc.
|
|---|
| 4 |
|
|---|
| 5 | This file is part of GNU Bash, the Bourne Again SHell.
|
|---|
| 6 |
|
|---|
| 7 | Bash is free software; you can redistribute it and/or modify it under
|
|---|
| 8 | the terms of the GNU General Public License as published by the Free
|
|---|
| 9 | Software Foundation; either version 2, or (at your option) any later
|
|---|
| 10 | version.
|
|---|
| 11 |
|
|---|
| 12 | Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
|---|
| 13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|---|
| 14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|---|
| 15 | for more details.
|
|---|
| 16 |
|
|---|
| 17 | You should have received a copy of the GNU General Public License along
|
|---|
| 18 | with Bash; see the file COPYING. If not, write to the Free Software
|
|---|
| 19 | Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
|---|
| 20 |
|
|---|
| 21 | #include <config.h>
|
|---|
| 22 |
|
|---|
| 23 | #if defined (HAVE_UNISTD_H)
|
|---|
| 24 | # include <unistd.h>
|
|---|
| 25 | #endif
|
|---|
| 26 |
|
|---|
| 27 | #include "../bashansi.h"
|
|---|
| 28 | #include <chartypes.h>
|
|---|
| 29 | #include <errno.h>
|
|---|
| 30 |
|
|---|
| 31 | #include "../shell.h"
|
|---|
| 32 | #include "common.h"
|
|---|
| 33 |
|
|---|
| 34 | #define ISOPT(s) (((*(s) == '-') || (plus && *(s) == '+')) && (s)[1])
|
|---|
| 35 | #define NOTOPT(s) (((*(s) != '-') && (!plus || *(s) != '+')) || (s)[1] == '\0')
|
|---|
| 36 |
|
|---|
| 37 | static int sp;
|
|---|
| 38 |
|
|---|
| 39 | char *list_optarg;
|
|---|
| 40 | int list_optopt;
|
|---|
| 41 | int list_opttype;
|
|---|
| 42 |
|
|---|
| 43 | static WORD_LIST *lhead = (WORD_LIST *)NULL;
|
|---|
| 44 | WORD_LIST *lcurrent = (WORD_LIST *)NULL;
|
|---|
| 45 | WORD_LIST *loptend; /* Points to the first non-option argument in the list */
|
|---|
| 46 |
|
|---|
| 47 | int
|
|---|
| 48 | internal_getopt(list, opts)
|
|---|
| 49 | WORD_LIST *list;
|
|---|
| 50 | char *opts;
|
|---|
| 51 | {
|
|---|
| 52 | register int c;
|
|---|
| 53 | register char *cp;
|
|---|
| 54 | int plus; /* nonzero means to handle +option */
|
|---|
| 55 | static char errstr[3] = { '-', '\0', '\0' };
|
|---|
| 56 |
|
|---|
| 57 | plus = *opts == '+';
|
|---|
| 58 | if (plus)
|
|---|
| 59 | opts++;
|
|---|
| 60 |
|
|---|
| 61 | if (list == 0) {
|
|---|
| 62 | list_optarg = (char *)NULL;
|
|---|
| 63 | loptend = (WORD_LIST *)NULL; /* No non-option arguments */
|
|---|
| 64 | return -1;
|
|---|
| 65 | }
|
|---|
| 66 |
|
|---|
| 67 | if (list != lhead || lhead == 0) {
|
|---|
| 68 | /* Hmmm.... called with a different word list. Reset. */
|
|---|
| 69 | sp = 1;
|
|---|
| 70 | lcurrent = lhead = list;
|
|---|
| 71 | loptend = (WORD_LIST *)NULL;
|
|---|
| 72 | }
|
|---|
| 73 |
|
|---|
| 74 | if (sp == 1) {
|
|---|
| 75 | if (lcurrent == 0 || NOTOPT(lcurrent->word->word)) {
|
|---|
| 76 | lhead = (WORD_LIST *)NULL;
|
|---|
| 77 | loptend = lcurrent;
|
|---|
| 78 | return(-1);
|
|---|
| 79 | } else if (lcurrent->word->word[0] == '-' &&
|
|---|
| 80 | lcurrent->word->word[1] == '-' &&
|
|---|
| 81 | lcurrent->word->word[2] == 0) {
|
|---|
| 82 | lhead = (WORD_LIST *)NULL;
|
|---|
| 83 | loptend = lcurrent->next;
|
|---|
| 84 | return(-1);
|
|---|
| 85 | }
|
|---|
| 86 | errstr[0] = list_opttype = lcurrent->word->word[0];
|
|---|
| 87 | }
|
|---|
| 88 |
|
|---|
| 89 | list_optopt = c = lcurrent->word->word[sp];
|
|---|
| 90 |
|
|---|
| 91 | if (c == ':' || (cp = strchr(opts, c)) == NULL) {
|
|---|
| 92 | errstr[1] = c;
|
|---|
| 93 | sh_invalidopt (errstr);
|
|---|
| 94 | if (lcurrent->word->word[++sp] == '\0') {
|
|---|
| 95 | lcurrent = lcurrent->next;
|
|---|
| 96 | sp = 1;
|
|---|
| 97 | }
|
|---|
| 98 | list_optarg = NULL;
|
|---|
| 99 | if (lcurrent)
|
|---|
| 100 | loptend = lcurrent->next;
|
|---|
| 101 | return('?');
|
|---|
| 102 | }
|
|---|
| 103 |
|
|---|
| 104 | if (*++cp == ':' || *cp == ';') {
|
|---|
| 105 | /* `:': Option requires an argument. */
|
|---|
| 106 | /* `;': option argument may be missing */
|
|---|
| 107 | /* We allow -l2 as equivalent to -l 2 */
|
|---|
| 108 | if (lcurrent->word->word[sp+1]) {
|
|---|
| 109 | list_optarg = lcurrent->word->word + sp + 1;
|
|---|
| 110 | lcurrent = lcurrent->next;
|
|---|
| 111 | /* If the specifier is `;', don't set optarg if the next
|
|---|
| 112 | argument looks like another option. */
|
|---|
| 113 | #if 0
|
|---|
| 114 | } else if (lcurrent->next && (*cp == ':' || lcurrent->next->word->word[0] != '-')) {
|
|---|
| 115 | #else
|
|---|
| 116 | } else if (lcurrent->next && (*cp == ':' || NOTOPT(lcurrent->next->word->word))) {
|
|---|
| 117 | #endif
|
|---|
| 118 | lcurrent = lcurrent->next;
|
|---|
| 119 | list_optarg = lcurrent->word->word;
|
|---|
| 120 | lcurrent = lcurrent->next;
|
|---|
| 121 | } else if (*cp == ';') {
|
|---|
| 122 | list_optarg = (char *)NULL;
|
|---|
| 123 | lcurrent = lcurrent->next;
|
|---|
| 124 | } else { /* lcurrent->next == NULL */
|
|---|
| 125 | errstr[1] = c;
|
|---|
| 126 | sh_needarg (errstr);
|
|---|
| 127 | sp = 1;
|
|---|
| 128 | list_optarg = (char *)NULL;
|
|---|
| 129 | return('?');
|
|---|
| 130 | }
|
|---|
| 131 | sp = 1;
|
|---|
| 132 | } else if (*cp == '#') {
|
|---|
| 133 | /* option requires a numeric argument */
|
|---|
| 134 | if (lcurrent->word->word[sp+1]) {
|
|---|
| 135 | if (DIGIT(lcurrent->word->word[sp+1])) {
|
|---|
| 136 | list_optarg = lcurrent->word->word + sp + 1;
|
|---|
| 137 | lcurrent = lcurrent->next;
|
|---|
| 138 | } else
|
|---|
| 139 | list_optarg = (char *)NULL;
|
|---|
| 140 | } else {
|
|---|
| 141 | if (lcurrent->next && legal_number(lcurrent->next->word->word, (intmax_t *)0)) {
|
|---|
| 142 | lcurrent = lcurrent->next;
|
|---|
| 143 | list_optarg = lcurrent->word->word;
|
|---|
| 144 | lcurrent = lcurrent->next;
|
|---|
| 145 | } else {
|
|---|
| 146 | errstr[1] = c;
|
|---|
| 147 | sh_neednumarg (errstr);
|
|---|
| 148 | sp = 1;
|
|---|
| 149 | list_optarg = (char *)NULL;
|
|---|
| 150 | return ('?');
|
|---|
| 151 | }
|
|---|
| 152 | }
|
|---|
| 153 |
|
|---|
| 154 | } else {
|
|---|
| 155 | /* No argument, just return the option. */
|
|---|
| 156 | if (lcurrent->word->word[++sp] == '\0') {
|
|---|
| 157 | sp = 1;
|
|---|
| 158 | lcurrent = lcurrent->next;
|
|---|
| 159 | }
|
|---|
| 160 | list_optarg = (char *)NULL;
|
|---|
| 161 | }
|
|---|
| 162 |
|
|---|
| 163 | return(c);
|
|---|
| 164 | }
|
|---|
| 165 |
|
|---|
| 166 | /*
|
|---|
| 167 | * reset_internal_getopt -- force the in[ft]ernal getopt to reset
|
|---|
| 168 | */
|
|---|
| 169 |
|
|---|
| 170 | void
|
|---|
| 171 | reset_internal_getopt ()
|
|---|
| 172 | {
|
|---|
| 173 | lhead = lcurrent = loptend = (WORD_LIST *)NULL;
|
|---|
| 174 | sp = 1;
|
|---|
| 175 | }
|
|---|