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