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