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