Imported from ../bash-2.04.tar.gz.
[platform/upstream/bash.git] / builtins / getopts.def
1 This file is getopts.def, from which is created getopts.c.
2 It implements the builtin "getopts" in Bash.
3
4 Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
8 Bash is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with Bash; see the file COPYING.  If not, write to the Free Software
20 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
21
22 $PRODUCES getopts.c
23
24 $BUILTIN getopts
25 $FUNCTION getopts_builtin
26 $SHORT_DOC getopts optstring name [arg]
27 Getopts is used by shell procedures to parse positional parameters.
28
29 OPTSTRING contains the option letters to be recognized; if a letter
30 is followed by a colon, the option is expected to have an argument,
31 which should be separated from it by white space.
32
33 Each time it is invoked, getopts will place the next option in the
34 shell variable $name, initializing name if it does not exist, and
35 the index of the next argument to be processed into the shell
36 variable OPTIND.  OPTIND is initialized to 1 each time the shell or
37 a shell script is invoked.  When an option requires an argument,
38 getopts places that argument into the shell variable OPTARG.
39
40 getopts reports errors in one of two ways.  If the first character
41 of OPTSTRING is a colon, getopts uses silent error reporting.  In
42 this mode, no error messages are printed.  If an illegal option is
43 seen, getopts places the option character found into OPTARG.  If a
44 required argument is not found, getopts places a ':' into NAME and
45 sets OPTARG to the option character found.  If getopts is not in
46 silent mode, and an illegal option is seen, getopts places '?' into
47 NAME and unsets OPTARG.  If a required option is not found, a '?'
48 is placed in NAME, OPTARG is unset, and a diagnostic message is
49 printed.
50
51 If the shell variable OPTERR has the value 0, getopts disables the
52 printing of error messages, even if the first character of
53 OPTSTRING is not a colon.  OPTERR has the value 1 by default.
54
55 Getopts normally parses the positional parameters ($0 - $9), but if
56 more arguments are given, they are parsed instead.
57 $END
58
59 #include <config.h>
60
61 #include <stdio.h>
62
63 #if defined (HAVE_UNISTD_H)
64 #  ifdef _MINIX
65 #    include <sys/types.h>
66 #  endif
67 #  include <unistd.h>
68 #endif
69
70 #include "../bashansi.h"
71
72 #include "../shell.h"
73 #include "common.h"
74 #include "bashgetopt.h"
75 #include "getopt.h"
76
77 #define G_EOF           -1
78 #define G_ILLEGAL_OPT   -2
79 #define G_ARG_MISSING   -3
80
81 extern char *this_command_name;
82 extern WORD_LIST *rest_of_args;
83
84 /* getopts_reset is magic code for when OPTIND is reset.  N is the
85    value that has just been assigned to OPTIND. */
86 void
87 getopts_reset (newind)
88      int newind;
89 {
90   sh_optind = newind;
91   sh_badopt = 0;
92 }
93
94 static int
95 getopts_bind_variable (name, value)
96      char *name, *value;
97 {
98   SHELL_VAR *v;
99
100   if (legal_identifier (name))
101     {
102       v = bind_variable (name, value);
103       return (v && (readonly_p (v) == 0)) ? EXECUTION_SUCCESS : EXECUTION_FAILURE;
104     }
105   else
106     {
107       builtin_error ("`%s': not a valid identifier", name);
108       return (EXECUTION_FAILURE);
109     }
110 }
111
112 /* Error handling is now performed as specified by Posix.2, draft 11
113    (identical to that of ksh-88).  The special handling is enabled if
114    the first character of the option string is a colon; this handling
115    disables diagnostic messages concerning missing option arguments
116    and illegal option characters.  The handling is as follows.
117
118    ILLEGAL OPTIONS:
119         name -> "?"
120         if (special_error) then
121                 OPTARG = option character found
122                 no error output
123         else
124                 OPTARG unset
125                 diagnostic message
126         fi
127  
128   MISSING OPTION ARGUMENT;
129         if (special_error) then
130                 name -> ":"
131                 OPTARG = option character found
132         else
133                 name -> "?"
134                 OPTARG unset
135                 diagnostic message
136         fi
137  */
138
139 static int
140 dogetopts (argc, argv)
141      int argc;
142      char **argv;
143 {
144   int ret, special_error, old_opterr, i, n;
145   char strval[2], numval[16];
146   char *optstr;                 /* list of options */
147   char *name;                   /* variable to get flag val */
148   char *t;
149
150   if (argc < 3)
151     {
152       builtin_usage ();
153       return (EX_USAGE);
154     }
155
156   /* argv[0] is "getopts". */
157
158   optstr = argv[1];
159   name = argv[2];
160   argc -= 2;
161   argv += 2;
162
163   special_error = optstr[0] == ':';
164
165   if (special_error)
166     {
167       old_opterr = sh_opterr;
168       optstr++;
169       sh_opterr = 0;            /* suppress diagnostic messages */
170     }
171
172   if (argc > 1)
173     {
174       sh_getopt_restore_state (argv);
175       t = argv[0];
176       argv[0] = dollar_vars[0];
177       ret = sh_getopt (argc, argv, optstr);
178       argv[0] = t;
179     }
180   else if (rest_of_args == (WORD_LIST *)NULL)
181     {
182       for (i = 0; i < 10 && dollar_vars[i]; i++)
183         ;
184
185       sh_getopt_restore_state (dollar_vars);
186       ret = sh_getopt (i, dollar_vars, optstr);
187     }
188   else
189     {
190       register WORD_LIST *words;
191       char **v;
192
193       for (i = 0; i < 10 && dollar_vars[i]; i++)
194         ;
195       for (words = rest_of_args; words; words = words->next, i++)
196         ;
197       v = alloc_array (i + 1);
198       for (i = 0; i < 10 && dollar_vars[i]; i++)
199         v[i] = dollar_vars[i];
200       for (words = rest_of_args; words; words = words->next, i++)
201         v[i] = words->word->word;
202       v[i] = (char *)NULL;
203       sh_getopt_restore_state (v);
204       ret = sh_getopt (i, v, optstr);
205       free (v);
206     }
207
208   if (special_error)
209     sh_opterr = old_opterr;
210
211   /* Set the OPTIND variable in any case, to handle "--" skipping. */
212   if (sh_optind < 10)
213     {
214       numval[14] = sh_optind + '0';
215       numval[15] = '\0';
216       i = 14;
217     }
218   else
219     {
220       numval[i = 15] = '\0';
221       n = sh_optind;
222       do
223         {
224           numval[--i] = (n % 10) + '0';
225         }
226       while (n /= 10);
227     }
228   bind_variable ("OPTIND", numval + i);
229
230   /* If an error occurred, decide which one it is and set the return
231      code appropriately.  In all cases, the option character in error
232      is in OPTOPT.  If an illegal option was encountered, OPTARG is
233      NULL.  If a required option argument was missing, OPTARG points
234      to a NULL string (that is, sh_optarg[0] == 0). */
235   if (ret == '?')
236     {
237       if (sh_optarg == NULL)
238         ret = G_ILLEGAL_OPT;
239       else if (sh_optarg[0] == '\0')
240         ret = G_ARG_MISSING;
241     }
242             
243   if (ret == G_EOF)
244     {
245       getopts_bind_variable (name, "?");
246       return (EXECUTION_FAILURE);
247     }
248
249   if (ret == G_ILLEGAL_OPT)
250     {
251       /* Illegal option encountered. */
252       ret = getopts_bind_variable (name, "?");
253
254       if (special_error)
255         {
256           strval[0] = (char)sh_optopt;
257           strval[1] = '\0';
258           bind_variable ("OPTARG", strval);
259         }
260       else
261         makunbound ("OPTARG", shell_variables);
262
263       return (ret);
264     }
265
266   if (ret == G_ARG_MISSING)
267     {
268       /* Required argument missing. */
269       if (special_error)
270         {
271           ret = getopts_bind_variable (name, ":");
272
273           strval[0] = (char)sh_optopt;
274           strval[1] = '\0';
275           bind_variable ("OPTARG", strval);
276         }
277       else
278         {
279           ret = getopts_bind_variable (name, "?");
280           makunbound ("OPTARG", shell_variables);
281         }
282       return (ret);
283     }                   
284
285   bind_variable ("OPTARG", sh_optarg);
286
287   strval[0] = (char) ret;
288   strval[1] = '\0';
289   return (getopts_bind_variable (name, strval));
290 }
291
292 /* The getopts builtin.  Build an argv, and call dogetopts with it. */
293 int
294 getopts_builtin (list)
295      WORD_LIST *list;
296 {
297   char **av;
298   int ac, ret;
299
300   if (list == 0)
301     {
302       builtin_usage ();
303       return EX_USAGE;
304     }
305
306   reset_internal_getopt ();
307   while ((ret = internal_getopt (list, "")) != -1)
308     {
309       switch (ret)
310         {
311         default:
312           builtin_usage ();
313           return (EX_USAGE);
314         }
315     }
316   list = loptend;
317
318   av = make_builtin_argv (list, &ac);
319   ret = dogetopts (ac, av);
320   free ((char *)av);
321
322   return (ret);
323 }