Imported from ../bash-1.14.7.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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 $PRODUCES getopts.c
23
24 $BUILTIN getopts
25 $DEPENDS_ON GETOPTS_BUILTIN
26 $FUNCTION getopts_builtin
27 $SHORT_DOC getopts optstring name [arg]
28 Getopts is used by shell procedures to parse positional parameters.
29
30 OPTSTRING contains the option letters to be recognized; if a letter
31 is followed by a colon, the option is expected to have an argument,
32 which should be separated from it by white space.
33
34 Each time it is invoked, getopts will place the next option in the
35 shell variable $name, initializing name if it does not exist, and
36 the index of the next argument to be processed into the shell
37 variable OPTIND.  OPTIND is initialized to 1 each time the shell or
38 a shell script is invoked.  When an option requires an argument,
39 getopts places that argument into the shell variable OPTARG.
40
41 getopts reports errors in one of two ways.  If the first character
42 of OPTSTRING is a colon, getopts uses silent error reporting.  In
43 this mode, no error messages are printed.  If an illegal option is
44 seen, getopts places the option character found into OPTARG.  If a
45 required argument is not found, getopts places a ':' into NAME and
46 sets OPTARG to the option character found.  If getopts is not in
47 silent mode, and an illegal option is seen, getopts places '?' into
48 NAME and unsets OPTARG.  If a required option is not found, a '?'
49 is placed in NAME, OPTARG is unset, and a diagnostic message is
50 printed.
51
52 If the shell variable OPTERR has the value 0, getopts disables the
53 printing of error messages, even if the first character of
54 OPTSTRING is not a colon.  OPTERR has the value 1 by default.
55
56 Getopts normally parses the positional parameters ($0 - $9), but if
57 more arguments are given, they are parsed instead.
58 $END
59
60 #include <stdio.h>
61
62 #if defined (HAVE_STRING_H)
63 #  include <string.h>
64 #else /* !HAVE_STRING_H */
65 #  include <strings.h>
66 #endif /* !HAVE_STRING_H */
67
68 #include "../shell.h"
69
70 #if defined (GETOPTS_BUILTIN)
71 #include "getopt.h"
72
73 #define G_EOF           (-1)
74 #define G_ILLEGAL_OPT   (-2)
75 #define G_ARG_MISSING   (-3)
76
77 extern char *this_command_name;
78 extern WORD_LIST *rest_of_args;
79
80 /* getopts_reset is magic code for when OPTIND is reset.  N is the
81    value that has just been assigned to OPTIND. */
82 void
83 getopts_reset (newind)
84      int newind;
85 {
86   sh_optind = newind;
87 }
88
89 /* Error handling is now performed as specified by Posix.2, draft 11
90    (identical to that of ksh-88).  The special handling is enabled if
91    the first character of the option string is a colon; this handling
92    disables diagnostic messages concerning missing option arguments
93    and illegal option characters.  The handling is as follows.
94
95    ILLEGAL OPTIONS:
96         name -> "?"
97         if (special_error) then
98                 OPTARG = option character found
99                 no error output
100         else
101                 OPTARG unset
102                 diagnostic message
103         fi
104  
105   MISSING OPTION ARGUMENT;
106         if (special_error) then
107                 name -> ":"
108                 OPTARG = option character found
109         else
110                 name -> "?"
111                 OPTARG unset
112                 diagnostic message
113         fi
114  */
115
116 static int
117 dogetopts (argc, argv)
118      int argc;
119      char **argv;
120 {
121   int ret, special_error, old_opterr = 0, i, n;
122   char strval[2], numval[16];
123   char *optstr;                 /* list of options */
124   char *name;                   /* variable to get flag val */
125   char *t;
126
127   if (argc < 3)
128     {
129       builtin_error("usage: getopts optstring name [arg]");
130       return (EX_USAGE);
131     }
132
133   /* argv[0] is "getopts". */
134
135   optstr = argv[1];
136   name = argv[2];
137   argc -= 2;
138   argv += 2;
139
140   special_error = optstr[0] == ':';
141
142   if (special_error)
143     {
144       old_opterr = sh_opterr;
145       optstr++;
146       sh_opterr = 0;            /* suppress diagnostic messages */
147     }
148
149   if (argc > 1)
150     {
151       sh_getopt_restore_state (argv);
152       t = argv[0];
153       argv[0] = dollar_vars[0];
154       ret = sh_getopt (argc, argv, optstr);
155       argv[0] = t;
156     }
157   else if (rest_of_args == (WORD_LIST *)NULL)
158     {
159       register int i;
160
161       for (i = 0; i < 10 && dollar_vars[i]; i++);
162       ret = sh_getopt (i, dollar_vars, optstr);
163     }
164   else
165     {
166       register int i;
167       register WORD_LIST *words;
168       char **v;
169
170       for (i = 0; i < 10 && dollar_vars[i]; i++);
171       for (words = rest_of_args; words; words = words->next, i++);
172       v = (char **)xmalloc ((i + 1) * sizeof (char *));
173       for (i = 0; i < 10 && dollar_vars[i]; i++)
174         v[i] = dollar_vars[i];
175       for (words = rest_of_args; words; words = words->next, i++)
176         v[i] = words->word->word;
177       v[i] = (char *)NULL;
178       ret = sh_getopt (i, v, optstr);
179       free (v);
180     }
181
182   if (special_error)
183     sh_opterr = old_opterr;
184
185   /* Set the OPTIND variable in any case, to handle "--" skipping. */
186   if (sh_optind < 10)
187     {
188       numval[14] = sh_optind + '0';
189       numval[15] = '\0';
190       i = 14;
191     }
192   else
193     {
194       numval[i = 15] = '\0';
195       n = sh_optind;
196       do
197         {
198           numval[--i] = (n % 10) + '0';
199         }
200       while (n /= 10);
201     }
202   bind_variable ("OPTIND", numval + i);
203
204   /* If an error occurred, decide which one it is and set the return
205      code appropriately.  In all cases, the option character in error
206      is in SH_OPTOPT.  If an illegal option was encountered, OPTARG is
207      NULL.  If a required option argument was missing, OPTARG points
208      to a NULL string (that is, optarg[0] == 0). */
209   if (ret == '?')
210     {
211       if (sh_optarg == NULL)
212         ret = G_ILLEGAL_OPT;
213       else if (sh_optarg[0] == '\0')
214         ret = G_ARG_MISSING;
215     }
216             
217   if (ret == G_EOF)
218     {
219       bind_variable (name, "?");
220       return (EXECUTION_FAILURE);
221     }
222
223   if (ret == G_ILLEGAL_OPT)
224     {
225       /* Illegal option encountered. */
226       strval[0] = '?';
227       strval[1] = '\0';
228       bind_variable (name, strval);
229
230       if (special_error)
231         {
232           strval[0] = (char) sh_optopt;
233           strval[1] = '\0';
234           bind_variable ("OPTARG", strval);
235         }
236       else
237         makunbound ("OPTARG", shell_variables);
238       return (EXECUTION_SUCCESS);
239     }
240
241   if (ret == G_ARG_MISSING)
242     {
243       /* Required argument missing. */
244       if (special_error)
245         {
246           strval[0] = ':';
247           strval[1] = '\0';
248           bind_variable (name, strval);
249
250           strval[0] = (char) sh_optopt;
251           strval[1] = '\0';
252           bind_variable ("OPTARG", strval);
253         }
254       else
255         {
256           strval[0] = '?';
257           strval[1] = '\0';
258           bind_variable (name, strval);
259           makunbound ("OPTARG", shell_variables);
260         }
261       return (EXECUTION_SUCCESS);
262     }                   
263
264   bind_variable ("OPTARG", sh_optarg);
265
266   strval[0] = (char) ret;
267   strval[1] = '\0';
268   bind_variable (name, strval);
269
270   return (EXECUTION_SUCCESS);
271 }
272
273 /* The getopts builtin.  Build an argv, and call dogetopts with it. */
274 int
275 getopts_builtin (list)
276      WORD_LIST *list;
277 {
278   register int  i;
279   char **av;
280   int ac, ret;
281   WORD_LIST *t;
282
283   if (list == 0)
284     return EXECUTION_FAILURE;
285
286   for (t = list, ac = 0; t; t = t->next, ac++);
287
288   ac++;
289   av = (char **)xmalloc ((1 + ac) * sizeof (char *));
290   av[ac] = (char *) NULL;
291   av[0] = this_command_name;
292
293   for (t = list, i = 1; t; t = t->next, i++)
294     av[i] = t->word->word;
295
296   ret = dogetopts (ac, av);
297   free ((char *)av);
298   return (ret);
299 }
300 #endif /* GETOPTS_BUILTIN */