1This file is declare.def, from which is created declare.c. 2It implements the builtins "declare" and "local" in Bash. 3 4Copyright (C) 1987-2020 Free Software Foundation, Inc. 5 6This file is part of GNU Bash, the Bourne Again SHell. 7 8Bash is free software: you can redistribute it and/or modify 9it under the terms of the GNU General Public License as published by 10the Free Software Foundation, either version 3 of the License, or 11(at your option) any later version. 12 13Bash is distributed in the hope that it will be useful, 14but WITHOUT ANY WARRANTY; without even the implied warranty of 15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16GNU General Public License for more details. 17 18You should have received a copy of the GNU General Public License 19along with Bash. If not, see <http://www.gnu.org/licenses/>. 20 21$PRODUCES declare.c 22 23$BUILTIN declare 24$FUNCTION declare_builtin 25$SHORT_DOC declare [-aAfFgiIlnrtux] [-p] [name[=value] ...] 26Set variable values and attributes. 27 28Declare variables and give them attributes. If no NAMEs are given, 29display the attributes and values of all variables. 30 31Options: 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) 35 -g create global variables when used in a shell function; otherwise 36 ignored 37 -I if creating a local variable, inherit the attributes and value 38 of a variable with the same name at a previous scope 39 -p display the attributes and value of each NAME 40 41Options which set attributes: 42 -a to make NAMEs indexed arrays (if supported) 43 -A to make NAMEs associative arrays (if supported) 44 -i to make NAMEs have the `integer' attribute 45 -l to convert the value of each NAME to lower case on assignment 46 -n make NAME a reference to the variable named by its value 47 -r to make NAMEs readonly 48 -t to make NAMEs have the `trace' attribute 49 -u to convert the value of each NAME to upper case on assignment 50 -x to make NAMEs export 51 52Using `+' instead of `-' turns off the given attribute. 53 54Variables with the integer attribute have arithmetic evaluation (see 55the `let' command) performed when the variable is assigned a value. 56 57When used in a function, `declare' makes NAMEs local, as with the `local' 58command. The `-g' option suppresses this behavior. 59 60Exit Status: 61Returns success unless an invalid option is supplied or a variable 62assignment error occurs. 63$END 64 65$BUILTIN typeset 66$FUNCTION declare_builtin 67$SHORT_DOC typeset [-aAfFgiIlnrtux] [-p] name[=value] ... 68Set variable values and attributes. 69 70A synonym for `declare'. See `help declare'. 71$END 72 73#include <config.h> 74 75#if defined (HAVE_UNISTD_H) 76# ifdef _MINIX 77# include <sys/types.h> 78# endif 79# include <unistd.h> 80#endif 81 82#include <stdio.h> 83 84#include "../bashansi.h" 85#include "../bashintl.h" 86 87#include "../shell.h" 88#include "../flags.h" 89#include "common.h" 90#include "builtext.h" 91#include "bashgetopt.h" 92 93static SHELL_VAR *declare_find_variable PARAMS((const char *, int, int)); 94static int declare_internal PARAMS((register WORD_LIST *, int)); 95 96/* Declare or change variable attributes. */ 97int 98declare_builtin (list) 99 register WORD_LIST *list; 100{ 101 return (declare_internal (list, 0)); 102} 103 104$BUILTIN local 105$FUNCTION local_builtin 106$SHORT_DOC local [option] name[=value] ... 107Define local variables. 108 109Create a local variable called NAME, and give it VALUE. OPTION can 110be any option accepted by `declare'. 111 112Local variables can only be used within a function; they are visible 113only to the function where they are defined and its children. 114 115Exit Status: 116Returns success unless an invalid option is supplied, a variable 117assignment error occurs, or the shell is not executing a function. 118$END 119int 120local_builtin (list) 121 register WORD_LIST *list; 122{ 123 /* Catch a straight `local --help' before checking function context */ 124 if (list && list->word && STREQ (list->word->word, "--help")) 125 { 126 builtin_help (); 127 return (EX_USAGE); 128 } 129 130 if (variable_context) 131 return (declare_internal (list, 1)); 132 else 133 { 134 builtin_error (_("can only be used in a function")); 135 return (EXECUTION_FAILURE); 136 } 137} 138 139#if defined (ARRAY_VARS) 140# define DECLARE_OPTS "+acfgilnprtuxAFGI" 141#else 142# define DECLARE_OPTS "+cfgilnprtuxFGI" 143#endif 144 145static SHELL_VAR * 146declare_find_variable (name, mkglobal, chklocal) 147 const char *name; 148 int mkglobal, chklocal; 149{ 150 SHELL_VAR *var; 151 152 if (mkglobal == 0) 153 return (find_variable (name)); 154 else if (chklocal) 155 { 156 var = find_variable (name); 157 if (var && local_p (var) && var->context == variable_context) 158 return var; 159 return (find_global_variable (name)); 160 } 161 else 162 return (find_global_variable (name)); 163} 164 165/* The workhorse function. */ 166static int 167declare_internal (list, local_var) 168 register WORD_LIST *list; 169 int local_var; 170{ 171 int flags_on, flags_off, *flags; 172 int any_failed, assign_error, pflag, nodefs, opt, onref, offref; 173 int mkglobal, chklocal, inherit_flag; 174 char *t, *subscript_start; 175 SHELL_VAR *var, *refvar, *v; 176 FUNCTION_DEF *shell_fn; 177 178 flags_on = flags_off = any_failed = assign_error = pflag = nodefs = 0; 179 mkglobal = chklocal = inherit_flag = 0; 180 refvar = (SHELL_VAR *)NULL; 181 reset_internal_getopt (); 182 while ((opt = internal_getopt (list, DECLARE_OPTS)) != -1) 183 { 184 flags = list_opttype == '+' ? &flags_off : &flags_on; 185 186 /* If you add options here, see whether or not they need to be added to 187 the loop in subst.c:shell_expand_word_list() */ 188 switch (opt) 189 { 190 case 'a': 191#if defined (ARRAY_VARS) 192 *flags |= att_array; 193 break; 194#else 195 builtin_usage (); 196 return (EX_USAGE); 197#endif 198 case 'A': 199#if defined (ARRAY_VARS) 200 *flags |= att_assoc; 201 break; 202#else 203 builtin_usage (); 204 return (EX_USAGE); 205#endif 206 case 'p': 207/* if (local_var == 0) */ 208 pflag++; 209 break; 210 case 'F': 211 nodefs++; 212 *flags |= att_function; 213 break; 214 case 'f': 215 *flags |= att_function; 216 break; 217 case 'G': 218 if (flags == &flags_on) 219 chklocal = 1; 220 /*FALLTHROUGH*/ 221 case 'g': 222 if (flags == &flags_on) 223 mkglobal = 1; 224 break; 225 case 'i': 226 *flags |= att_integer; 227 break; 228 case 'n': 229 *flags |= att_nameref; 230 break; 231 case 'r': 232 *flags |= att_readonly; 233 break; 234 case 't': 235 *flags |= att_trace; 236 break; 237 case 'x': 238 *flags |= att_exported; 239 array_needs_making = 1; 240 break; 241#if defined (CASEMOD_ATTRS) 242# if defined (CASEMOD_CAPCASE) 243 case 'c': 244 *flags |= att_capcase; 245 if (flags == &flags_on) 246 flags_off |= att_uppercase|att_lowercase; 247 break; 248# endif 249 case 'l': 250 *flags |= att_lowercase; 251 if (flags == &flags_on) 252 flags_off |= att_capcase|att_uppercase; 253 break; 254 case 'u': 255 *flags |= att_uppercase; 256 if (flags == &flags_on) 257 flags_off |= att_capcase|att_lowercase; 258 break; 259#endif /* CASEMOD_ATTRS */ 260 case 'I': 261 inherit_flag = MKLOC_INHERIT; 262 break; 263 CASE_HELPOPT; 264 default: 265 builtin_usage (); 266 return (EX_USAGE); 267 } 268 } 269 270 list = loptend; 271 272 /* If there are no more arguments left, then we just want to show 273 some variables. */ 274 if (list == 0) /* declare -[aAfFirtx] */ 275 { 276 /* Show local variables defined at this context level if this is 277 the `local' builtin. */ 278 if (local_var) 279 show_local_var_attributes (0, nodefs); /* XXX - fix up args later */ 280 else if (pflag && (flags_on == 0 || flags_on == att_function)) 281 show_all_var_attributes (flags_on == 0, nodefs); 282 else if (flags_on == 0) 283 return (set_builtin ((WORD_LIST *)NULL)); 284 else 285 set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs); 286 287 return (sh_chkwrite (EXECUTION_SUCCESS)); 288 } 289 290 if (pflag) /* declare -p [-aAfFirtx] name [name...] */ 291 { 292 for (any_failed = 0; list; list = list->next) 293 { 294 if (flags_on & att_function) 295 pflag = show_func_attributes (list->word->word, nodefs); 296 else if (local_var) 297 pflag = show_localname_attributes (list->word->word, nodefs); 298 else 299 pflag = show_name_attributes (list->word->word, nodefs); 300 if (pflag) 301 { 302 sh_notfound (list->word->word); 303 any_failed++; 304 } 305 } 306 return (sh_chkwrite (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS)); 307 } 308 309#define NEXT_VARIABLE() free (name); list = list->next; continue 310 311 /* There are arguments left, so we are making variables. */ 312 while (list) /* declare [-aAfFirx] name [name ...] */ 313 { 314 char *value, *name, *oldname; 315 int offset, aflags, wflags, created_var, namelen; 316 int assoc_noexpand; 317#if defined (ARRAY_VARS) 318 int making_array_special, compound_array_assign, simple_array_assign; 319 int var_exists, array_exists, creating_array, array_subscript_assignment; 320#endif 321 322 name = savestring (list->word->word); 323 wflags = list->word->flags; 324#if defined (ARRAY_VARS) 325 assoc_noexpand = assoc_expand_once && (wflags & W_ASSIGNMENT); 326#else 327 assoc_noexpand = 0; 328#endif 329 offset = assignment (name, assoc_noexpand ? 2 : 0); 330 aflags = 0; 331 created_var = 0; 332 333 if (local_var && variable_context && STREQ (name, "-")) 334 { 335 var = make_local_variable ("-", 0); 336 FREE (value_cell (var)); /* just in case */ 337 value = get_current_options (); 338 var_setvalue (var, value); 339 VSETATTR (var, att_invisible); 340 NEXT_VARIABLE (); 341 } 342 343 if (offset) /* declare [-aAfFirx] name=value */ 344 { 345 name[offset] = '\0'; 346 value = name + offset + 1; 347 if (name[offset - 1] == '+') 348 { 349 aflags |= ASS_APPEND; 350 name[offset - 1] = '\0'; 351 } 352 } 353 else 354 value = ""; 355 356 /* Do some lexical error checking on the LHS and RHS of the assignment 357 that is specific to nameref variables. */ 358 if (flags_on & att_nameref) 359 { 360#if defined (ARRAY_VARS) 361 if (valid_array_reference (name, 0)) 362 { 363 builtin_error (_("%s: reference variable cannot be an array"), name); 364 assign_error++; 365 NEXT_VARIABLE (); 366 } 367 else 368#endif 369 /* disallow self references at global scope, warn at function scope */ 370 if (check_selfref (name, value, 0)) 371 { 372 if (variable_context == 0) 373 { 374 builtin_error (_("%s: nameref variable self references not allowed"), name); 375 assign_error++; 376 NEXT_VARIABLE (); 377 } 378 else 379 builtin_warning (_("%s: circular name reference"), name); 380 } 381#if 1 382 if (value && *value && (aflags & ASS_APPEND) == 0 && valid_nameref_value (value, 1) == 0) 383 { 384 builtin_error (_("`%s': invalid variable name for name reference"), value); 385 assign_error++; 386 NEXT_VARIABLE (); 387 } 388#endif 389 } 390 391restart_new_var_name: 392#if defined (ARRAY_VARS) 393 var_exists = array_exists = creating_array = 0; 394 compound_array_assign = simple_array_assign = 0; 395 array_subscript_assignment = 0; 396 subscript_start = (char *)NULL; 397 if ((t = strchr (name, '[')) && (flags_on & att_function) == 0) /* ] */ 398 { 399 /* If offset != 0 we have already validated any array reference 400 because assignment() calls skipsubscript() */ 401 if (offset == 0 && valid_array_reference (name, 0) == 0) 402 { 403 sh_invalidid (name); 404 assign_error++; 405 NEXT_VARIABLE (); 406 } 407 subscript_start = t; 408 *t = '\0'; 409 making_array_special = 1; /* XXX - should this check offset? */ 410 array_subscript_assignment = offset != 0; 411 } 412 else 413 making_array_special = 0; 414#endif 415 416 /* If we're in posix mode or not looking for a shell function (since 417 shell function names don't have to be valid identifiers when the 418 shell's not in posix mode), check whether or not the argument is a 419 valid, well-formed shell identifier. */ 420 if ((posixly_correct || (flags_on & att_function) == 0) && legal_identifier (name) == 0) 421 { 422 sh_invalidid (name); 423 assign_error++; 424 NEXT_VARIABLE (); 425 } 426 427 /* If VARIABLE_CONTEXT has a non-zero value, then we are executing 428 inside of a function. This means we should make local variables, 429 not global ones. */ 430 431 /* XXX - this has consequences when we're making a local copy of a 432 variable that was in the temporary environment. Watch out 433 for this. */ 434 refvar = (SHELL_VAR *)NULL; 435 if (variable_context && mkglobal == 0 && ((flags_on & att_function) == 0)) 436 { 437 char *newname; 438 439 /* check name for validity here? */ 440 var = find_variable (name); 441 if (var == 0) 442 newname = nameref_transform_name (name, ASS_MKLOCAL); 443 else if ((flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0) 444 { 445 /* Ok, we're following namerefs here, so let's make sure that if 446 we followed one, it was at the same context (see below for 447 more details). */ 448 refvar = find_variable_last_nameref (name, 1); 449 newname = (refvar && refvar->context != variable_context) ? name : var->name; 450 refvar = (SHELL_VAR *)NULL; 451 } 452 else 453 newname = name; /* dealing with nameref attribute */ 454 455#if defined (ARRAY_VARS) 456 /* Pass 1 as second argument to make_local_{assoc,array}_variable 457 return an existing {array,assoc} variable to be flagged as an 458 error below. */ 459 if (flags_on & att_assoc) 460 var = make_local_assoc_variable (newname, MKLOC_ARRAYOK|inherit_flag); 461 else if ((flags_on & att_array) || making_array_special) 462 var = make_local_array_variable (newname, MKLOC_ASSOCOK|inherit_flag); 463 else 464#endif 465 if (offset == 0 && (flags_on & att_nameref)) 466 { 467 /* First look for refvar at current scope */ 468 refvar = find_variable_last_nameref (name, 1); 469 /* VARIABLE_CONTEXT != 0, so we are attempting to create or modify 470 the attributes for a local variable at the same scope. If we've 471 used a reference from a previous context to resolve VAR, we 472 want to throw REFVAR and VAR away and create a new local var. */ 473 if (refvar && refvar->context != variable_context) 474 { 475 refvar = 0; 476 var = make_local_variable (name, inherit_flag); 477 } 478 else if (refvar && refvar->context == variable_context) 479 var = refvar; 480 /* Maybe we just want to create a new local variable */ 481 else if (var == 0 || var->context != variable_context) 482 var = make_local_variable (name, inherit_flag); 483 /* otherwise we have a var at the right context */ 484 } 485 else 486 /* XXX - check name for validity here with valid_nameref_value */ 487 var = make_local_variable ((flags_on & att_nameref) ? name : newname, inherit_flag); /* sets att_invisible for new vars */ 488 489 if (var == 0) 490 { 491 any_failed++; 492 NEXT_VARIABLE (); 493 } 494 if (var && nameref_p (var) && readonly_p (var) && nameref_cell (var) && (flags_off & att_nameref)) 495 { 496 sh_readonly (name); 497 any_failed++; 498 NEXT_VARIABLE (); 499 } 500 } 501 else 502 var = (SHELL_VAR *)NULL; 503 504 /* If we are declaring a function, then complain about it in some way. 505 We don't let people make functions by saying `typeset -f foo=bar'. */ 506 507 /* There should be a way, however, to let people look at a particular 508 function definition by saying `typeset -f foo'. */ 509 510 if (flags_on & att_function) 511 { 512 if (offset) /* declare -f [-rix] foo=bar */ 513 { 514 builtin_error (_("cannot use `-f' to make functions")); 515 free (name); 516 return (EXECUTION_FAILURE); 517 } 518 else /* declare -f [-rx] name [name...] */ 519 { 520 var = find_function (name); 521 522 if (var) 523 { 524 if (readonly_p (var) && (flags_off & att_readonly)) 525 { 526 builtin_error (_("%s: readonly function"), name); 527 any_failed++; 528 NEXT_VARIABLE (); 529 } 530 else if (flags_on & (att_array|att_assoc)) 531 { 532 sh_invalidopt ((flags_on & att_array) ? "-a" : "-A"); 533 any_failed++; 534 NEXT_VARIABLE (); 535 } 536 /* declare -[Ff] name [name...] */ 537 if (flags_on == att_function && flags_off == 0) 538 { 539#if defined (DEBUGGER) 540 if (nodefs && debugging_mode) 541 { 542 shell_fn = find_function_def (var->name); 543 if (shell_fn) 544 printf ("%s %d %s\n", var->name, shell_fn->line, shell_fn->source_file); 545 else 546 printf ("%s\n", var->name); 547 } 548 else 549#endif /* DEBUGGER */ 550 { 551 t = nodefs ? var->name 552 : named_function_string (name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL); 553 printf ("%s\n", t); 554 any_failed = sh_chkwrite (any_failed); 555 } 556 } 557 else /* declare -[fF] -[rx] name [name...] */ 558 { 559 VSETATTR (var, flags_on); 560 flags_off &= ~att_function; /* makes no sense */ 561 VUNSETATTR (var, flags_off); 562 } 563 } 564 else 565 any_failed++; 566 NEXT_VARIABLE (); 567 } 568 } 569 else /* declare -[aAinrx] name [name...] */ 570 { 571 /* Non-null if we just created or fetched a local variable. */ 572#if 0 573 /* This is bash-4.3 code. */ 574 /* Here's what ksh93 seems to do. If we are modifying an existing 575 nameref variable, we don't follow the nameref chain past the last 576 nameref, and we set the nameref variable's value so future 577 references to that variable will return the value of the variable 578 we're assigning right now. */ 579#else 580 /* Here's what ksh93 seems to do as of the 2012 version: if we are 581 using declare -n to modify the value of an existing nameref 582 variable, don't follow the nameref chain at all and just search 583 for a nameref at the current context. If we have a nameref, 584 modify its value (changing which variable it references). */ 585#endif 586 if (var == 0 && (flags_on & att_nameref)) 587 { 588 /* See if we are trying to modify an existing nameref variable, 589 but don't follow the nameref chain. */ 590 var = mkglobal ? find_global_variable_noref (name) : find_variable_noref (name); 591 if (var && nameref_p (var) == 0) 592 var = 0; 593 } 594 /* However, if we're turning off the nameref attribute on an existing 595 nameref variable, we first follow the nameref chain to the end, 596 modify the value of the variable this nameref variable references 597 if there is an assignment statement argument, 598 *CHANGING ITS VALUE AS A SIDE EFFECT*, then turn off the nameref 599 flag *LEAVING THE NAMEREF VARIABLE'S VALUE UNCHANGED* */ 600 else if (var == 0 && (flags_off & att_nameref)) 601 { 602 /* See if we are trying to modify an existing nameref variable */ 603 refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0); 604 if (refvar && nameref_p (refvar) == 0) 605 refvar = 0; 606 /* If the nameref is readonly but doesn't have a value, ksh93 607 allows the nameref attribute to be removed. If it's readonly 608 and has a value, even if the value doesn't reference an 609 existing variable, we disallow the modification */ 610 if (refvar && nameref_cell (refvar) && readonly_p (refvar)) 611 { 612 sh_readonly (name); 613 any_failed++; 614 NEXT_VARIABLE (); 615 } 616 617 /* If all we're doing is turning off the nameref attribute, don't 618 bother with VAR at all, whether it exists or not. Just turn it 619 off and go on. */ 620 if (refvar && flags_on == 0 && offset == 0 && (flags_off & ~att_nameref) == 0) 621 { 622 VUNSETATTR (refvar, att_nameref); 623 NEXT_VARIABLE (); 624 } 625 626 if (refvar) 627 /* XXX - use declare_find_variable here? */ 628 var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar)); 629 } 630#if defined (ARRAY_VARS) 631 /* If we have an array assignment to a nameref, remove the nameref 632 attribute and go on. */ 633 else if (var == 0 && offset && array_subscript_assignment) 634 { 635 var = mkglobal ? find_global_variable_noref (name) : find_variable_noref (name); 636 if (var && nameref_p (var)) 637 { 638 internal_warning (_("%s: removing nameref attribute"), name); 639 FREE (value_cell (var)); /* XXX - bash-4.3 compat */ 640 var_setvalue (var, (char *)NULL); 641 VUNSETATTR (var, att_nameref); 642 } 643 } 644#endif 645 646 /* See if we are trying to set flags or value (or create) for an 647 existing nameref that points to a non-existent variable: e.g., 648 declare -n foo=bar 649 unset foo # unsets bar 650 declare -i foo 651 foo=4+4 652 declare -p foo */ 653 if (var == 0 && (mkglobal || flags_on || flags_off || offset)) 654 { 655 refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0); 656 if (refvar && nameref_p (refvar) == 0) 657 refvar = 0; 658 if (refvar) 659 /* XXX - use declare_find_variable here? */ 660 var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar)); 661 if (refvar && var == 0) 662 { 663 oldname = name; /* need to free this */ 664 665 namelen = strlen (nameref_cell (refvar)); 666#if defined (ARRAY_VARS) 667 if (subscript_start) 668 { 669 *subscript_start = '['; /*]*/ 670 namelen += strlen (subscript_start); 671 } 672#endif 673 name = xmalloc (namelen + 2 + strlen (value) + 1); 674 strcpy (name, nameref_cell (refvar)); 675#if defined (ARRAY_VARS) 676 if (subscript_start) 677 strcpy (name + strlen (nameref_cell (refvar)), subscript_start); 678#endif 679 /* We are committed to using the new name, so reset */ 680 if (offset) 681 { 682 /* Rebuild assignment and restore offset and value */ 683 if (aflags & ASS_APPEND) 684 name[namelen++] = '+'; 685 name[namelen++] = '='; 686 if (value && *value) 687 strcpy (name + namelen, value); 688 else 689 name[namelen] = '\0'; 690 offset = assignment (name, 0); 691 /* if offset was valid previously, but the substituting 692 of the nameref value results in an invalid assignment, 693 throw an invalid identifier error */ 694 if (offset == 0) 695 { 696 free (oldname); 697 sh_invalidid (name); 698 assign_error++; 699 NEXT_VARIABLE (); 700 } 701 name[offset] = '\0'; 702 value = name + namelen; 703 } 704 free (oldname); 705 706 /* OK, let's turn off the nameref attribute. 707 Now everything else applies to VAR. */ 708 if (flags_off & att_nameref) 709 VUNSETATTR (refvar, att_nameref); 710 711 goto restart_new_var_name; 712 /* NOTREACHED */ 713 } 714 } 715 if (var == 0) 716 var = declare_find_variable (name, mkglobal, chklocal); 717 718#if defined (ARRAY_VARS) 719 var_exists = var != 0; 720 array_exists = var && (array_p (var) || assoc_p (var)); 721 creating_array = flags_on & (att_array|att_assoc); 722#endif 723 724 if (var == 0) 725 { 726#if defined (ARRAY_VARS) 727 if (flags_on & att_assoc) 728 { 729 var = make_new_assoc_variable (name); 730 if (var && offset == 0) 731 VSETATTR (var, att_invisible); 732 } 733 else if ((flags_on & att_array) || making_array_special) 734 { 735 var = make_new_array_variable (name); 736 if (var && offset == 0) 737 VSETATTR (var, att_invisible); 738 } 739 else 740#endif 741 { 742 var = mkglobal ? bind_global_variable (name, (char *)NULL, ASS_FORCE) : bind_variable (name, (char *)NULL, ASS_FORCE); 743 if (var && offset == 0) 744 VSETATTR (var, att_invisible); 745 } 746 if (var == 0) 747 { 748 /* Has to appear in brackets */ 749 NEXT_VARIABLE (); 750 } 751 created_var = 1; 752 } 753 /* Can't take an existing array variable and make it a nameref */ 754 else if ((array_p (var) || assoc_p (var)) && (flags_on & att_nameref)) 755 { 756 builtin_error (_("%s: reference variable cannot be an array"), name); 757 assign_error++; 758 NEXT_VARIABLE (); 759 } 760 else if (nameref_p (var) && (flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0 && offset && valid_nameref_value (value, 1) == 0) 761 { 762 builtin_error (_("`%s': invalid variable name for name reference"), value); 763 any_failed++; 764 NEXT_VARIABLE (); 765 } 766 else if (flags_on & att_nameref) 767 { 768#if 1 769 /* Check of offset is to allow an assignment to a nameref var as 770 part of the declare word to override existing value */ 771 if (nameref_p (var) == 0 && var_isset (var) && offset == 0 && valid_nameref_value (value_cell (var), 0) == 0) 772 { 773 builtin_error (_("`%s': invalid variable name for name reference"), value_cell (var)); 774 any_failed++; 775 NEXT_VARIABLE (); 776 } 777#endif 778 if (readonly_p (var)) 779 { 780 sh_readonly (name); 781 any_failed++; 782 NEXT_VARIABLE (); 783 } 784 /* ksh93 compat: turning on nameref attribute turns off -ilu */ 785 VUNSETATTR (var, att_integer|att_uppercase|att_lowercase|att_capcase); 786 } 787 788 /* Cannot use declare +r to turn off readonly attribute. */ 789 if (readonly_p (var) && (flags_off & att_readonly)) 790 { 791 sh_readonly (name_cell (var)); 792 any_failed++; 793 NEXT_VARIABLE (); 794 } 795 796 /* Cannot use declare to assign value to readonly or noassign 797 variable. */ 798 if ((readonly_p (var) || noassign_p (var)) && offset) 799 { 800 if (readonly_p (var)) 801 sh_readonly (name); 802 assign_error++; 803 NEXT_VARIABLE (); 804 } 805 806#if defined (ARRAY_VARS) 807 /* make declare a[2]=foo as similar to a[2]=foo as possible if 808 a is already an array or assoc variable. */ 809 if (array_subscript_assignment && array_exists && creating_array == 0) 810 simple_array_assign = 1; 811 else if ((making_array_special || creating_array || array_exists) && offset) 812 { 813 int vlen; 814 vlen = STRLEN (value); 815/*itrace("declare_builtin: name = %s value = %s flags = %d", name, value, wflags);*/ 816 if (shell_compatibility_level > 43 && (wflags & W_COMPASSIGN) == 0 && 817 value[0] == '(' && value[vlen-1] == ')') 818 { 819 /* The warning is only printed when using compound assignment 820 to an array variable that doesn't already exist. We use 821 creating_array to allow things like 822 declare -a foo$bar='(abc)' to work. */ 823 if (array_exists == 0 && creating_array == 0) 824 internal_warning (_("%s: quoted compound array assignment deprecated"), list->word->word); 825 compound_array_assign = array_exists || creating_array; 826 simple_array_assign = making_array_special; 827 } 828 else if (value[0] == '(' && value[vlen-1] == ')' && (shell_compatibility_level < 44 || (wflags & W_COMPASSIGN))) 829 compound_array_assign = 1; 830 else 831 simple_array_assign = 1; 832 } 833 834 /* Cannot use declare +a name or declare +A name to remove an 835 array variable. */ 836 if (((flags_off & att_array) && array_p (var)) || ((flags_off & att_assoc) && assoc_p (var))) 837 { 838 builtin_error (_("%s: cannot destroy array variables in this way"), name); 839 any_failed++; 840 NEXT_VARIABLE (); 841 } 842 843 if ((flags_on & att_array) && assoc_p (var)) 844 { 845 builtin_error (_("%s: cannot convert associative to indexed array"), name); 846 any_failed++; 847 NEXT_VARIABLE (); 848 } 849 if ((flags_on & att_assoc) && array_p (var)) 850 { 851 builtin_error (_("%s: cannot convert indexed to associative array"), name); 852 any_failed++; 853 NEXT_VARIABLE (); 854 } 855 856 /* declare -A name[[n]] makes name an associative array variable. */ 857 if (flags_on & att_assoc) 858 { 859 if (assoc_p (var) == 0) 860 var = convert_var_to_assoc (var); 861 } 862 /* declare -a name[[n]] or declare name[n] makes name an indexed 863 array variable. */ 864 else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0 && assoc_p (var) == 0) 865 var = convert_var_to_array (var); 866#endif /* ARRAY_VARS */ 867 868 /* XXX - we note that we are turning on nameref attribute and defer 869 setting it until the assignment has been made so we don't do an 870 inadvertent nameref lookup. Might have to do the same thing for 871 flags_off&att_nameref. */ 872 /* XXX - ksh93 makes it an error to set a readonly nameref variable 873 using a single typeset command. */ 874 onref = (flags_on & att_nameref); 875 flags_on &= ~att_nameref; 876#if defined (ARRAY_VARS) 877 if (array_p (var) || assoc_p (var) 878 || (offset && compound_array_assign) 879 || simple_array_assign) 880 onref = 0; /* array variables may not be namerefs */ 881#endif 882 883 /* ksh93 seems to do this */ 884 offref = (flags_off & att_nameref); 885 flags_off &= ~att_nameref; 886 887 VSETATTR (var, flags_on); 888 VUNSETATTR (var, flags_off); 889 890#if defined (ARRAY_VARS) 891 if (offset && compound_array_assign) 892 assign_array_var_from_string (var, value, aflags|ASS_FORCE); 893 else if (simple_array_assign && subscript_start) 894 { 895 int local_aflags; 896 /* declare [-aA] name[N]=value */ 897 *subscript_start = '['; /* ] */ 898 /* XXX - problem here with appending */ 899 local_aflags = aflags&ASS_APPEND; 900 local_aflags |= assoc_noexpand ? ASS_NOEXPAND : 0; 901 var = assign_array_element (name, value, local_aflags); /* XXX - not aflags */ 902 *subscript_start = '\0'; 903 if (var == 0) /* some kind of assignment error */ 904 { 905 assign_error++; 906 flags_on |= onref; 907 flags_off |= offref; 908 NEXT_VARIABLE (); 909 } 910 } 911 else if (simple_array_assign) 912 { 913 /* let bind_{array,assoc}_variable take care of this. */ 914 if (assoc_p (var)) 915 bind_assoc_variable (var, name, savestring ("0"), value, aflags|ASS_FORCE); 916 else 917 bind_array_variable (name, 0, value, aflags|ASS_FORCE); 918 } 919 else 920#endif 921 /* XXX - no ASS_FORCE here */ 922 /* bind_variable_value duplicates the essential internals of 923 bind_variable() */ 924 if (offset) 925 { 926 if (onref || nameref_p (var)) 927 aflags |= ASS_NAMEREF; 928 v = bind_variable_value (var, value, aflags); 929 if (v == 0 && (onref || nameref_p (var))) 930 { 931 if (valid_nameref_value (value, 1) == 0) 932 sh_invalidid (value); 933 assign_error++; 934 /* XXX - unset this variable? or leave it as normal var? */ 935 if (created_var) 936 delete_var (var->name, mkglobal ? global_variables : shell_variables); 937 flags_on |= onref; /* undo change from above */ 938 flags_off |= offref; 939 NEXT_VARIABLE (); 940 } 941 } 942 943 /* If we found this variable in the temporary environment, as with 944 `var=value declare -x var', make sure it is treated identically 945 to `var=value export var'. Do the same for `declare -r' and 946 `readonly'. Preserve the attributes, except for att_tempvar. */ 947 /* XXX -- should this create a variable in the global scope, or 948 modify the local variable flags? ksh93 has it modify the 949 global scope. 950 Need to handle case like in set_var_attribute where a temporary 951 variable is in the same table as the function local vars. */ 952 if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var)) 953 { 954 SHELL_VAR *tv; 955 char *tvalue; 956 957 tv = find_tempenv_variable (var->name); 958 if (tv) 959 { 960 tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring (""); 961 tv = bind_variable (var->name, tvalue, 0); 962 if (tv) 963 { 964 tv->attributes |= var->attributes & ~att_tempvar; 965 if (tv->context > 0) 966 VSETATTR (tv, att_propagate); 967 } 968 free (tvalue); 969 } 970 VSETATTR (var, att_propagate); 971 } 972 } 973 974 /* Turn on nameref attribute we deferred above. */ 975 /* XXX - should we turn on the noassign attribute for consistency with 976 ksh93 when we turn on the nameref attribute? */ 977 VSETATTR (var, onref); 978 flags_on |= onref; 979 VUNSETATTR (var, offref); 980 flags_off |= offref; 981 /* Yuck. ksh93 compatibility. XXX - need to investigate more but 982 definitely happens when turning off nameref attribute on nameref 983 (see comments above). Under no circumstances allow this to turn 984 off readonly attribute on readonly nameref variable. */ 985 if (refvar) 986 { 987 if (flags_off & att_readonly) 988 flags_off &= ~att_readonly; 989 VUNSETATTR (refvar, flags_off); 990 } 991 992 stupidly_hack_special_variables (name); 993 994 NEXT_VARIABLE (); 995 } 996 997 return (assign_error ? EX_BADASSIGN 998 : ((any_failed == 0) ? EXECUTION_SUCCESS 999 : EXECUTION_FAILURE)); 1000} 1001