1/* declare.c, created from declare.def. */ 2#line 23 "declare.def" 3 4#line 52 "declare.def" 5 6#line 58 "declare.def" 7 8#include <config.h> 9 10#if defined (HAVE_UNISTD_H) 11# ifdef _MINIX 12# include <sys/types.h> 13# endif 14# include <unistd.h> 15#endif 16 17#include <stdio.h> 18 19#include "../bashansi.h" 20#include "../bashintl.h" 21 22#include "../shell.h" 23#include "common.h" 24#include "builtext.h" 25#include "bashgetopt.h" 26 27extern int array_needs_making; 28extern int posixly_correct; 29 30static int declare_internal __P((register WORD_LIST *, int)); 31 32/* Declare or change variable attributes. */ 33int 34declare_builtin (list) 35 register WORD_LIST *list; 36{ 37 return (declare_internal (list, 0)); 38} 39 40#line 98 "declare.def" 41int 42local_builtin (list) 43 register WORD_LIST *list; 44{ 45 if (variable_context) 46 return (declare_internal (list, 1)); 47 else 48 { 49 builtin_error (_("can only be used in a function")); 50 return (EXECUTION_FAILURE); 51 } 52} 53 54#if defined (ARRAY_VARS) 55# define DECLARE_OPTS "+afiprtxF" 56#else 57# define DECLARE_OPTS "+fiprtxF" 58#endif 59 60/* The workhorse function. */ 61static int 62declare_internal (list, local_var) 63 register WORD_LIST *list; 64 int local_var; 65{ 66 int flags_on, flags_off, *flags, any_failed, assign_error, pflag, nodefs, opt; 67 char *t, *subscript_start; 68 SHELL_VAR *var; 69 FUNCTION_DEF *shell_fn; 70 71 flags_on = flags_off = any_failed = assign_error = pflag = nodefs = 0; 72 reset_internal_getopt (); 73 while ((opt = internal_getopt (list, DECLARE_OPTS)) != EOF) 74 { 75 flags = list_opttype == '+' ? &flags_off : &flags_on; 76 77 switch (opt) 78 { 79 case 'a': 80#if defined (ARRAY_VARS) 81 *flags |= att_array; 82#endif 83 break; 84 case 'p': 85 if (local_var == 0) 86 pflag++; 87 break; 88 case 'F': 89 nodefs++; 90 *flags |= att_function; 91 break; 92 case 'f': 93 *flags |= att_function; 94 break; 95 case 'i': 96 *flags |= att_integer; 97 break; 98 case 'r': 99 *flags |= att_readonly; 100 break; 101 case 't': 102 *flags |= att_trace; 103 break; 104 case 'x': 105 *flags |= att_exported; 106 array_needs_making = 1; 107 break; 108 default: 109 builtin_usage (); 110 return (EX_USAGE); 111 } 112 } 113 114 list = loptend; 115 116 /* If there are no more arguments left, then we just want to show 117 some variables. */ 118 if (list == 0) /* declare -[afFirtx] */ 119 { 120 /* Show local variables defined at this context level if this is 121 the `local' builtin. */ 122 if (local_var) 123 { 124 register SHELL_VAR **vlist; 125 register int i; 126 127 vlist = all_local_variables (); 128 129 if (vlist) 130 { 131 for (i = 0; vlist[i]; i++) 132 print_assignment (vlist[i]); 133 134 free (vlist); 135 } 136 } 137 else 138 { 139 if (flags_on == 0) 140 set_builtin ((WORD_LIST *)NULL); 141 else 142 set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs); 143 } 144 145 fflush (stdout); 146 return (EXECUTION_SUCCESS); 147 } 148 149 if (pflag) /* declare -p [-afFirtx] name [name...] */ 150 { 151 for (any_failed = 0; list; list = list->next) 152 { 153 pflag = show_name_attributes (list->word->word, nodefs); 154 if (pflag) 155 { 156 sh_notfound (list->word->word); 157 any_failed++; 158 } 159 } 160 return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS); 161 } 162 163#define NEXT_VARIABLE() free (name); list = list->next; continue 164 165 /* There are arguments left, so we are making variables. */ 166 while (list) /* declare [-afFirx] name [name ...] */ 167 { 168 char *value, *name; 169 int offset, aflags; 170#if defined (ARRAY_VARS) 171 int making_array_special, compound_array_assign, simple_array_assign; 172#endif 173 174 name = savestring (list->word->word); 175 offset = assignment (name, 0); 176 aflags = 0; 177 178 if (offset) /* declare [-afFirx] name=value */ 179 { 180 name[offset] = '\0'; 181 value = name + offset + 1; 182 if (name[offset - 1] == '+') 183 { 184 aflags |= ASS_APPEND; 185 name[offset - 1] = '\0'; 186 } 187 } 188 else 189 value = ""; 190 191#if defined (ARRAY_VARS) 192 compound_array_assign = simple_array_assign = 0; 193 subscript_start = (char *)NULL; 194 if (t = strchr (name, '[')) /* ] */ 195 { 196 subscript_start = t; 197 *t = '\0'; 198 making_array_special = 1; 199 } 200 else 201 making_array_special = 0; 202#endif 203 204 /* If we're in posix mode or not looking for a shell function (since 205 shell function names don't have to be valid identifiers when the 206 shell's not in posix mode), check whether or not the argument is a 207 valid, well-formed shell identifier. */ 208 if ((posixly_correct || (flags_on & att_function) == 0) && legal_identifier (name) == 0) 209 { 210 sh_invalidid (name); 211 assign_error++; 212 NEXT_VARIABLE (); 213 } 214 215 /* If VARIABLE_CONTEXT has a non-zero value, then we are executing 216 inside of a function. This means we should make local variables, 217 not global ones. */ 218 219 /* XXX - this has consequences when we're making a local copy of a 220 variable that was in the temporary environment. Watch out 221 for this. */ 222 if (variable_context && ((flags_on & att_function) == 0)) 223 { 224#if defined (ARRAY_VARS) 225 if ((flags_on & att_array) || making_array_special) 226 var = make_local_array_variable (name); 227 else 228#endif 229 var = make_local_variable (name); 230 if (var == 0) 231 { 232 any_failed++; 233 NEXT_VARIABLE (); 234 } 235 } 236 else 237 var = (SHELL_VAR *)NULL; 238 239 /* If we are declaring a function, then complain about it in some way. 240 We don't let people make functions by saying `typeset -f foo=bar'. */ 241 242 /* There should be a way, however, to let people look at a particular 243 function definition by saying `typeset -f foo'. */ 244 245 if (flags_on & att_function) 246 { 247 if (offset) /* declare -f [-rix] foo=bar */ 248 { 249 builtin_error (_("cannot use `-f' to make functions")); 250 free (name); 251 return (EXECUTION_FAILURE); 252 } 253 else /* declare -f [-rx] name [name...] */ 254 { 255 var = find_function (name); 256 257 if (var) 258 { 259 if (readonly_p (var) && (flags_off & att_readonly)) 260 { 261 builtin_error (_("%s: readonly function"), name); 262 any_failed++; 263 NEXT_VARIABLE (); 264 } 265 266 /* declare -[Ff] name [name...] */ 267 if (flags_on == att_function && flags_off == 0) 268 { 269#if defined (DEBUGGER) 270 if (nodefs && debugging_mode) 271 { 272 shell_fn = find_function_def (var->name); 273 if (shell_fn) 274 printf ("%s %d %s\n", var->name, shell_fn->line, shell_fn->source_file); 275 else 276 printf ("%s\n", var->name); 277 } 278 else 279#endif /* DEBUGGER */ 280 { 281 t = nodefs ? var->name 282 : named_function_string (name, function_cell (var), 1); 283 printf ("%s\n", t); 284 } 285 } 286 else /* declare -[fF] -[rx] name [name...] */ 287 { 288 VSETATTR (var, flags_on); 289 VUNSETATTR (var, flags_off); 290 } 291 } 292 else 293 any_failed++; 294 NEXT_VARIABLE (); 295 } 296 } 297 else /* declare -[airx] name [name...] */ 298 { 299 /* Non-null if we just created or fetched a local variable. */ 300 if (var == 0) 301 var = find_variable (name); 302 303 if (var == 0) 304 { 305#if defined (ARRAY_VARS) 306 if ((flags_on & att_array) || making_array_special) 307 var = make_new_array_variable (name); 308 else 309#endif 310 var = bind_variable (name, "", 0); 311 } 312 313 /* Cannot use declare +r to turn off readonly attribute. */ 314 if (readonly_p (var) && (flags_off & att_readonly)) 315 { 316 sh_readonly (name); 317 any_failed++; 318 NEXT_VARIABLE (); 319 } 320 321 /* Cannot use declare to assign value to readonly or noassign 322 variable. */ 323 if ((readonly_p (var) || noassign_p (var)) && offset) 324 { 325 if (readonly_p (var)) 326 sh_readonly (name); 327 assign_error++; 328 NEXT_VARIABLE (); 329 } 330 331#if defined (ARRAY_VARS) 332 if ((making_array_special || (flags_on & att_array) || array_p (var)) && offset) 333 { 334 int vlen; 335 vlen = STRLEN (value); 336#if 0 337 if (value[0] == '(' && strchr (value, ')')) 338#else 339 if (value[0] == '(' && value[vlen-1] == ')') 340#endif 341 compound_array_assign = 1; 342 else 343 simple_array_assign = 1; 344 } 345 346 /* Cannot use declare +a name to remove an array variable. */ 347 if ((flags_off & att_array) && array_p (var)) 348 { 349 builtin_error (_("%s: cannot destroy array variables in this way"), name); 350 any_failed++; 351 NEXT_VARIABLE (); 352 } 353 354 /* declare -a name makes name an array variable. */ 355 if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0) 356 var = convert_var_to_array (var); 357#endif /* ARRAY_VARS */ 358 359 VSETATTR (var, flags_on); 360 VUNSETATTR (var, flags_off); 361 362#if defined (ARRAY_VARS) 363 if (offset && compound_array_assign) 364 assign_array_var_from_string (var, value, aflags); 365 else if (simple_array_assign && subscript_start) 366 { 367 /* declare [-a] name[N]=value */ 368 *subscript_start = '['; /* ] */ 369 var = assign_array_element (name, value, 0); /* XXX - not aflags */ 370 *subscript_start = '\0'; 371 } 372 else if (simple_array_assign) 373 /* let bind_array_variable take care of this. */ 374 bind_array_variable (name, 0, value, aflags); 375 else 376#endif 377 /* bind_variable_value duplicates the essential internals of 378 bind_variable() */ 379 if (offset) 380 bind_variable_value (var, value, aflags); 381 382 /* If we found this variable in the temporary environment, as with 383 `var=value declare -x var', make sure it is treated identically 384 to `var=value export var'. Do the same for `declare -r' and 385 `readonly'. Preserve the attributes, except for att_tempvar. */ 386 /* XXX -- should this create a variable in the global scope, or 387 modify the local variable flags? ksh93 has it modify the 388 global scope. 389 Need to handle case like in set_var_attribute where a temporary 390 variable is in the same table as the function local vars. */ 391 if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var)) 392 { 393 SHELL_VAR *tv; 394 char *tvalue; 395 396 tv = find_tempenv_variable (var->name); 397 if (tv) 398 { 399 tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring (""); 400 tv = bind_variable (var->name, tvalue, 0); 401 tv->attributes |= var->attributes & ~att_tempvar; 402 if (tv->context > 0) 403 VSETATTR (tv, att_propagate); 404 free (tvalue); 405 } 406 VSETATTR (var, att_propagate); 407 } 408 } 409 410 stupidly_hack_special_variables (name); 411 412 NEXT_VARIABLE (); 413 } 414 415 return (assign_error ? EX_BADASSIGN 416 : ((any_failed == 0) ? EXECUTION_SUCCESS 417 : EXECUTION_FAILURE)); 418} 419