6e69eb6e9513fe0e48ac58a7d5755bcaa2b33d3d
[platform/upstream/bash.git] / builtins / set.def
1 This file is set.def, from which is created set.c.
2 It implements the "set" and "unset" builtins in Bash.
3
4 Copyright (C) 1987-2009 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
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 Bash is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Bash.  If not, see <http://www.gnu.org/licenses/>.
20
21 $PRODUCES set.c
22
23 #include <config.h>
24
25 #if defined (HAVE_UNISTD_H)
26 #  ifdef _MINIX
27 #    include <sys/types.h>
28 #  endif
29 #  include <unistd.h>
30 #endif
31
32 #include <stdio.h>
33
34 #include "../bashansi.h"
35 #include "../bashintl.h"
36
37 #include "../shell.h"
38 #include "../flags.h"
39 #include "common.h"
40 #include "bashgetopt.h"
41
42 #if defined (READLINE)
43 #  include "../input.h"
44 #  include "../bashline.h"
45 #  include <readline/readline.h>
46 #endif
47
48 #if defined (HISTORY)
49 #  include "../bashhist.h"
50 #endif
51
52 extern int posixly_correct, ignoreeof, eof_encountered_limit;
53 #if defined (HISTORY)
54 extern int dont_save_function_defs;
55 #endif
56 #if defined (READLINE)
57 extern int no_line_editing;
58 #endif /* READLINE */
59
60 $BUILTIN set
61 $FUNCTION set_builtin
62 $SHORT_DOC set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]
63 Set or unset values of shell options and positional parameters.
64
65 Change the value of shell attributes and positional parameters, or
66 display the names and values of shell variables.
67
68 Options:
69   -a  Mark variables which are modified or created for export.
70   -b  Notify of job termination immediately.
71   -e  Exit immediately if a command exits with a non-zero status.
72   -f  Disable file name generation (globbing).
73   -h  Remember the location of commands as they are looked up.
74   -k  All assignment arguments are placed in the environment for a
75       command, not just those that precede the command name.
76   -m  Job control is enabled.
77   -n  Read commands but do not execute them.
78   -o option-name
79       Set the variable corresponding to option-name:
80           allexport    same as -a
81           braceexpand  same as -B
82 #if defined (READLINE)
83           emacs        use an emacs-style line editing interface
84 #endif /* READLINE */
85           errexit      same as -e
86           errtrace     same as -E
87           functrace    same as -T
88           hashall      same as -h
89 #if defined (BANG_HISTORY)
90           histexpand   same as -H
91 #endif /* BANG_HISTORY */
92 #if defined (HISTORY)
93           history      enable command history
94 #endif
95           ignoreeof    the shell will not exit upon reading EOF
96           interactive-comments
97                        allow comments to appear in interactive commands
98           keyword      same as -k
99           monitor      same as -m
100           noclobber    same as -C
101           noexec       same as -n
102           noglob       same as -f
103           nolog        currently accepted but ignored
104           notify       same as -b
105           nounset      same as -u
106           onecmd       same as -t
107           physical     same as -P
108           pipefail     the return value of a pipeline is the status of
109                        the last command to exit with a non-zero status,
110                        or zero if no command exited with a non-zero status
111           posix        change the behavior of bash where the default
112                        operation differs from the Posix standard to
113                        match the standard
114           privileged   same as -p
115           verbose      same as -v
116 #if defined (READLINE)
117           vi           use a vi-style line editing interface
118 #endif /* READLINE */
119           xtrace       same as -x
120   -p  Turned on whenever the real and effective user ids do not match.
121       Disables processing of the $ENV file and importing of shell
122       functions.  Turning this option off causes the effective uid and
123       gid to be set to the real uid and gid.
124   -t  Exit after reading and executing one command.
125   -u  Treat unset variables as an error when substituting.
126   -v  Print shell input lines as they are read.
127   -x  Print commands and their arguments as they are executed.
128 #if defined (BRACE_EXPANSION)
129   -B  the shell will perform brace expansion
130 #endif /* BRACE_EXPANSION */
131   -C  If set, disallow existing regular files to be overwritten
132       by redirection of output.
133   -E  If set, the ERR trap is inherited by shell functions.
134 #if defined (BANG_HISTORY)
135   -H  Enable ! style history substitution.  This flag is on
136       by default when the shell is interactive.
137 #endif /* BANG_HISTORY */
138   -P  If set, do not follow symbolic links when executing commands
139       such as cd which change the current directory.
140   -T  If set, the DEBUG trap is inherited by shell functions.
141   --  Assign any remaining arguments to the positional parameters.
142       If there are no remaining arguments, the positional parameters
143       are unset.
144   -   Assign any remaining arguments to the positional parameters.
145       The -x and -v options are turned off.
146
147 Using + rather than - causes these flags to be turned off.  The
148 flags can also be used upon invocation of the shell.  The current
149 set of flags may be found in $-.  The remaining n ARGs are positional
150 parameters and are assigned, in order, to $1, $2, .. $n.  If no
151 ARGs are given, all shell variables are printed.
152
153 Exit Status:
154 Returns success unless an invalid option is given.
155 $END
156
157 typedef int setopt_set_func_t __P((int, char *));
158 typedef int setopt_get_func_t __P((char *));
159
160 static void print_minus_o_option __P((char *, int, int));
161 static void print_all_shell_variables __P((void));
162
163 static int set_ignoreeof __P((int, char *));
164 static int set_posix_mode __P((int, char *));
165
166 #if defined (READLINE)
167 static int set_edit_mode __P((int, char *));
168 static int get_edit_mode __P((char *));
169 #endif
170
171 #if defined (HISTORY)
172 static int bash_set_history __P((int, char *));
173 #endif
174
175 static const char * const on = "on";
176 static const char * const off = "off";
177
178 /* A struct used to match long options for set -o to the corresponding
179    option letter or internal variable.  The functions can be called to
180    dynamically generate values. */
181 const struct {
182   char *name;
183   int letter;
184   int *variable;
185   setopt_set_func_t *set_func;
186   setopt_get_func_t *get_func;
187 } o_options[] = {
188   { "allexport",  'a', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
189 #if defined (BRACE_EXPANSION)
190   { "braceexpand",'B', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
191 #endif
192 #if defined (READLINE)
193   { "emacs",     '\0', (int *)NULL, set_edit_mode, get_edit_mode },
194 #endif
195   { "errexit",    'e', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
196   { "errtrace",   'E', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
197   { "functrace",  'T', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
198   { "hashall",    'h', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
199 #if defined (BANG_HISTORY)
200   { "histexpand", 'H', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
201 #endif /* BANG_HISTORY */
202 #if defined (HISTORY)
203   { "history",   '\0', &enable_history_list, bash_set_history, (setopt_get_func_t *)NULL },
204 #endif
205   { "ignoreeof", '\0', &ignoreeof, set_ignoreeof, (setopt_get_func_t *)NULL },
206   { "interactive-comments", '\0', &interactive_comments, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
207   { "keyword",    'k', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
208   { "monitor",    'm', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
209   { "noclobber",  'C', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
210   { "noexec",     'n', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
211   { "noglob",     'f', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
212 #if defined (HISTORY)
213   { "nolog",     '\0', &dont_save_function_defs, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
214 #endif
215 #if defined (JOB_CONTROL)
216   { "notify",     'b', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
217 #endif /* JOB_CONTROL */
218   { "nounset",    'u', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
219   { "onecmd",     't', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
220   { "physical",   'P', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
221   { "pipefail",  '\0', &pipefail_opt, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
222   { "posix",     '\0', &posixly_correct, set_posix_mode, (setopt_get_func_t *)NULL },
223   { "privileged", 'p', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
224   { "verbose",    'v', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
225 #if defined (READLINE)
226   { "vi",        '\0', (int *)NULL, set_edit_mode, get_edit_mode },
227 #endif
228   { "xtrace",     'x', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
229   {(char *)NULL, 0 , (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
230 };
231
232 #define N_O_OPTIONS     (sizeof (o_options) / sizeof (o_options[0]))
233
234 #define GET_BINARY_O_OPTION_VALUE(i, name) \
235   ((o_options[i].get_func) ? (*o_options[i].get_func) (name) \
236                            : (*o_options[i].variable))
237
238 #define SET_BINARY_O_OPTION_VALUE(i, onoff, name) \
239   ((o_options[i].set_func) ? (*o_options[i].set_func) (onoff, name) \
240                            : (*o_options[i].variable = (onoff == FLAG_ON)))
241
242 int
243 minus_o_option_value (name)
244      char *name;
245 {
246   register int  i;
247   int *on_or_off;
248
249   for (i = 0; o_options[i].name; i++)
250     {
251       if (STREQ (name, o_options[i].name))
252         {
253           if (o_options[i].letter)
254             {
255               on_or_off = find_flag (o_options[i].letter);
256               return ((on_or_off == FLAG_UNKNOWN) ? -1 : *on_or_off);
257             }
258           else
259             return (GET_BINARY_O_OPTION_VALUE (i, name));
260         }
261     }
262
263   return (-1);
264 }
265
266 #define MINUS_O_FORMAT "%-15s\t%s\n"
267
268 static void
269 print_minus_o_option (name, value, pflag)
270      char *name;
271      int value, pflag;
272 {
273   if (pflag == 0)
274     printf (MINUS_O_FORMAT, name, value ? on : off);
275   else
276     printf ("set %co %s\n", value ? '-' : '+', name);
277 }
278
279 void
280 list_minus_o_opts (mode, reusable)
281      int mode, reusable;
282 {
283   register int  i;
284   int *on_or_off, value;
285
286   for (i = 0; o_options[i].name; i++)
287     {
288       if (o_options[i].letter)
289         {
290           value = 0;
291           on_or_off = find_flag (o_options[i].letter);
292           if (on_or_off == FLAG_UNKNOWN)
293             on_or_off = &value;
294           if (mode == -1 || mode == *on_or_off)
295             print_minus_o_option (o_options[i].name, *on_or_off, reusable);
296         }
297       else
298         {
299           value = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
300           if (mode == -1 || mode == value)
301             print_minus_o_option (o_options[i].name, value, reusable);
302         }
303     }
304 }
305
306 char **
307 get_minus_o_opts ()
308 {
309   char **ret;
310   int i;
311
312   ret = strvec_create (N_O_OPTIONS + 1);
313   for (i = 0; o_options[i].name; i++)
314     ret[i] = o_options[i].name;
315   ret[i] = (char *)NULL;
316   return ret;
317 }
318
319 static int
320 set_ignoreeof (on_or_off, option_name)
321      int on_or_off;
322      char *option_name;
323 {
324   ignoreeof = on_or_off == FLAG_ON;
325   unbind_variable ("ignoreeof");
326   if (ignoreeof)
327     bind_variable ("IGNOREEOF", "10", 0); 
328   else
329     unbind_variable ("IGNOREEOF");
330   sv_ignoreeof ("IGNOREEOF");
331   return 0;
332 }
333
334 static int
335 set_posix_mode (on_or_off, option_name)
336      int on_or_off;
337      char *option_name;
338 {
339   posixly_correct = on_or_off == FLAG_ON;
340   if (posixly_correct == 0)
341     unbind_variable ("POSIXLY_CORRECT");
342   else
343     bind_variable ("POSIXLY_CORRECT", "y", 0);
344   sv_strict_posix ("POSIXLY_CORRECT");
345   return (0);
346 }
347
348 #if defined (READLINE)
349 /* Magic.  This code `knows' how readline handles rl_editing_mode. */
350 static int
351 set_edit_mode (on_or_off, option_name)
352      int on_or_off;
353      char *option_name;
354 {
355   int isemacs;
356
357   if (on_or_off == FLAG_ON)
358     {
359       rl_variable_bind ("editing-mode", option_name);
360
361       if (interactive)
362         with_input_from_stdin ();
363       no_line_editing = 0;
364     }
365   else
366     {
367       isemacs = rl_editing_mode == 1;
368       if ((isemacs && *option_name == 'e') || (!isemacs && *option_name == 'v'))
369         {
370           if (interactive)
371             with_input_from_stream (stdin, "stdin");
372           no_line_editing = 1;
373         }
374     }
375   return 1-no_line_editing;
376 }
377
378 static int
379 get_edit_mode (name)
380      char *name;
381 {
382   return (*name == 'e' ? no_line_editing == 0 && rl_editing_mode == 1
383                        : no_line_editing == 0 && rl_editing_mode == 0);
384 }
385 #endif /* READLINE */
386
387 #if defined (HISTORY)
388 static int
389 bash_set_history (on_or_off, option_name)
390      int on_or_off;
391      char *option_name;
392 {
393   if (on_or_off == FLAG_ON)
394     {
395       enable_history_list = 1;
396       bash_history_enable ();
397       if (history_lines_this_session == 0)
398         load_history ();
399     }
400   else
401     {
402       enable_history_list = 0;
403       bash_history_disable ();
404     }
405   return (1 - enable_history_list);
406 }
407 #endif
408
409 int
410 set_minus_o_option (on_or_off, option_name)
411      int on_or_off;
412      char *option_name;
413 {
414   register int i;
415
416   for (i = 0; o_options[i].name; i++)
417     {
418       if (STREQ (option_name, o_options[i].name))
419         {
420           if (o_options[i].letter == 0)
421             {
422               SET_BINARY_O_OPTION_VALUE (i, on_or_off, option_name);
423               return (EXECUTION_SUCCESS);
424             }
425           else
426             {
427               if (change_flag (o_options[i].letter, on_or_off) == FLAG_ERROR)
428                 {
429                   sh_invalidoptname (option_name);
430                   return (EXECUTION_FAILURE);
431                 }
432               else
433                 return (EXECUTION_SUCCESS);
434             }
435
436         }
437     }
438
439   sh_invalidoptname (option_name);
440   return (EX_USAGE);
441 }
442
443 static void
444 print_all_shell_variables ()
445 {
446   SHELL_VAR **vars;
447
448   vars = all_shell_variables ();
449   if (vars)
450     {
451       print_var_list (vars);
452       free (vars);
453     }
454
455   /* POSIX.2 does not allow function names and definitions to be output when
456      `set' is invoked without options (PASC Interp #202). */
457   if (posixly_correct == 0)
458     {
459       vars = all_shell_functions ();
460       if (vars)
461         {
462           print_func_list (vars);
463           free (vars);
464         }
465     }
466 }
467
468 void
469 set_shellopts ()
470 {
471   char *value;
472   char tflag[N_O_OPTIONS];
473   int vsize, i, vptr, *ip, exported;
474   SHELL_VAR *v;
475
476   for (vsize = i = 0; o_options[i].name; i++)
477     {
478       tflag[i] = 0;
479       if (o_options[i].letter)
480         {
481           ip = find_flag (o_options[i].letter);
482           if (ip && *ip)
483             {
484               vsize += strlen (o_options[i].name) + 1;
485               tflag[i] = 1;
486             }
487         }
488       else if (GET_BINARY_O_OPTION_VALUE (i, o_options[i].name))
489         {
490           vsize += strlen (o_options[i].name) + 1;
491           tflag[i] = 1;
492         }
493     }
494
495   value = (char *)xmalloc (vsize + 1);
496
497   for (i = vptr = 0; o_options[i].name; i++)
498     {
499       if (tflag[i])
500         {
501           strcpy (value + vptr, o_options[i].name);
502           vptr += strlen (o_options[i].name);
503           value[vptr++] = ':';
504         }
505     }
506
507   if (vptr)
508     vptr--;                     /* cut off trailing colon */
509   value[vptr] = '\0';
510
511   v = find_variable ("SHELLOPTS");
512
513   /* Turn off the read-only attribute so we can bind the new value, and
514      note whether or not the variable was exported. */
515   if (v)
516     {
517       VUNSETATTR (v, att_readonly);
518       exported = exported_p (v);
519     }
520   else
521     exported = 0;
522
523   v = bind_variable ("SHELLOPTS", value, 0);
524
525   /* Turn the read-only attribute back on, and turn off the export attribute
526      if it was set implicitly by mark_modified_vars and SHELLOPTS was not
527      exported before we bound the new value. */
528   VSETATTR (v, att_readonly);
529   if (mark_modified_vars && exported == 0 && exported_p (v))
530     VUNSETATTR (v, att_exported);
531
532   free (value);
533 }
534
535 void
536 parse_shellopts (value)
537      char *value;
538 {
539   char *vname;
540   int vptr;
541
542   vptr = 0;
543   while (vname = extract_colon_unit (value, &vptr))
544     {
545       set_minus_o_option (FLAG_ON, vname);
546       free (vname);
547     }
548 }
549
550 void
551 initialize_shell_options (no_shellopts)
552      int no_shellopts;
553 {
554   char *temp;
555   SHELL_VAR *var;
556
557   if (no_shellopts == 0)
558     {
559       var = find_variable ("SHELLOPTS");
560       /* set up any shell options we may have inherited. */
561       if (var && imported_p (var))
562         {
563           temp = (array_p (var) || assoc_p (var)) ? (char *)NULL : savestring (value_cell (var));
564           if (temp)
565             {
566               parse_shellopts (temp);
567               free (temp);
568             }
569         }
570     }
571
572   /* Set up the $SHELLOPTS variable. */
573   set_shellopts ();
574 }
575
576 /* Reset the values of the -o options that are not also shell flags.  This is
577    called from execute_cmd.c:initialize_subshell() when setting up a subshell
578    to run an executable shell script without a leading `#!'. */
579 void
580 reset_shell_options ()
581 {
582 #if defined (HISTORY)
583   remember_on_history = enable_history_list = 1;
584 #endif
585   ignoreeof = 0;
586 }
587
588 /* Set some flags from the word values in the input list.  If LIST is empty,
589    then print out the values of the variables instead.  If LIST contains
590    non-flags, then set $1 - $9 to the successive words of LIST. */
591 int
592 set_builtin (list)
593      WORD_LIST *list;
594 {
595   int on_or_off, flag_name, force_assignment, opts_changed, rv, r;
596   register char *arg;
597   char s[3];
598
599   if (list == 0)
600     {
601       print_all_shell_variables ();
602       return (sh_chkwrite (EXECUTION_SUCCESS));
603     }
604
605   /* Check validity of flag arguments. */
606   rv = EXECUTION_SUCCESS;
607   reset_internal_getopt ();
608   while ((flag_name = internal_getopt (list, optflags)) != -1)
609     {
610       switch (flag_name)
611         {
612           case '?':
613             builtin_usage ();
614             return (list_optopt == '?' ? EXECUTION_SUCCESS : EX_USAGE);
615           default:
616             break;
617         }
618     }
619     
620   /* Do the set command.  While the list consists of words starting with
621      '-' or '+' treat them as flags, otherwise, start assigning them to
622      $1 ... $n. */
623   for (force_assignment = opts_changed = 0; list; )
624     {
625       arg = list->word->word;
626
627       /* If the argument is `--' or `-' then signal the end of the list
628          and remember the remaining arguments. */
629       if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2])))
630         {
631           list = list->next;
632
633           /* `set --' unsets the positional parameters. */
634           if (arg[1] == '-')
635             force_assignment = 1;
636
637           /* Until told differently, the old shell behaviour of
638              `set - [arg ...]' being equivalent to `set +xv [arg ...]'
639              stands.  Posix.2 says the behaviour is marked as obsolescent. */
640           else
641             {
642               change_flag ('x', '+');
643               change_flag ('v', '+');
644               opts_changed = 1;
645             }
646
647           break;
648         }
649
650       if ((on_or_off = *arg) && (on_or_off == '-' || on_or_off == '+'))
651         {
652           while (flag_name = *++arg)
653             {
654               if (flag_name == '?')
655                 {
656                   builtin_usage ();
657                   return (EXECUTION_SUCCESS);
658                 }
659               else if (flag_name == 'o') /* -+o option-name */
660                 {
661                   char *option_name;
662                   WORD_LIST *opt;
663
664                   opt = list->next;
665
666                   if (opt == 0)
667                     {
668                       list_minus_o_opts (-1, (on_or_off == '+'));
669                       rv = sh_chkwrite (rv);
670                       continue;
671                     }
672
673                   option_name = opt->word->word;
674
675                   if (option_name == 0 || *option_name == '\0' ||
676                       *option_name == '-' || *option_name == '+')
677                     {
678                       list_minus_o_opts (-1, (on_or_off == '+'));
679                       continue;
680                     }
681                   list = list->next; /* Skip over option name. */
682
683                   opts_changed = 1;
684                   if ((r = set_minus_o_option (on_or_off, option_name)) != EXECUTION_SUCCESS)
685                     {
686                       set_shellopts ();
687                       return (r);
688                     }
689                 }
690               else if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
691                 {
692                   s[0] = on_or_off;
693                   s[1] = flag_name;
694                   s[2] = '\0';
695                   sh_invalidopt (s);
696                   builtin_usage ();
697                   set_shellopts ();
698                   return (EXECUTION_FAILURE);
699                 }
700               opts_changed = 1;
701             }
702         }
703       else
704         {
705           break;
706         }
707       list = list->next;
708     }
709
710   /* Assigning $1 ... $n */
711   if (list || force_assignment)
712     remember_args (list, 1);
713   /* Set up new value of $SHELLOPTS */
714   if (opts_changed)
715     set_shellopts ();
716   return (rv);
717 }
718
719 $BUILTIN unset
720 $FUNCTION unset_builtin
721 $SHORT_DOC unset [-f] [-v] [name ...]
722 Unset values and attributes of shell variables and functions.
723
724 For each NAME, remove the corresponding variable or function.
725
726 Options:
727   -f    treat each NAME as a shell function
728   -v    treat each NAME as a shell variable
729
730 Without options, unset first tries to unset a variable, and if that fails,
731 tries to unset a function.
732
733 Some variables cannot be unset; also see `readonly'.
734
735 Exit Status:
736 Returns success unless an invalid option is given or a NAME is read-only.
737 $END
738
739 #define NEXT_VARIABLE() any_failed++; list = list->next; continue;
740
741 int
742 unset_builtin (list)
743   WORD_LIST *list;
744 {
745   int unset_function, unset_variable, unset_array, opt, any_failed;
746   char *name;
747
748   unset_function = unset_variable = unset_array = any_failed = 0;
749
750   reset_internal_getopt ();
751   while ((opt = internal_getopt (list, "fv")) != -1)
752     {
753       switch (opt)
754         {
755         case 'f':
756           unset_function = 1;
757           break;
758         case 'v':
759           unset_variable = 1;
760           break;
761         default:
762           builtin_usage ();
763           return (EX_USAGE);
764         }
765     }
766
767   list = loptend;
768
769   if (unset_function && unset_variable)
770     {
771       builtin_error (_("cannot simultaneously unset a function and a variable"));
772       return (EXECUTION_FAILURE);
773     }
774
775   while (list)
776     {
777       SHELL_VAR *var;
778       int tem;
779 #if defined (ARRAY_VARS)
780       char *t;
781 #endif
782
783       name = list->word->word;
784
785 #if defined (ARRAY_VARS)
786       unset_array = 0;
787       if (!unset_function && valid_array_reference (name))
788         {
789           t = strchr (name, '[');
790           *t++ = '\0';
791           unset_array++;
792         }
793 #endif
794
795       /* Bash allows functions with names which are not valid identifiers
796          to be created when not in posix mode, so check only when in posix
797          mode when unsetting a function. */
798       if (((unset_function && posixly_correct) || !unset_function) && legal_identifier (name) == 0)
799         {
800           sh_invalidid (name);
801           NEXT_VARIABLE ();
802         }
803
804       var = unset_function ? find_function (name) : find_variable (name);
805
806       if (var && !unset_function && non_unsettable_p (var))
807         {
808           builtin_error (_("%s: cannot unset"), name);
809           NEXT_VARIABLE ();
810         }
811
812       /* Posix.2 says that unsetting readonly variables is an error. */
813       if (var && readonly_p (var))
814         {
815           builtin_error (_("%s: cannot unset: readonly %s"),
816                          name, unset_function ? "function" : "variable");
817           NEXT_VARIABLE ();
818         }
819
820       /* Unless the -f option is supplied, the name refers to a variable. */
821 #if defined (ARRAY_VARS)
822       if (var && unset_array)
823         {
824           if (array_p (var) == 0 && assoc_p (var) == 0)
825             {
826               builtin_error (_("%s: not an array variable"), name);
827               NEXT_VARIABLE ();
828             }
829           else
830             {
831               tem = unbind_array_element (var, t);
832               if (tem == -1)
833                 any_failed++;
834             }
835         }
836       else
837 #endif /* ARRAY_VARS */
838       tem = unset_function ? unbind_func (name) : unbind_variable (name);
839
840       /* This is what Posix.2 draft 11+ says.  ``If neither -f nor -v
841          is specified, the name refers to a variable; if a variable by
842          that name does not exist, a function by that name, if any,
843          shall be unset.'' */
844       if (tem == -1 && !unset_function && !unset_variable)
845         tem = unbind_func (name);
846
847       /* SUSv3, POSIX.1-2001 say:  ``Unsetting a variable or function that
848          was not previously set shall not be considered an error.'' */
849
850       if (unset_function == 0)
851         stupidly_hack_special_variables (name);
852
853       list = list->next;
854     }
855
856   return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
857 }