1/* set.c, created from set.def. */
2#line 23 "set.def"
3
4#include <config.h>
5
6#if defined (HAVE_UNISTD_H)
7#  ifdef _MINIX
8#    include <sys/types.h>
9#  endif
10#  include <unistd.h>
11#endif
12
13#include <stdio.h>
14
15#include "../bashansi.h"
16#include "../bashintl.h"
17
18#include "../shell.h"
19#include "../flags.h"
20#include "common.h"
21#include "bashgetopt.h"
22
23#if defined (READLINE)
24#  include "../input.h"
25#  include "../bashline.h"
26#  include <readline/readline.h>
27#endif
28
29#if defined (HISTORY)
30#  include "../bashhist.h"
31#endif
32
33extern int posixly_correct, ignoreeof, eof_encountered_limit;
34#if defined (HISTORY)
35extern int dont_save_function_defs;
36#endif
37#if defined (READLINE)
38extern int no_line_editing;
39#endif /* READLINE */
40
41#line 145 "set.def"
42
43typedef int setopt_set_func_t __P((int, char *));
44typedef int setopt_get_func_t __P((char *));
45
46static void print_minus_o_option __P((char *, int, int));
47static void print_all_shell_variables __P((void));
48
49static int set_ignoreeof __P((int, char *));
50static int set_posix_mode __P((int, char *));
51
52#if defined (READLINE)
53static int set_edit_mode __P((int, char *));
54static int get_edit_mode __P((char *));
55#endif
56
57#if defined (HISTORY)
58static int bash_set_history __P((int, char *));
59#endif
60
61static char *on = "on";
62static char *off = "off";
63
64/* A struct used to match long options for set -o to the corresponding
65   option letter or internal variable.  The functions can be called to
66   dynamically generate values. */
67struct {
68  char *name;
69  int letter;
70  int *variable;
71  setopt_set_func_t *set_func;
72  setopt_get_func_t *get_func;
73} o_options[] = {
74  { "allexport",  'a', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
75#if defined (BRACE_EXPANSION)
76  { "braceexpand",'B', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
77#endif
78#if defined (READLINE)
79  { "emacs",     '\0', (int *)NULL, set_edit_mode, get_edit_mode },
80#endif
81  { "errexit",	  'e', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
82  { "errtrace",	  'E', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
83  { "functrace",  'T', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
84  { "hashall",    'h', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
85#if defined (BANG_HISTORY)
86  { "histexpand", 'H', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
87#endif /* BANG_HISTORY */
88#if defined (HISTORY)
89  { "history",   '\0', &enable_history_list, bash_set_history, (setopt_get_func_t *)NULL },
90#endif
91  { "ignoreeof", '\0', &ignoreeof, set_ignoreeof, (setopt_get_func_t *)NULL },
92  { "interactive-comments", '\0', &interactive_comments, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
93  { "keyword",    'k', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
94  { "monitor",	  'm', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
95  { "noclobber",  'C', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
96  { "noexec",	  'n', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
97  { "noglob",	  'f', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
98#if defined (HISTORY)
99  { "nolog",     '\0', &dont_save_function_defs, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
100#endif
101#if defined (JOB_CONTROL)
102  { "notify",	  'b', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
103#endif /* JOB_CONTROL */
104  { "nounset",	  'u', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
105  { "onecmd",	  't', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
106  { "physical",   'P', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
107  { "pipefail",  '\0', &pipefail_opt, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
108  { "posix",     '\0', &posixly_correct, set_posix_mode, (setopt_get_func_t *)NULL },
109  { "privileged", 'p', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
110  { "verbose",	  'v', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
111#if defined (READLINE)
112  { "vi",        '\0', (int *)NULL, set_edit_mode, get_edit_mode },
113#endif
114  { "xtrace",	  'x', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
115  {(char *)NULL, 0 , (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
116};
117
118#define N_O_OPTIONS	(sizeof (o_options) / sizeof (o_options[0]))
119
120#define GET_BINARY_O_OPTION_VALUE(i, name) \
121  ((o_options[i].get_func) ? (*o_options[i].get_func) (name) \
122			   : (*o_options[i].variable))
123
124#define SET_BINARY_O_OPTION_VALUE(i, onoff, name) \
125  ((o_options[i].set_func) ? (*o_options[i].set_func) (onoff, name) \
126			   : (*o_options[i].variable = (onoff == FLAG_ON)))
127
128int
129minus_o_option_value (name)
130     char *name;
131{
132  register int	i;
133  int *on_or_off;
134
135  for (i = 0; o_options[i].name; i++)
136    {
137      if (STREQ (name, o_options[i].name))
138	{
139	  if (o_options[i].letter)
140	    {
141	      on_or_off = find_flag (o_options[i].letter);
142	      return ((on_or_off == FLAG_UNKNOWN) ? -1 : *on_or_off);
143	    }
144	  else
145	    return (GET_BINARY_O_OPTION_VALUE (i, name));
146	}
147    }
148
149  return (-1);
150}
151
152#define MINUS_O_FORMAT "%-15s\t%s\n"
153
154static void
155print_minus_o_option (name, value, pflag)
156     char *name;
157     int value, pflag;
158{
159  if (pflag == 0)
160    printf (MINUS_O_FORMAT, name, value ? on : off);
161  else
162    printf ("set %co %s\n", value ? '-' : '+', name);
163}
164
165void
166list_minus_o_opts (mode, reusable)
167     int mode, reusable;
168{
169  register int	i;
170  int *on_or_off, value;
171
172  for (i = 0; o_options[i].name; i++)
173    {
174      if (o_options[i].letter)
175	{
176	  value = 0;
177	  on_or_off = find_flag (o_options[i].letter);
178	  if (on_or_off == FLAG_UNKNOWN)
179	    on_or_off = &value;
180	  if (mode == -1 || mode == *on_or_off)
181	    print_minus_o_option (o_options[i].name, *on_or_off, reusable);
182	}
183      else
184	{
185	  value = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
186	  if (mode == -1 || mode == value)
187	    print_minus_o_option (o_options[i].name, value, reusable);
188	}
189    }
190}
191
192char **
193get_minus_o_opts ()
194{
195  char **ret;
196  int i;
197
198  ret = strvec_create (N_O_OPTIONS + 1);
199  for (i = 0; o_options[i].name; i++)
200    ret[i] = o_options[i].name;
201  ret[i] = (char *)NULL;
202  return ret;
203}
204
205static int
206set_ignoreeof (on_or_off, option_name)
207     int on_or_off;
208     char *option_name;
209{
210  ignoreeof = on_or_off == FLAG_ON;
211  unbind_variable ("ignoreeof");
212  if (ignoreeof)
213    bind_variable ("IGNOREEOF", "10", 0);
214  else
215    unbind_variable ("IGNOREEOF");
216  sv_ignoreeof ("IGNOREEOF");
217  return 0;
218}
219
220static int
221set_posix_mode (on_or_off, option_name)
222     int on_or_off;
223     char *option_name;
224{
225  posixly_correct = on_or_off == FLAG_ON;
226  if (posixly_correct == 0)
227    unbind_variable ("POSIXLY_CORRECT");
228  else
229    bind_variable ("POSIXLY_CORRECT", "y", 0);
230  sv_strict_posix ("POSIXLY_CORRECT");
231  return (0);
232}
233
234#if defined (READLINE)
235/* Magic.  This code `knows' how readline handles rl_editing_mode. */
236static int
237set_edit_mode (on_or_off, option_name)
238     int on_or_off;
239     char *option_name;
240{
241  int isemacs;
242
243  if (on_or_off == FLAG_ON)
244    {
245      rl_variable_bind ("editing-mode", option_name);
246
247      if (interactive)
248	with_input_from_stdin ();
249      no_line_editing = 0;
250    }
251  else
252    {
253      isemacs = rl_editing_mode == 1;
254      if ((isemacs && *option_name == 'e') || (!isemacs && *option_name == 'v'))
255	{
256	  if (interactive)
257	    with_input_from_stream (stdin, "stdin");
258	  no_line_editing = 1;
259	}
260    }
261  return 1-no_line_editing;
262}
263
264static int
265get_edit_mode (name)
266     char *name;
267{
268  return (*name == 'e' ? no_line_editing == 0 && rl_editing_mode == 1
269		       : no_line_editing == 0 && rl_editing_mode == 0);
270}
271#endif /* READLINE */
272
273#if defined (HISTORY)
274static int
275bash_set_history (on_or_off, option_name)
276     int on_or_off;
277     char *option_name;
278{
279  if (on_or_off == FLAG_ON)
280    {
281      enable_history_list = 1;
282      bash_history_enable ();
283      if (history_lines_this_session == 0)
284	load_history ();
285    }
286  else
287    {
288      enable_history_list = 0;
289      bash_history_disable ();
290    }
291  return (1 - enable_history_list);
292}
293#endif
294
295int
296set_minus_o_option (on_or_off, option_name)
297     int on_or_off;
298     char *option_name;
299{
300  register int i;
301
302  for (i = 0; o_options[i].name; i++)
303    {
304      if (STREQ (option_name, o_options[i].name))
305	{
306	  if (o_options[i].letter == 0)
307	    {
308	      SET_BINARY_O_OPTION_VALUE (i, on_or_off, option_name);
309	      return (EXECUTION_SUCCESS);
310	    }
311	  else
312	    {
313	      if (change_flag (o_options[i].letter, on_or_off) == FLAG_ERROR)
314		{
315		  sh_invalidoptname (option_name);
316		  return (EXECUTION_FAILURE);
317		}
318	      else
319		return (EXECUTION_SUCCESS);
320	    }
321
322	}
323    }
324
325  sh_invalidoptname (option_name);
326  return (EXECUTION_FAILURE);
327}
328
329static void
330print_all_shell_variables ()
331{
332  SHELL_VAR **vars;
333
334  vars = all_shell_variables ();
335  if (vars)
336    {
337      print_var_list (vars);
338      free (vars);
339    }
340
341  /* POSIX.2 does not allow function names and definitions to be output when
342     `set' is invoked without options (PASC Interp #202). */
343  if (posixly_correct == 0)
344    {
345      vars = all_shell_functions ();
346      if (vars)
347	{
348	  print_func_list (vars);
349	  free (vars);
350	}
351    }
352}
353
354void
355set_shellopts ()
356{
357  char *value;
358  char tflag[N_O_OPTIONS];
359  int vsize, i, vptr, *ip, exported;
360  SHELL_VAR *v;
361
362  for (vsize = i = 0; o_options[i].name; i++)
363    {
364      tflag[i] = 0;
365      if (o_options[i].letter)
366	{
367	  ip = find_flag (o_options[i].letter);
368	  if (ip && *ip)
369	    {
370	      vsize += strlen (o_options[i].name) + 1;
371	      tflag[i] = 1;
372	    }
373	}
374      else if (GET_BINARY_O_OPTION_VALUE (i, o_options[i].name))
375	{
376	  vsize += strlen (o_options[i].name) + 1;
377	  tflag[i] = 1;
378	}
379    }
380
381  value = (char *)xmalloc (vsize + 1);
382
383  for (i = vptr = 0; o_options[i].name; i++)
384    {
385      if (tflag[i])
386	{
387	  strcpy (value + vptr, o_options[i].name);
388	  vptr += strlen (o_options[i].name);
389	  value[vptr++] = ':';
390	}
391    }
392
393  if (vptr)
394    vptr--;			/* cut off trailing colon */
395  value[vptr] = '\0';
396
397  v = find_variable ("SHELLOPTS");
398
399  /* Turn off the read-only attribute so we can bind the new value, and
400     note whether or not the variable was exported. */
401  if (v)
402    {
403      VUNSETATTR (v, att_readonly);
404      exported = exported_p (v);
405    }
406  else
407    exported = 0;
408
409  v = bind_variable ("SHELLOPTS", value, 0);
410
411  /* Turn the read-only attribute back on, and turn off the export attribute
412     if it was set implicitly by mark_modified_vars and SHELLOPTS was not
413     exported before we bound the new value. */
414  VSETATTR (v, att_readonly);
415  if (mark_modified_vars && exported == 0 && exported_p (v))
416    VUNSETATTR (v, att_exported);
417
418  free (value);
419}
420
421void
422parse_shellopts (value)
423     char *value;
424{
425  char *vname;
426  int vptr;
427
428  vptr = 0;
429  while (vname = extract_colon_unit (value, &vptr))
430    {
431      set_minus_o_option (FLAG_ON, vname);
432      free (vname);
433    }
434}
435
436void
437initialize_shell_options (no_shellopts)
438     int no_shellopts;
439{
440  char *temp;
441  SHELL_VAR *var;
442
443  if (no_shellopts == 0)
444    {
445      var = find_variable ("SHELLOPTS");
446      /* set up any shell options we may have inherited. */
447      if (var && imported_p (var))
448	{
449	  temp = (array_p (var)) ? (char *)NULL : savestring (value_cell (var));
450	  if (temp)
451	    {
452	      parse_shellopts (temp);
453	      free (temp);
454	    }
455	}
456    }
457
458  /* Set up the $SHELLOPTS variable. */
459  set_shellopts ();
460}
461
462/* Reset the values of the -o options that are not also shell flags.  This is
463   called from execute_cmd.c:initialize_subshell() when setting up a subshell
464   to run an executable shell script without a leading `#!'. */
465void
466reset_shell_options ()
467{
468#if defined (HISTORY)
469  remember_on_history = enable_history_list = 1;
470#endif
471  ignoreeof = 0;
472}
473
474/* Set some flags from the word values in the input list.  If LIST is empty,
475   then print out the values of the variables instead.  If LIST contains
476   non-flags, then set $1 - $9 to the successive words of LIST. */
477int
478set_builtin (list)
479     WORD_LIST *list;
480{
481  int on_or_off, flag_name, force_assignment, opts_changed;
482  register char *arg;
483  char s[3];
484
485  if (list == 0)
486    {
487      print_all_shell_variables ();
488      return (EXECUTION_SUCCESS);
489    }
490
491  /* Check validity of flag arguments. */
492  reset_internal_getopt ();
493  while ((flag_name = internal_getopt (list, optflags)) != -1)
494    {
495      switch (flag_name)
496	{
497	  case '?':
498	    builtin_usage ();
499	    return (list_optopt == '?' ? EXECUTION_SUCCESS : EX_USAGE);
500	  default:
501	    break;
502	}
503    }
504
505  /* Do the set command.  While the list consists of words starting with
506     '-' or '+' treat them as flags, otherwise, start assigning them to
507     $1 ... $n. */
508  for (force_assignment = opts_changed = 0; list; )
509    {
510      arg = list->word->word;
511
512      /* If the argument is `--' or `-' then signal the end of the list
513	 and remember the remaining arguments. */
514      if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2])))
515	{
516	  list = list->next;
517
518	  /* `set --' unsets the positional parameters. */
519	  if (arg[1] == '-')
520	    force_assignment = 1;
521
522	  /* Until told differently, the old shell behaviour of
523	     `set - [arg ...]' being equivalent to `set +xv [arg ...]'
524	     stands.  Posix.2 says the behaviour is marked as obsolescent. */
525	  else
526	    {
527	      change_flag ('x', '+');
528	      change_flag ('v', '+');
529	      opts_changed = 1;
530	    }
531
532	  break;
533	}
534
535      if ((on_or_off = *arg) && (on_or_off == '-' || on_or_off == '+'))
536	{
537	  while (flag_name = *++arg)
538	    {
539	      if (flag_name == '?')
540		{
541		  builtin_usage ();
542		  return (EXECUTION_SUCCESS);
543		}
544	      else if (flag_name == 'o') /* -+o option-name */
545		{
546		  char *option_name;
547		  WORD_LIST *opt;
548
549		  opt = list->next;
550
551		  if (opt == 0)
552		    {
553		      list_minus_o_opts (-1, (on_or_off == '+'));
554		      continue;
555		    }
556
557		  option_name = opt->word->word;
558
559		  if (option_name == 0 || *option_name == '\0' ||
560		      *option_name == '-' || *option_name == '+')
561		    {
562		      list_minus_o_opts (-1, (on_or_off == '+'));
563		      continue;
564		    }
565		  list = list->next; /* Skip over option name. */
566
567		  opts_changed = 1;
568		  if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS)
569		    {
570		      set_shellopts ();
571		      return (EXECUTION_FAILURE);
572		    }
573		}
574	      else if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
575		{
576		  s[0] = on_or_off;
577		  s[1] = flag_name;
578		  s[2] = '\0';
579		  sh_invalidopt (s);
580		  builtin_usage ();
581		  set_shellopts ();
582		  return (EXECUTION_FAILURE);
583		}
584	      opts_changed = 1;
585	    }
586	}
587      else
588	{
589	  break;
590	}
591      list = list->next;
592    }
593
594  /* Assigning $1 ... $n */
595  if (list || force_assignment)
596    remember_args (list, 1);
597  /* Set up new value of $SHELLOPTS */
598  if (opts_changed)
599    set_shellopts ();
600  return (EXECUTION_SUCCESS);
601}
602
603#line 715 "set.def"
604
605#define NEXT_VARIABLE()	any_failed++; list = list->next; continue;
606
607int
608unset_builtin (list)
609  WORD_LIST *list;
610{
611  int unset_function, unset_variable, unset_array, opt, any_failed;
612  char *name;
613
614  unset_function = unset_variable = unset_array = any_failed = 0;
615
616  reset_internal_getopt ();
617  while ((opt = internal_getopt (list, "fv")) != -1)
618    {
619      switch (opt)
620	{
621	case 'f':
622	  unset_function = 1;
623	  break;
624	case 'v':
625	  unset_variable = 1;
626	  break;
627	default:
628	  builtin_usage ();
629	  return (EX_USAGE);
630	}
631    }
632
633  list = loptend;
634
635  if (unset_function && unset_variable)
636    {
637      builtin_error (_("cannot simultaneously unset a function and a variable"));
638      return (EXECUTION_FAILURE);
639    }
640
641  while (list)
642    {
643      SHELL_VAR *var;
644      int tem;
645#if defined (ARRAY_VARS)
646      char *t;
647#endif
648
649      name = list->word->word;
650
651#if defined (ARRAY_VARS)
652      unset_array = 0;
653      if (!unset_function && valid_array_reference (name))
654	{
655	  t = strchr (name, '[');
656	  *t++ = '\0';
657	  unset_array++;
658	}
659#endif
660
661      /* Bash allows functions with names which are not valid identifiers
662	 to be created when not in posix mode, so check only when in posix
663	 mode when unsetting a function. */
664      if (((unset_function && posixly_correct) || !unset_function) && legal_identifier (name) == 0)
665	{
666	  sh_invalidid (name);
667	  NEXT_VARIABLE ();
668	}
669
670      var = unset_function ? find_function (name) : find_variable (name);
671
672      if (var && !unset_function && non_unsettable_p (var))
673	{
674	  builtin_error (_("%s: cannot unset"), name);
675	  NEXT_VARIABLE ();
676	}
677
678      /* Posix.2 says that unsetting readonly variables is an error. */
679      if (var && readonly_p (var))
680	{
681	  builtin_error (_("%s: cannot unset: readonly %s"),
682			 name, unset_function ? "function" : "variable");
683	  NEXT_VARIABLE ();
684	}
685
686      /* Unless the -f option is supplied, the name refers to a variable. */
687#if defined (ARRAY_VARS)
688      if (var && unset_array)
689	{
690	  if (array_p (var) == 0)
691	    {
692	      builtin_error (_("%s: not an array variable"), name);
693	      NEXT_VARIABLE ();
694	    }
695	  else
696	    {
697	      tem = unbind_array_element (var, t);
698	      if (tem == -1)
699		any_failed++;
700	    }
701	}
702      else
703#endif /* ARRAY_VARS */
704      tem = unset_function ? unbind_func (name) : unbind_variable (name);
705
706      /* This is what Posix.2 draft 11+ says.  ``If neither -f nor -v
707	 is specified, the name refers to a variable; if a variable by
708	 that name does not exist, a function by that name, if any,
709	 shall be unset.'' */
710      if (tem == -1 && !unset_function && !unset_variable)
711	tem = unbind_func (name);
712
713      /* SUSv3, POSIX.1-2001 say:  ``Unsetting a variable or function that
714	 was not previously set shall not be considered an error.'' */
715
716      if (unset_function == 0)
717	stupidly_hack_special_variables (name);
718
719      list = list->next;
720    }
721
722  return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
723}
724