1/* shopt.c, created from shopt.def. */
2#line 23 "shopt.def"
3
4#line 36 "shopt.def"
5
6#include <config.h>
7
8#if defined (HAVE_UNISTD_H)
9#  ifdef _MINIX
10#    include <sys/types.h>
11#  endif
12#  include <unistd.h>
13#endif
14
15#include <stdio.h>
16
17#include "../bashintl.h"
18
19#include "../shell.h"
20#include "../flags.h"
21#include "common.h"
22#include "bashgetopt.h"
23
24#define UNSETOPT	0
25#define SETOPT		1
26
27#define OPTFMT		"%-15s\t%s\n"
28
29extern int allow_null_glob_expansion, fail_glob_expansion, glob_dot_filenames;
30extern int cdable_vars, mail_warning, source_uses_path;
31extern int no_exit_on_failed_exec, print_shift_error;
32extern int check_hashed_filenames, promptvars;
33extern int cdspelling, expand_aliases;
34extern int extended_quote;
35extern int check_window_size;
36extern int glob_ignore_case, match_ignore_case;
37extern int hup_on_exit;
38extern int xpg_echo;
39extern int gnu_error_format;
40
41#if defined (EXTENDED_GLOB)
42extern int extended_glob;
43#endif
44
45#if defined (HISTORY)
46extern int literal_history, command_oriented_history;
47extern int force_append_history;
48#endif
49
50#if defined (READLINE)
51extern int hist_verify, history_reediting, perform_hostname_completion;
52extern int no_empty_command_completion;
53extern int force_fignore;
54extern int enable_hostname_completion __P((int));
55#endif
56
57#if defined (PROGRAMMABLE_COMPLETION)
58extern int prog_completion_enabled;
59#endif
60
61#if defined (RESTRICTED_SHELL)
62extern char *shell_name;
63#endif
64
65#if defined (DEBUGGER)
66extern int debugging_mode;
67#endif
68
69static void shopt_error __P((char *));
70
71static int set_shellopts_after_change __P((int));
72
73static int set_compatibility_level __P((int));
74
75#if defined (RESTRICTED_SHELL)
76static int set_restricted_shell __P((int));
77#endif
78
79static int shopt_login_shell;
80static int shopt_compat31;
81
82typedef int shopt_set_func_t __P((int));
83
84static struct {
85  char *name;
86  int  *value;
87  shopt_set_func_t *set_func;
88} shopt_vars[] = {
89  { "cdable_vars", &cdable_vars, (shopt_set_func_t *)NULL },
90  { "cdspell", &cdspelling, (shopt_set_func_t *)NULL },
91  { "checkhash", &check_hashed_filenames, (shopt_set_func_t *)NULL },
92  { "checkwinsize", &check_window_size, (shopt_set_func_t *)NULL },
93#if defined (HISTORY)
94  { "cmdhist", &command_oriented_history, (shopt_set_func_t *)NULL },
95#endif
96  { "compat31", &shopt_compat31, set_compatibility_level },
97  { "dotglob", &glob_dot_filenames, (shopt_set_func_t *)NULL },
98  { "execfail", &no_exit_on_failed_exec, (shopt_set_func_t *)NULL },
99  { "expand_aliases", &expand_aliases, (shopt_set_func_t *)NULL },
100#if defined (DEBUGGER)
101  { "extdebug", &debugging_mode, (shopt_set_func_t *)NULL },
102#endif
103#if defined (EXTENDED_GLOB)
104  { "extglob", &extended_glob, (shopt_set_func_t *)NULL },
105#endif
106  { "extquote", &extended_quote, (shopt_set_func_t *)NULL },
107  { "failglob", &fail_glob_expansion, (shopt_set_func_t *)NULL },
108#if defined (READLINE)
109  { "force_fignore", &force_fignore, (shopt_set_func_t *)NULL },
110#endif
111  { "gnu_errfmt", &gnu_error_format, (shopt_set_func_t *)NULL },
112#if defined (HISTORY)
113  { "histappend", &force_append_history, (shopt_set_func_t *)NULL },
114#endif
115#if defined (READLINE)
116  { "histreedit", &history_reediting, (shopt_set_func_t *)NULL },
117  { "histverify", &hist_verify, (shopt_set_func_t *)NULL },
118  { "hostcomplete", &perform_hostname_completion, enable_hostname_completion },
119#endif
120  { "huponexit", &hup_on_exit, (shopt_set_func_t *)NULL },
121  { "interactive_comments", &interactive_comments, set_shellopts_after_change },
122#if defined (HISTORY)
123  { "lithist", &literal_history, (shopt_set_func_t *)NULL },
124#endif
125  { "login_shell", &shopt_login_shell, set_login_shell },
126  { "mailwarn", &mail_warning, (shopt_set_func_t *)NULL },
127#if defined (READLINE)
128  { "no_empty_cmd_completion", &no_empty_command_completion, (shopt_set_func_t *)NULL },
129#endif
130  { "nocaseglob", &glob_ignore_case, (shopt_set_func_t *)NULL },
131  { "nocasematch", &match_ignore_case, (shopt_set_func_t *)NULL },
132  { "nullglob",	&allow_null_glob_expansion, (shopt_set_func_t *)NULL },
133#if defined (PROGRAMMABLE_COMPLETION)
134  { "progcomp", &prog_completion_enabled, (shopt_set_func_t *)NULL },
135#endif
136  { "promptvars", &promptvars, (shopt_set_func_t *)NULL },
137#if defined (RESTRICTED_SHELL)
138  { "restricted_shell", &restricted_shell, set_restricted_shell },
139#endif
140  { "shift_verbose", &print_shift_error, (shopt_set_func_t *)NULL },
141  { "sourcepath", &source_uses_path, (shopt_set_func_t *)NULL },
142  { "xpg_echo", &xpg_echo, (shopt_set_func_t *)NULL },
143  { (char *)0, (int *)0, (shopt_set_func_t *)NULL }
144};
145
146static char *on = "on";
147static char *off = "off";
148
149static int find_shopt __P((char *));
150static int toggle_shopts __P((int, WORD_LIST *, int));
151static void print_shopt __P((char *, int, int));
152static int list_shopts __P((WORD_LIST *, int));
153static int list_some_shopts __P((int, int));
154static int list_shopt_o_options __P((WORD_LIST *, int));
155static int list_some_o_options __P((int, int));
156static int set_shopt_o_options __P((int, WORD_LIST *, int));
157
158#define SFLAG	0x01
159#define UFLAG	0x02
160#define QFLAG	0x04
161#define OFLAG	0x08
162#define PFLAG	0x10
163
164int
165shopt_builtin (list)
166     WORD_LIST *list;
167{
168  int opt, flags, rval;
169
170  flags = 0;
171  reset_internal_getopt ();
172  while ((opt = internal_getopt (list, "psuoq")) != -1)
173    {
174      switch (opt)
175	{
176	case 's':
177	  flags |= SFLAG;
178	  break;
179	case 'u':
180	  flags |= UFLAG;
181	  break;
182	case 'q':
183	  flags |= QFLAG;
184	  break;
185	case 'o':
186	  flags |= OFLAG;
187	  break;
188	case 'p':
189	  flags |= PFLAG;
190	  break;
191	default:
192	  builtin_usage ();
193	  return (EX_USAGE);
194	}
195    }
196  list = loptend;
197
198  if ((flags & (SFLAG|UFLAG)) == (SFLAG|UFLAG))
199    {
200      builtin_error (_("cannot set and unset shell options simultaneously"));
201      return (EXECUTION_FAILURE);
202    }
203
204  rval = EXECUTION_SUCCESS;
205  if ((flags & OFLAG) && ((flags & (SFLAG|UFLAG)) == 0))	/* shopt -o */
206    rval = list_shopt_o_options (list, flags);
207  else if (list && (flags & OFLAG))		/* shopt -so args */
208    rval = set_shopt_o_options ((flags & SFLAG) ? FLAG_ON : FLAG_OFF, list, flags & QFLAG);
209  else if (flags & OFLAG)	/* shopt -so */
210    rval = list_some_o_options ((flags & SFLAG) ? 1 : 0, flags);
211  else if (list && (flags & (SFLAG|UFLAG)))	/* shopt -su args */
212    rval = toggle_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, list, flags & QFLAG);
213  else if ((flags & (SFLAG|UFLAG)) == 0)	/* shopt [args] */
214    rval = list_shopts (list, flags);
215  else						/* shopt -su */
216    rval = list_some_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, flags);
217  return (rval);
218}
219
220/* Reset the options managed by `shopt' to the values they would have at
221   shell startup. */
222void
223reset_shopt_options ()
224{
225  allow_null_glob_expansion = glob_dot_filenames = 0;
226  cdable_vars = mail_warning = 0;
227  no_exit_on_failed_exec = print_shift_error = 0;
228  check_hashed_filenames = cdspelling = expand_aliases = check_window_size = 0;
229
230  source_uses_path = promptvars = 1;
231
232#if defined (EXTENDED_GLOB)
233  extended_glob = 0;
234#endif
235
236#if defined (HISTORY)
237  literal_history = force_append_history = 0;
238  command_oriented_history = 1;
239#endif
240
241#if defined (READLINE)
242  hist_verify = history_reediting = 0;
243  perform_hostname_completion = 1;
244#endif
245
246  shopt_login_shell = login_shell;
247}
248
249static int
250find_shopt (name)
251     char *name;
252{
253  int i;
254
255  for (i = 0; shopt_vars[i].name; i++)
256    if (STREQ (name, shopt_vars[i].name))
257      return i;
258  return -1;
259}
260
261static void
262shopt_error (s)
263     char *s;
264{
265  builtin_error (_("%s: invalid shell option name"), s);
266}
267
268static int
269toggle_shopts (mode, list, quiet)
270     int mode;
271     WORD_LIST *list;
272     int quiet;
273{
274  WORD_LIST *l;
275  int ind, rval;
276
277  for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
278    {
279      ind = find_shopt (l->word->word);
280      if (ind < 0)
281	{
282	  shopt_error (l->word->word);
283	  rval = EXECUTION_FAILURE;
284	}
285      else
286	{
287	  *shopt_vars[ind].value = mode;	/* 1 for set, 0 for unset */
288	  if (shopt_vars[ind].set_func)
289	    (*shopt_vars[ind].set_func) (mode);
290	}
291    }
292  return (rval);
293}
294
295static void
296print_shopt (name, val, flags)
297     char *name;
298     int val, flags;
299{
300  if (flags & PFLAG)
301    printf ("shopt %s %s\n", val ? "-s" : "-u", name);
302  else
303    printf (OPTFMT, name, val ? on : off);
304}
305
306/* List the values of all or any of the `shopt' options.  Returns 0 if
307   all were listed or all variables queried were on; 1 otherwise. */
308static int
309list_shopts (list, flags)
310     WORD_LIST *list;
311     int flags;
312{
313  WORD_LIST *l;
314  int i, val, rval;
315
316  if (list == 0)
317    {
318      for (i = 0; shopt_vars[i].name; i++)
319	{
320	  val = *shopt_vars[i].value;
321	  if ((flags & QFLAG) == 0)
322	    print_shopt (shopt_vars[i].name, val, flags);
323	}
324      return (EXECUTION_SUCCESS);
325    }
326
327  for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
328    {
329      i = find_shopt (l->word->word);
330      if (i < 0)
331	{
332	  shopt_error (l->word->word);
333	  rval = EXECUTION_FAILURE;
334	  continue;
335	}
336      val = *shopt_vars[i].value;
337      if (val == 0)
338	rval = EXECUTION_FAILURE;
339      if ((flags & QFLAG) == 0)
340	print_shopt (l->word->word, val, flags);
341    }
342
343  return (rval);
344}
345
346static int
347list_some_shopts (mode, flags)
348     int mode, flags;
349{
350  int val, i;
351
352  for (i = 0; shopt_vars[i].name; i++)
353    {
354      val = *shopt_vars[i].value;
355      if (((flags & QFLAG) == 0) && mode == val)
356	print_shopt (shopt_vars[i].name, val, flags);
357    }
358  return (EXECUTION_SUCCESS);
359}
360
361static int
362list_shopt_o_options (list, flags)
363     WORD_LIST *list;
364     int flags;
365{
366  WORD_LIST *l;
367  int val, rval;
368
369  if (list == 0)
370    {
371      if ((flags & QFLAG) == 0)
372	list_minus_o_opts (-1, (flags & PFLAG));
373      return (EXECUTION_SUCCESS);
374    }
375
376  for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
377    {
378      val = minus_o_option_value (l->word->word);
379      if (val == -1)
380	{
381	  sh_invalidoptname (l->word->word);
382	  rval = EXECUTION_FAILURE;
383	  continue;
384	}
385      if (val == 0)
386	rval = EXECUTION_FAILURE;
387      if ((flags & QFLAG) == 0)
388	{
389	  if (flags & PFLAG)
390	    printf ("set %co %s\n", val ? '-' : '+', l->word->word);
391	  else
392	    printf (OPTFMT, l->word->word, val ? on : off);
393	}
394    }
395  return (rval);
396}
397
398static int
399list_some_o_options (mode, flags)
400     int mode, flags;
401{
402  if ((flags & QFLAG) == 0)
403    list_minus_o_opts (mode, (flags & PFLAG));
404  return (EXECUTION_SUCCESS);
405}
406
407static int
408set_shopt_o_options (mode, list, quiet)
409     int mode;
410     WORD_LIST *list;
411     int quiet;
412{
413  WORD_LIST *l;
414  int rval;
415
416  for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
417    {
418      if (set_minus_o_option (mode, l->word->word) == EXECUTION_FAILURE)
419	rval = EXECUTION_FAILURE;
420    }
421  set_shellopts ();
422  return rval;
423}
424
425/* If we set or unset interactive_comments with shopt, make sure the
426   change is reflected in $SHELLOPTS. */
427static int
428set_shellopts_after_change (mode)
429     int mode;
430{
431  set_shellopts ();
432  return (0);
433}
434
435static int
436set_compatibility_level (mode)
437     int mode;
438{
439  /* Need to change logic here as we add more compatibility levels */
440  if (shopt_compat31)
441    shell_compatibility_level = 31;
442  else
443    shell_compatibility_level = 32;
444  return 0;
445}
446
447#if defined (RESTRICTED_SHELL)
448/* Don't allow the value of restricted_shell to be modified. */
449
450static int
451set_restricted_shell (mode)
452     int mode;
453{
454  static int save_restricted = -1;
455
456  if (save_restricted == -1)
457    save_restricted = shell_is_restricted (shell_name);
458
459  restricted_shell = save_restricted;
460  return (0);
461}
462#endif /* RESTRICTED_SHELL */
463
464/* Not static so shell.c can call it to initialize shopt_login_shell */
465int
466set_login_shell (mode)
467     int mode;
468{
469  shopt_login_shell = login_shell != 0;
470  return (0);
471}
472
473char **
474get_shopt_options ()
475{
476  char **ret;
477  int n, i;
478
479  n = sizeof (shopt_vars) / sizeof (shopt_vars[0]);
480  ret = strvec_create (n + 1);
481  for (i = 0; shopt_vars[i].name; i++)
482    ret[i] = savestring (shopt_vars[i].name);
483  ret[i] = (char *)NULL;
484  return ret;
485}
486
487/*
488 * External interface for other parts of the shell.  NAME is a string option;
489 * MODE is 0 if we want to unset an option; 1 if we want to set an option.
490 * REUSABLE is 1 if we want to print output in a form that may be reused.
491 */
492int
493shopt_setopt (name, mode)
494     char *name;
495     int mode;
496{
497  WORD_LIST *wl;
498  int r;
499
500  wl = add_string_to_list (name, (WORD_LIST *)NULL);
501  r = toggle_shopts (mode, wl, 0);
502  dispose_words (wl);
503  return r;
504}
505
506int
507shopt_listopt (name, reusable)
508     char *name;
509     int reusable;
510{
511  int i;
512
513  if (name == 0)
514    return (list_shopts ((WORD_LIST *)NULL, reusable ? PFLAG : 0));
515
516  i = find_shopt (name);
517  if (i < 0)
518    {
519      shopt_error (name);
520      return (EXECUTION_FAILURE);
521    }
522
523  print_shopt (name, *shopt_vars[i].value, reusable ? PFLAG : 0);
524  return (EXECUTION_SUCCESS);
525}
526