Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 1 | This file is declare.def, from which is created declare.c. |
| 2 | It implements the builtins "declare" and "local" in Bash. |
| 3 | |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 4 | Copyright (C) 1987-2012 Free Software Foundation, Inc. |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 5 | |
| 6 | This file is part of GNU Bash, the Bourne Again SHell. |
| 7 | |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 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. |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 12 | |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 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. |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 17 | |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 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/>. |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 20 | |
| 21 | $PRODUCES declare.c |
| 22 | |
| 23 | $BUILTIN declare |
| 24 | $FUNCTION declare_builtin |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 25 | $SHORT_DOC declare [-aAfFgilnrtux] [-p] [name[=value] ...] |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 26 | Set variable values and attributes. |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 27 | |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 28 | Declare variables and give them attributes. If no NAMEs are given, |
| 29 | display the attributes and values of all variables. |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 30 | |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 31 | Options: |
| 32 | -f restrict action or display to function names and definitions |
| 33 | -F restrict display to function names only (plus line number and |
| 34 | source file when debugging) |
Chet Ramey | 495aee4 | 2011-11-22 19:11:26 -0500 | [diff] [blame] | 35 | -g create global variables when used in a shell function; otherwise |
| 36 | ignored |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 37 | -p display the attributes and value of each NAME |
| 38 | |
| 39 | Options which set attributes: |
| 40 | -a to make NAMEs indexed arrays (if supported) |
| 41 | -A to make NAMEs associative arrays (if supported) |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 42 | -i to make NAMEs have the `integer' attribute |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 43 | -l to convert NAMEs to lower case on assignment |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 44 | -n make NAME a reference to the variable named by its value |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 45 | -r to make NAMEs readonly |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 46 | -t to make NAMEs have the `trace' attribute |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 47 | -u to convert NAMEs to upper case on assignment |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 48 | -x to make NAMEs export |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 49 | |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 50 | Using `+' instead of `-' turns off the given attribute. |
| 51 | |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 52 | Variables with the integer attribute have arithmetic evaluation (see |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 53 | the `let' command) performed when the variable is assigned a value. |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 54 | |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 55 | When used in a function, `declare' makes NAMEs local, as with the `local' |
Chet Ramey | 495aee4 | 2011-11-22 19:11:26 -0500 | [diff] [blame] | 56 | command. The `-g' option suppresses this behavior. |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 57 | |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 58 | Exit Status: |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 59 | Returns success unless an invalid option is supplied or a variable |
| 60 | assignment error occurs. |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 61 | $END |
| 62 | |
| 63 | $BUILTIN typeset |
| 64 | $FUNCTION declare_builtin |
Chet Ramey | 495aee4 | 2011-11-22 19:11:26 -0500 | [diff] [blame] | 65 | $SHORT_DOC typeset [-aAfFgilrtux] [-p] name[=value] ... |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 66 | Set variable values and attributes. |
| 67 | |
| 68 | Obsolete. See `help declare'. |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 69 | $END |
| 70 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 71 | #include <config.h> |
| 72 | |
| 73 | #if defined (HAVE_UNISTD_H) |
Jari Aalto | cce855b | 1998-04-17 19:52:44 +0000 | [diff] [blame] | 74 | # ifdef _MINIX |
| 75 | # include <sys/types.h> |
| 76 | # endif |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 77 | # include <unistd.h> |
| 78 | #endif |
| 79 | |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 80 | #include <stdio.h> |
| 81 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 82 | #include "../bashansi.h" |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 83 | #include "../bashintl.h" |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 84 | |
| 85 | #include "../shell.h" |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 86 | #include "common.h" |
| 87 | #include "builtext.h" |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 88 | #include "bashgetopt.h" |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 89 | |
Jari Aalto | f73dda0 | 2001-11-13 17:56:06 +0000 | [diff] [blame] | 90 | extern int array_needs_making; |
Jari Aalto | 0628567 | 2006-10-10 14:15:34 +0000 | [diff] [blame] | 91 | extern int posixly_correct; |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 92 | |
Jari Aalto | f73dda0 | 2001-11-13 17:56:06 +0000 | [diff] [blame] | 93 | static int declare_internal __P((register WORD_LIST *, int)); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 94 | |
| 95 | /* Declare or change variable attributes. */ |
| 96 | int |
| 97 | declare_builtin (list) |
| 98 | register WORD_LIST *list; |
| 99 | { |
| 100 | return (declare_internal (list, 0)); |
| 101 | } |
| 102 | |
| 103 | $BUILTIN local |
| 104 | $FUNCTION local_builtin |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 105 | $SHORT_DOC local [option] name[=value] ... |
| 106 | Define local variables. |
| 107 | |
| 108 | Create a local variable called NAME, and give it VALUE. OPTION can |
| 109 | be any option accepted by `declare'. |
| 110 | |
| 111 | Local variables can only be used within a function; they are visible |
| 112 | only to the function where they are defined and its children. |
| 113 | |
| 114 | Exit Status: |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 115 | Returns success unless an invalid option is supplied, a variable |
| 116 | assignment error occurs, or the shell is not executing a function. |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 117 | $END |
| 118 | int |
| 119 | local_builtin (list) |
| 120 | register WORD_LIST *list; |
| 121 | { |
| 122 | if (variable_context) |
| 123 | return (declare_internal (list, 1)); |
| 124 | else |
| 125 | { |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 126 | builtin_error (_("can only be used in a function")); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 127 | return (EXECUTION_FAILURE); |
| 128 | } |
| 129 | } |
| 130 | |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 131 | #if defined (ARRAY_VARS) |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 132 | # define DECLARE_OPTS "+acfgilnprtuxAF" |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 133 | #else |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 134 | # define DECLARE_OPTS "+cfgilnprtuxF" |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 135 | #endif |
| 136 | |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 137 | /* The workhorse function. */ |
| 138 | static int |
| 139 | declare_internal (list, local_var) |
| 140 | register WORD_LIST *list; |
| 141 | int local_var; |
| 142 | { |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 143 | int flags_on, flags_off, *flags; |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 144 | int any_failed, assign_error, pflag, nodefs, opt, mkglobal, onref, offref; |
Jari Aalto | f73dda0 | 2001-11-13 17:56:06 +0000 | [diff] [blame] | 145 | char *t, *subscript_start; |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 146 | SHELL_VAR *var, *refvar, *v; |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 147 | FUNCTION_DEF *shell_fn; |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 148 | |
Chet Ramey | 495aee4 | 2011-11-22 19:11:26 -0500 | [diff] [blame] | 149 | flags_on = flags_off = any_failed = assign_error = pflag = nodefs = mkglobal = 0; |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 150 | refvar = (SHELL_VAR *)NULL; |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 151 | reset_internal_getopt (); |
| 152 | while ((opt = internal_getopt (list, DECLARE_OPTS)) != EOF) |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 153 | { |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 154 | flags = list_opttype == '+' ? &flags_off : &flags_on; |
| 155 | |
| 156 | switch (opt) |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 157 | { |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 158 | case 'a': |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 159 | #if defined (ARRAY_VARS) |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 160 | *flags |= att_array; |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 161 | break; |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 162 | #else |
| 163 | builtin_usage (); |
| 164 | return (EX_USAGE); |
| 165 | #endif |
| 166 | case 'A': |
| 167 | #if defined (ARRAY_VARS) |
| 168 | *flags |= att_assoc; |
| 169 | break; |
| 170 | #else |
| 171 | builtin_usage (); |
| 172 | return (EX_USAGE); |
| 173 | #endif |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 174 | case 'p': |
| 175 | if (local_var == 0) |
| 176 | pflag++; |
| 177 | break; |
| 178 | case 'F': |
| 179 | nodefs++; |
| 180 | *flags |= att_function; |
| 181 | break; |
| 182 | case 'f': |
| 183 | *flags |= att_function; |
| 184 | break; |
Chet Ramey | 495aee4 | 2011-11-22 19:11:26 -0500 | [diff] [blame] | 185 | case 'g': |
| 186 | if (flags == &flags_on) |
| 187 | mkglobal = 1; |
| 188 | break; |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 189 | case 'i': |
| 190 | *flags |= att_integer; |
| 191 | break; |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 192 | case 'n': |
| 193 | *flags |= att_nameref; |
| 194 | break; |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 195 | case 'r': |
| 196 | *flags |= att_readonly; |
| 197 | break; |
| 198 | case 't': |
| 199 | *flags |= att_trace; |
| 200 | break; |
| 201 | case 'x': |
| 202 | *flags |= att_exported; |
| 203 | array_needs_making = 1; |
| 204 | break; |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 205 | #if defined (CASEMOD_ATTRS) |
| 206 | # if defined (CASEMOD_CAPCASE) |
| 207 | case 'c': |
| 208 | *flags |= att_capcase; |
| 209 | if (flags == &flags_on) |
| 210 | flags_off |= att_uppercase|att_lowercase; |
| 211 | break; |
| 212 | # endif |
| 213 | case 'l': |
| 214 | *flags |= att_lowercase; |
| 215 | if (flags == &flags_on) |
| 216 | flags_off |= att_capcase|att_uppercase; |
| 217 | break; |
| 218 | case 'u': |
| 219 | *flags |= att_uppercase; |
| 220 | if (flags == &flags_on) |
| 221 | flags_off |= att_capcase|att_lowercase; |
| 222 | break; |
| 223 | #endif /* CASEMOD_ATTRS */ |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 224 | default: |
| 225 | builtin_usage (); |
| 226 | return (EX_USAGE); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 227 | } |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 228 | } |
| 229 | |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 230 | list = loptend; |
| 231 | |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 232 | /* If there are no more arguments left, then we just want to show |
| 233 | some variables. */ |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 234 | if (list == 0) /* declare -[aAfFirtx] */ |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 235 | { |
| 236 | /* Show local variables defined at this context level if this is |
| 237 | the `local' builtin. */ |
| 238 | if (local_var) |
| 239 | { |
| 240 | register SHELL_VAR **vlist; |
| 241 | register int i; |
| 242 | |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 243 | vlist = all_local_variables (); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 244 | |
| 245 | if (vlist) |
| 246 | { |
| 247 | for (i = 0; vlist[i]; i++) |
| 248 | print_assignment (vlist[i]); |
| 249 | |
| 250 | free (vlist); |
| 251 | } |
| 252 | } |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 253 | else if (pflag && (flags_on == 0 || flags_on == att_function)) |
| 254 | show_all_var_attributes (flags_on == 0, nodefs); |
| 255 | else if (flags_on == 0) |
| 256 | return (set_builtin ((WORD_LIST *)NULL)); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 257 | else |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 258 | set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 259 | |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 260 | return (sh_chkwrite (EXECUTION_SUCCESS)); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 261 | } |
| 262 | |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 263 | if (pflag) /* declare -p [-aAfFirtx] name [name...] */ |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 264 | { |
| 265 | for (any_failed = 0; list; list = list->next) |
| 266 | { |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 267 | if (flags_on & att_function) |
| 268 | pflag = show_func_attributes (list->word->word, nodefs); |
| 269 | else |
| 270 | pflag = show_name_attributes (list->word->word, nodefs); |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 271 | if (pflag) |
| 272 | { |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 273 | sh_notfound (list->word->word); |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 274 | any_failed++; |
| 275 | } |
| 276 | } |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 277 | return (sh_chkwrite (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS)); |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 278 | } |
| 279 | |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 280 | #define NEXT_VARIABLE() free (name); list = list->next; continue |
| 281 | |
| 282 | /* There are arguments left, so we are making variables. */ |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 283 | while (list) /* declare [-aAfFirx] name [name ...] */ |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 284 | { |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 285 | char *value, *name; |
Jari Aalto | 95732b4 | 2005-12-07 14:08:12 +0000 | [diff] [blame] | 286 | int offset, aflags; |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 287 | #if defined (ARRAY_VARS) |
Jari Aalto | f73dda0 | 2001-11-13 17:56:06 +0000 | [diff] [blame] | 288 | int making_array_special, compound_array_assign, simple_array_assign; |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 289 | #endif |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 290 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 291 | name = savestring (list->word->word); |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 292 | offset = assignment (name, 0); |
Jari Aalto | 95732b4 | 2005-12-07 14:08:12 +0000 | [diff] [blame] | 293 | aflags = 0; |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 294 | |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 295 | if (offset) /* declare [-aAfFirx] name=value */ |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 296 | { |
| 297 | name[offset] = '\0'; |
| 298 | value = name + offset + 1; |
Jari Aalto | 95732b4 | 2005-12-07 14:08:12 +0000 | [diff] [blame] | 299 | if (name[offset - 1] == '+') |
| 300 | { |
| 301 | aflags |= ASS_APPEND; |
| 302 | name[offset - 1] = '\0'; |
| 303 | } |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 304 | } |
| 305 | else |
| 306 | value = ""; |
| 307 | |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 308 | /* Do some lexical error checking on the LHS and RHS of the assignment |
| 309 | that is specific to nameref variables. */ |
| 310 | if (flags_on & att_nameref) |
| 311 | { |
| 312 | #if defined (ARRAY_VARIABLES) |
| 313 | if (valid_array_reference (name)) |
| 314 | { |
| 315 | builtin_error (_("%s: reference variable cannot be an array"), name); |
| 316 | assign_error++; |
| 317 | NEXT_VARIABLE (); |
| 318 | } |
| 319 | else |
| 320 | #endif |
| 321 | /* disallow self references at global scope */ |
| 322 | if (STREQ (name, value) && variable_context == 0) |
| 323 | { |
| 324 | builtin_error (_("%s: nameref variable self references not allowed"), name); |
| 325 | assign_error++; |
| 326 | NEXT_VARIABLE (); |
| 327 | } |
| 328 | } |
| 329 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 330 | #if defined (ARRAY_VARS) |
Jari Aalto | f73dda0 | 2001-11-13 17:56:06 +0000 | [diff] [blame] | 331 | compound_array_assign = simple_array_assign = 0; |
| 332 | subscript_start = (char *)NULL; |
| 333 | if (t = strchr (name, '[')) /* ] */ |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 334 | { |
Chet Ramey | 89a9286 | 2011-11-21 20:49:12 -0500 | [diff] [blame] | 335 | /* If offset != 0 we have already validated any array reference */ |
| 336 | if (offset == 0 && valid_array_reference (name) == 0) |
| 337 | { |
| 338 | sh_invalidid (name); |
| 339 | assign_error++; |
| 340 | NEXT_VARIABLE (); |
| 341 | } |
Jari Aalto | f73dda0 | 2001-11-13 17:56:06 +0000 | [diff] [blame] | 342 | subscript_start = t; |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 343 | *t = '\0'; |
| 344 | making_array_special = 1; |
| 345 | } |
| 346 | else |
| 347 | making_array_special = 0; |
| 348 | #endif |
Jari Aalto | 0628567 | 2006-10-10 14:15:34 +0000 | [diff] [blame] | 349 | |
| 350 | /* If we're in posix mode or not looking for a shell function (since |
| 351 | shell function names don't have to be valid identifiers when the |
| 352 | shell's not in posix mode), check whether or not the argument is a |
| 353 | valid, well-formed shell identifier. */ |
| 354 | if ((posixly_correct || (flags_on & att_function) == 0) && legal_identifier (name) == 0) |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 355 | { |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 356 | sh_invalidid (name); |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 357 | assign_error++; |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 358 | NEXT_VARIABLE (); |
| 359 | } |
| 360 | |
| 361 | /* If VARIABLE_CONTEXT has a non-zero value, then we are executing |
| 362 | inside of a function. This means we should make local variables, |
| 363 | not global ones. */ |
| 364 | |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 365 | /* XXX - this has consequences when we're making a local copy of a |
| 366 | variable that was in the temporary environment. Watch out |
| 367 | for this. */ |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 368 | refvar = (SHELL_VAR *)NULL; |
Chet Ramey | 495aee4 | 2011-11-22 19:11:26 -0500 | [diff] [blame] | 369 | if (variable_context && mkglobal == 0 && ((flags_on & att_function) == 0)) |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 370 | { |
| 371 | #if defined (ARRAY_VARS) |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 372 | if (flags_on & att_assoc) |
| 373 | var = make_local_assoc_variable (name); |
| 374 | else if ((flags_on & att_array) || making_array_special) |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 375 | var = make_local_array_variable (name, making_array_special); |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 376 | else |
| 377 | #endif |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 378 | var = make_local_variable (name); /* sets att_invisible for new vars */ |
Jari Aalto | bb70624 | 2000-03-17 21:46:59 +0000 | [diff] [blame] | 379 | if (var == 0) |
| 380 | { |
| 381 | any_failed++; |
| 382 | NEXT_VARIABLE (); |
| 383 | } |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 384 | } |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 385 | else |
| 386 | var = (SHELL_VAR *)NULL; |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 387 | |
| 388 | /* If we are declaring a function, then complain about it in some way. |
| 389 | We don't let people make functions by saying `typeset -f foo=bar'. */ |
| 390 | |
| 391 | /* There should be a way, however, to let people look at a particular |
| 392 | function definition by saying `typeset -f foo'. */ |
| 393 | |
| 394 | if (flags_on & att_function) |
| 395 | { |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 396 | if (offset) /* declare -f [-rix] foo=bar */ |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 397 | { |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 398 | builtin_error (_("cannot use `-f' to make functions")); |
Jari Aalto | d166f04 | 1997-06-05 14:59:13 +0000 | [diff] [blame] | 399 | free (name); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 400 | return (EXECUTION_FAILURE); |
| 401 | } |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 402 | else /* declare -f [-rx] name [name...] */ |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 403 | { |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 404 | var = find_function (name); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 405 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 406 | if (var) |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 407 | { |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 408 | if (readonly_p (var) && (flags_off & att_readonly)) |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 409 | { |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 410 | builtin_error (_("%s: readonly function"), name); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 411 | any_failed++; |
| 412 | NEXT_VARIABLE (); |
| 413 | } |
| 414 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 415 | /* declare -[Ff] name [name...] */ |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 416 | if (flags_on == att_function && flags_off == 0) |
| 417 | { |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 418 | #if defined (DEBUGGER) |
| 419 | if (nodefs && debugging_mode) |
| 420 | { |
| 421 | shell_fn = find_function_def (var->name); |
| 422 | if (shell_fn) |
| 423 | printf ("%s %d %s\n", var->name, shell_fn->line, shell_fn->source_file); |
| 424 | else |
| 425 | printf ("%s\n", var->name); |
| 426 | } |
| 427 | else |
| 428 | #endif /* DEBUGGER */ |
| 429 | { |
| 430 | t = nodefs ? var->name |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 431 | : named_function_string (name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL); |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 432 | printf ("%s\n", t); |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 433 | any_failed = sh_chkwrite (any_failed); |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 434 | } |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 435 | } |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 436 | else /* declare -[fF] -[rx] name [name...] */ |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 437 | { |
Jari Aalto | bb70624 | 2000-03-17 21:46:59 +0000 | [diff] [blame] | 438 | VSETATTR (var, flags_on); |
| 439 | VUNSETATTR (var, flags_off); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 440 | } |
| 441 | } |
| 442 | else |
| 443 | any_failed++; |
| 444 | NEXT_VARIABLE (); |
| 445 | } |
| 446 | } |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 447 | else /* declare -[aAirx] name [name...] */ |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 448 | { |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 449 | /* Non-null if we just created or fetched a local variable. */ |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 450 | /* Here's what ksh93 seems to do. If we are modifying an existing |
| 451 | nameref variable, we don't follow the nameref chain past the last |
| 452 | nameref, and we set the nameref variable's value so future |
| 453 | references to that variable will return the value of the variable |
| 454 | we're assigning right now. */ |
| 455 | if (var == 0 && (flags_on & att_nameref)) |
| 456 | { |
| 457 | /* See if we are trying to modify an existing nameref variable */ |
| 458 | var = mkglobal ? find_global_variable_last_nameref (name) : find_variable_last_nameref (name); |
| 459 | if (var && nameref_p (var) == 0) |
| 460 | var = 0; |
| 461 | } |
| 462 | /* However, if we're turning off the nameref attribute on an existing |
| 463 | nameref variable, we first follow the nameref chain to the end, |
| 464 | modify the value of the variable this nameref variable references, |
| 465 | *CHANGING ITS VALUE AS A SIDE EFFECT* then turn off the nameref |
| 466 | flag *LEAVING THE NAMEREF VARIABLE'S VALUE UNCHANGED* */ |
| 467 | else if (var == 0 && (flags_off & att_nameref)) |
| 468 | { |
| 469 | /* See if we are trying to modify an existing nameref variable */ |
| 470 | refvar = mkglobal ? find_global_variable_last_nameref (name) : find_variable_last_nameref (name); |
| 471 | if (refvar && nameref_p (refvar) == 0) |
| 472 | refvar = 0; |
| 473 | if (refvar) |
| 474 | var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar)); |
| 475 | } |
| 476 | |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 477 | if (var == 0) |
Chet Ramey | 495aee4 | 2011-11-22 19:11:26 -0500 | [diff] [blame] | 478 | var = mkglobal ? find_global_variable (name) : find_variable (name); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 479 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 480 | if (var == 0) |
| 481 | { |
| 482 | #if defined (ARRAY_VARS) |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 483 | if (flags_on & att_assoc) |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 484 | { |
| 485 | var = make_new_assoc_variable (name); |
| 486 | if (offset == 0) |
| 487 | VSETATTR (var, att_invisible); |
| 488 | } |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 489 | else if ((flags_on & att_array) || making_array_special) |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 490 | { |
| 491 | var = make_new_array_variable (name); |
| 492 | if (offset == 0) |
| 493 | VSETATTR (var, att_invisible); |
| 494 | } |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 495 | else |
| 496 | #endif |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 497 | |
| 498 | if (offset) |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 499 | var = mkglobal ? bind_global_variable (name, "", 0) : bind_variable (name, "", 0); |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 500 | else |
| 501 | { |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 502 | var = mkglobal ? bind_global_variable (name, (char *)NULL, 0) : bind_variable (name, (char *)NULL, 0); |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 503 | VSETATTR (var, att_invisible); |
| 504 | } |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 505 | } |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 506 | /* Can't take an existing array variable and make it a nameref */ |
| 507 | else if ((array_p (var) || assoc_p (var)) && (flags_on & att_nameref)) |
| 508 | { |
| 509 | builtin_error (_("%s: reference variable cannot be an array"), name); |
| 510 | assign_error++; |
| 511 | NEXT_VARIABLE (); |
| 512 | } |
| 513 | else if (flags_on & att_nameref) |
| 514 | { |
| 515 | /* ksh93 compat: turning on nameref attribute turns off -ilu */ |
| 516 | VUNSETATTR (var, att_integer|att_uppercase|att_lowercase|att_capcase); |
| 517 | } |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 518 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 519 | /* Cannot use declare +r to turn off readonly attribute. */ |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 520 | if (readonly_p (var) && (flags_off & att_readonly)) |
| 521 | { |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 522 | sh_readonly (name); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 523 | any_failed++; |
| 524 | NEXT_VARIABLE (); |
| 525 | } |
| 526 | |
Jari Aalto | 28ef6c3 | 2001-04-06 19:14:31 +0000 | [diff] [blame] | 527 | /* Cannot use declare to assign value to readonly or noassign |
| 528 | variable. */ |
| 529 | if ((readonly_p (var) || noassign_p (var)) && offset) |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 530 | { |
Jari Aalto | 28ef6c3 | 2001-04-06 19:14:31 +0000 | [diff] [blame] | 531 | if (readonly_p (var)) |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 532 | sh_readonly (name); |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 533 | assign_error++; |
| 534 | NEXT_VARIABLE (); |
| 535 | } |
| 536 | |
| 537 | #if defined (ARRAY_VARS) |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 538 | if ((making_array_special || (flags_on & (att_array|att_assoc)) || array_p (var) || assoc_p (var)) && offset) |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 539 | { |
Jari Aalto | 95732b4 | 2005-12-07 14:08:12 +0000 | [diff] [blame] | 540 | int vlen; |
| 541 | vlen = STRLEN (value); |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 542 | |
Jari Aalto | 95732b4 | 2005-12-07 14:08:12 +0000 | [diff] [blame] | 543 | if (value[0] == '(' && value[vlen-1] == ')') |
Jari Aalto | f73dda0 | 2001-11-13 17:56:06 +0000 | [diff] [blame] | 544 | compound_array_assign = 1; |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 545 | else |
Jari Aalto | f73dda0 | 2001-11-13 17:56:06 +0000 | [diff] [blame] | 546 | simple_array_assign = 1; |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 547 | } |
| 548 | |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 549 | /* Cannot use declare +a name or declare +A name to remove an |
| 550 | array variable. */ |
| 551 | if (((flags_off & att_array) && array_p (var)) || ((flags_off & att_assoc) && assoc_p (var))) |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 552 | { |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 553 | builtin_error (_("%s: cannot destroy array variables in this way"), name); |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 554 | any_failed++; |
| 555 | NEXT_VARIABLE (); |
| 556 | } |
| 557 | |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 558 | if ((flags_on & att_array) && assoc_p (var)) |
| 559 | { |
| 560 | builtin_error (_("%s: cannot convert associative to indexed array"), name); |
| 561 | any_failed++; |
| 562 | NEXT_VARIABLE (); |
| 563 | } |
| 564 | if ((flags_on & att_assoc) && array_p (var)) |
| 565 | { |
| 566 | builtin_error (_("%s: cannot convert indexed to associative array"), name); |
| 567 | any_failed++; |
| 568 | NEXT_VARIABLE (); |
| 569 | } |
| 570 | |
| 571 | /* declare -A name[[n]] makes name an associative array variable. */ |
| 572 | if (flags_on & att_assoc) |
| 573 | { |
| 574 | if (assoc_p (var) == 0) |
| 575 | var = convert_var_to_assoc (var); |
| 576 | } |
| 577 | /* declare -a name[[n]] or declare name[n] makes name an indexed |
| 578 | array variable. */ |
Chet Ramey | 89a9286 | 2011-11-21 20:49:12 -0500 | [diff] [blame] | 579 | else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0 && assoc_p (var) == 0) |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 580 | var = convert_var_to_array (var); |
| 581 | #endif /* ARRAY_VARS */ |
| 582 | |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 583 | /* XXX - we note that we are turning on nameref attribute and defer |
| 584 | setting it until the assignment has been made so we don't do an |
| 585 | inadvertent nameref lookup. Might have to do the same thing for |
| 586 | flags_off&att_nameref. */ |
| 587 | /* XXX - ksh93 makes it an error to set a readonly nameref variable |
| 588 | using a single typeset command. */ |
| 589 | onref = (flags_on & att_nameref); |
| 590 | flags_on &= ~att_nameref; |
| 591 | #if defined (ARRAY_VARS) |
| 592 | if (array_p (var) || assoc_p (var) |
| 593 | || (offset && compound_array_assign) |
| 594 | || simple_array_assign) |
| 595 | onref = 0; /* array variables may not be namerefs */ |
| 596 | #endif |
| 597 | |
| 598 | /* ksh93 seems to do this */ |
| 599 | offref = (flags_off & att_nameref); |
| 600 | flags_off &= ~att_nameref; |
| 601 | |
Jari Aalto | bb70624 | 2000-03-17 21:46:59 +0000 | [diff] [blame] | 602 | VSETATTR (var, flags_on); |
| 603 | VUNSETATTR (var, flags_off); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 604 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 605 | #if defined (ARRAY_VARS) |
Jari Aalto | f73dda0 | 2001-11-13 17:56:06 +0000 | [diff] [blame] | 606 | if (offset && compound_array_assign) |
Jari Aalto | 95732b4 | 2005-12-07 14:08:12 +0000 | [diff] [blame] | 607 | assign_array_var_from_string (var, value, aflags); |
Jari Aalto | f73dda0 | 2001-11-13 17:56:06 +0000 | [diff] [blame] | 608 | else if (simple_array_assign && subscript_start) |
| 609 | { |
Chet Ramey | 0001803 | 2011-11-21 20:51:19 -0500 | [diff] [blame] | 610 | /* declare [-aA] name[N]=value */ |
Jari Aalto | f73dda0 | 2001-11-13 17:56:06 +0000 | [diff] [blame] | 611 | *subscript_start = '['; /* ] */ |
Jari Aalto | 95732b4 | 2005-12-07 14:08:12 +0000 | [diff] [blame] | 612 | var = assign_array_element (name, value, 0); /* XXX - not aflags */ |
Jari Aalto | f73dda0 | 2001-11-13 17:56:06 +0000 | [diff] [blame] | 613 | *subscript_start = '\0'; |
Chet Ramey | 307dbc7 | 2011-11-22 20:03:23 -0500 | [diff] [blame] | 614 | if (var == 0) /* some kind of assignment error */ |
| 615 | { |
| 616 | assign_error++; |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 617 | flags_on |= onref; |
| 618 | flags_off |= offref; |
Chet Ramey | 307dbc7 | 2011-11-22 20:03:23 -0500 | [diff] [blame] | 619 | NEXT_VARIABLE (); |
| 620 | } |
Jari Aalto | f73dda0 | 2001-11-13 17:56:06 +0000 | [diff] [blame] | 621 | } |
| 622 | else if (simple_array_assign) |
Chet Ramey | 0001803 | 2011-11-21 20:51:19 -0500 | [diff] [blame] | 623 | { |
| 624 | /* let bind_{array,assoc}_variable take care of this. */ |
| 625 | if (assoc_p (var)) |
Chet Ramey | 30d188c | 2011-11-21 20:57:16 -0500 | [diff] [blame] | 626 | bind_assoc_variable (var, name, savestring ("0"), value, aflags); |
Chet Ramey | 0001803 | 2011-11-21 20:51:19 -0500 | [diff] [blame] | 627 | else |
| 628 | bind_array_variable (name, 0, value, aflags); |
| 629 | } |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 630 | else |
| 631 | #endif |
Jari Aalto | bb70624 | 2000-03-17 21:46:59 +0000 | [diff] [blame] | 632 | /* bind_variable_value duplicates the essential internals of |
| 633 | bind_variable() */ |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 634 | if (offset) |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 635 | { |
| 636 | if (onref) |
| 637 | aflags |= ASS_NAMEREF; |
| 638 | v = bind_variable_value (var, value, aflags); |
| 639 | if (v == 0 && onref) |
| 640 | { |
| 641 | sh_invalidid (value); |
| 642 | assign_error++; |
| 643 | /* XXX - unset this variable? or leave it as normal var? */ |
| 644 | delete_var (var->name, mkglobal ? global_variables : shell_variables); |
| 645 | NEXT_VARIABLE (); |
| 646 | } |
| 647 | } |
Jari Aalto | cce855b | 1998-04-17 19:52:44 +0000 | [diff] [blame] | 648 | |
| 649 | /* If we found this variable in the temporary environment, as with |
| 650 | `var=value declare -x var', make sure it is treated identically |
| 651 | to `var=value export var'. Do the same for `declare -r' and |
| 652 | `readonly'. Preserve the attributes, except for att_tempvar. */ |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 653 | /* XXX -- should this create a variable in the global scope, or |
| 654 | modify the local variable flags? ksh93 has it modify the |
| 655 | global scope. |
| 656 | Need to handle case like in set_var_attribute where a temporary |
| 657 | variable is in the same table as the function local vars. */ |
Jari Aalto | cce855b | 1998-04-17 19:52:44 +0000 | [diff] [blame] | 658 | if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var)) |
| 659 | { |
| 660 | SHELL_VAR *tv; |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 661 | char *tvalue; |
| 662 | |
| 663 | tv = find_tempenv_variable (var->name); |
| 664 | if (tv) |
| 665 | { |
| 666 | tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring (""); |
Jari Aalto | 95732b4 | 2005-12-07 14:08:12 +0000 | [diff] [blame] | 667 | tv = bind_variable (var->name, tvalue, 0); |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 668 | tv->attributes |= var->attributes & ~att_tempvar; |
| 669 | if (tv->context > 0) |
| 670 | VSETATTR (tv, att_propagate); |
| 671 | free (tvalue); |
| 672 | } |
| 673 | VSETATTR (var, att_propagate); |
Jari Aalto | cce855b | 1998-04-17 19:52:44 +0000 | [diff] [blame] | 674 | } |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 675 | } |
| 676 | |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 677 | /* Turn on nameref attribute we deferred above. */ |
| 678 | /* XXX - should we turn on the noassign attribute for consistency with |
| 679 | ksh93 when we turn on the nameref attribute? */ |
| 680 | VSETATTR (var, onref); |
| 681 | flags_on |= onref; |
| 682 | VUNSETATTR (var, offref); |
| 683 | flags_off |= offref; |
| 684 | /* Yuck. ksh93 compatibility */ |
| 685 | if (refvar) |
| 686 | VUNSETATTR (refvar, flags_off); |
| 687 | |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 688 | stupidly_hack_special_variables (name); |
| 689 | |
| 690 | NEXT_VARIABLE (); |
| 691 | } |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 692 | |
| 693 | return (assign_error ? EX_BADASSIGN |
| 694 | : ((any_failed == 0) ? EXECUTION_SUCCESS |
| 695 | : EXECUTION_FAILURE)); |
Jari Aalto | 726f638 | 1996-08-26 18:22:31 +0000 | [diff] [blame] | 696 | } |