65b8d087ae654992040e07945bc3ceed72976ee9
[platform/upstream/bash.git] / builtins / bashgetopt.c
1 /* bashgetopt.c -- `getopt' for use by the builtins. */
2
3 /* Copyright (C) 1992 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, 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 <errno.h>
29
30 #include "../shell.h"
31 #include "common.h"
32
33 #define ERR(S, C)       builtin_error("%s%c", (S), (C))
34
35 static int      sp;
36
37 char    *list_optarg;
38 int     list_optopt;
39
40 static WORD_LIST *lhead = (WORD_LIST *)NULL;
41 WORD_LIST       *lcurrent = (WORD_LIST *)NULL;
42 WORD_LIST       *loptend;       /* Points to the first non-option argument in the list */
43
44 int
45 internal_getopt(list, opts)
46 WORD_LIST       *list;
47 char            *opts;
48 {
49         register int c;
50         register char *cp;
51         int     plus;   /* nonzero means to handle +option */
52
53         if (*opts == '+') {
54                 plus = 1;
55                 opts++;
56         } else
57                 plus = 0;
58
59         if (list == 0) {
60                 list_optarg = (char *)NULL;
61                 loptend = (WORD_LIST *)NULL;    /* No non-option arguments */
62                 return -1;
63         }
64
65         if (list != lhead || lhead == 0) {
66                 /* Hmmm.... called with a different word list.  Reset. */
67                 sp = 1;
68                 lcurrent = lhead = list;
69                 loptend = (WORD_LIST *)NULL;
70         }
71
72         if (sp == 1) {
73                 if (lcurrent == 0 ||
74                     (lcurrent->word->word[0] != '-' || lcurrent->word->word[1] == '\0')) {
75                         lhead = (WORD_LIST *)NULL;
76                         loptend = lcurrent;
77                         return(-1);
78                 } else if (lcurrent->word->word[0] == '-' &&
79                            lcurrent->word->word[1] == '-' &&
80                            lcurrent->word->word[2] == 0) {
81                         lhead = (WORD_LIST *)NULL;
82                         loptend = lcurrent->next;
83                         return(-1);
84                 }
85         }
86
87         list_optopt = c = lcurrent->word->word[sp];
88
89         if (c == ':' || (cp = strchr(opts, c)) == NULL) {
90                 ERR("illegal option: -", c);
91                 if (lcurrent->word->word[++sp] == '\0') {
92                         lcurrent = lcurrent->next;
93                         sp = 1;
94                 }
95                 list_optarg = NULL;
96                 if (lcurrent)
97                         loptend = lcurrent->next;
98                 return('?');
99         }
100
101         if (*++cp == ':' || *cp == ';') {
102                 /* `:': Option requires an argument. */
103                 /* `;': option argument may be missing */
104                 /* We allow -l2 as equivalent to -l 2 */
105                 if (lcurrent->word->word[sp+1]) {
106                         list_optarg = lcurrent->word->word + sp + 1;
107                         lcurrent = lcurrent->next;
108                 /* If the specifier is `;', don't set optarg if the next
109                    argument looks like another option. */
110                 } else if (lcurrent->next && (*cp == ':' || lcurrent->next->word->word[0] != '-')) {
111                         lcurrent = lcurrent->next;
112                         list_optarg = lcurrent->word->word;
113                         lcurrent = lcurrent->next;
114                 } else if (*cp == ';') {
115                         list_optarg = (char *)NULL;
116                         lcurrent = lcurrent->next;
117                 } else {        /* lcurrent->next == NULL */
118                         ERR("option requires an argument: -", c);
119                         sp = 1;
120                         list_optarg = (char *)NULL;
121                         return('?');
122                 }
123                 sp = 1;
124         } else if (*cp == '#') {
125                 /* optional numeric argument */
126                 if (lcurrent->word->word[sp+1]) {
127                         if (digit(lcurrent->word->word[sp+1])) {
128                                 list_optarg = lcurrent->word->word + sp + 1;
129                                 lcurrent = lcurrent->next;
130                         } else
131                                 list_optarg = (char *)NULL;
132                 } else {
133                         if (lcurrent->next && legal_number(lcurrent->next->word->word, (long *)0)) {
134                                 lcurrent = lcurrent->next;
135                                 list_optarg = lcurrent->word->word;
136                                 lcurrent = lcurrent->next;
137                         } else
138                                 list_optarg = (char *)NULL;
139                 }
140
141         } else {
142                 /* No argument, just return the option. */
143                 if (lcurrent->word->word[++sp] == '\0') {
144                         sp = 1;
145                         lcurrent = lcurrent->next;
146                 }
147                 list_optarg = (char *)NULL;
148         }
149
150         return(c);
151 }
152
153 /*
154  * reset_internal_getopt -- force the in[ft]ernal getopt to reset
155  */
156
157 void
158 reset_internal_getopt ()
159 {
160         lhead = lcurrent = loptend = (WORD_LIST *)NULL;
161         sp = 1;
162 }
163
164 #ifdef INCLUDE_UNUSED
165 void
166 report_bad_option ()
167 {
168         char s[3];
169
170         s[0] = '-';
171         s[1] = list_optopt;
172         s[2] = '\0';
173         bad_option (s);
174 }
175 #endif