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