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