Dan Pasanen | c6e3786 | 2014-10-02 14:08:59 -0500 | [diff] [blame] | 1 | /* setattr.c, created from setattr.def. */ |
| 2 | #line 22 "./setattr.def" |
| 3 | |
| 4 | #include <config.h> |
| 5 | |
| 6 | #if defined (HAVE_UNISTD_H) |
| 7 | # ifdef _MINIX |
| 8 | # include <sys/types.h> |
| 9 | # endif |
| 10 | # include <unistd.h> |
| 11 | #endif |
| 12 | |
| 13 | #include <stdio.h> |
| 14 | #include "../bashansi.h" |
| 15 | #include "../bashintl.h" |
| 16 | |
| 17 | #include "../shell.h" |
| 18 | #include "common.h" |
| 19 | #include "bashgetopt.h" |
| 20 | |
| 21 | extern int posixly_correct; |
| 22 | extern int array_needs_making; |
| 23 | extern char *this_command_name; |
| 24 | extern sh_builtin_func_t *this_shell_builtin; |
| 25 | |
| 26 | #ifdef ARRAY_VARS |
| 27 | extern int declare_builtin __P((WORD_LIST *)); |
| 28 | #endif |
| 29 | |
| 30 | #define READONLY_OR_EXPORT \ |
| 31 | (this_shell_builtin == readonly_builtin || this_shell_builtin == export_builtin) |
| 32 | |
| 33 | #line 70 "./setattr.def" |
| 34 | |
| 35 | /* For each variable name in LIST, make that variable appear in the |
| 36 | environment passed to simple commands. If there is no LIST, then |
| 37 | print all such variables. An argument of `-n' says to remove the |
| 38 | exported attribute from variables named in LIST. An argument of |
| 39 | -f indicates that the names present in LIST refer to functions. */ |
| 40 | int |
| 41 | export_builtin (list) |
| 42 | register WORD_LIST *list; |
| 43 | { |
| 44 | return (set_or_show_attributes (list, att_exported, 0)); |
| 45 | } |
| 46 | |
| 47 | #line 104 "./setattr.def" |
| 48 | |
| 49 | /* For each variable name in LIST, make that variable readonly. Given an |
| 50 | empty LIST, print out all existing readonly variables. */ |
| 51 | int |
| 52 | readonly_builtin (list) |
| 53 | register WORD_LIST *list; |
| 54 | { |
| 55 | return (set_or_show_attributes (list, att_readonly, 0)); |
| 56 | } |
| 57 | |
| 58 | #if defined (ARRAY_VARS) |
| 59 | # define ATTROPTS "aAfnp" |
| 60 | #else |
| 61 | # define ATTROPTS "fnp" |
| 62 | #endif |
| 63 | |
| 64 | /* For each variable name in LIST, make that variable have the specified |
| 65 | ATTRIBUTE. An arg of `-n' says to remove the attribute from the the |
| 66 | remaining names in LIST (doesn't work for readonly). */ |
| 67 | int |
| 68 | set_or_show_attributes (list, attribute, nodefs) |
| 69 | register WORD_LIST *list; |
| 70 | int attribute, nodefs; |
| 71 | { |
| 72 | register SHELL_VAR *var; |
| 73 | int assign, undo, any_failed, assign_error, opt; |
| 74 | int functions_only, arrays_only, assoc_only; |
| 75 | int aflags; |
| 76 | char *name; |
| 77 | #if defined (ARRAY_VARS) |
| 78 | WORD_LIST *nlist, *tlist; |
| 79 | WORD_DESC *w; |
| 80 | #endif |
| 81 | |
| 82 | functions_only = arrays_only = assoc_only = 0; |
| 83 | undo = any_failed = assign_error = 0; |
| 84 | /* Read arguments from the front of the list. */ |
| 85 | reset_internal_getopt (); |
| 86 | while ((opt = internal_getopt (list, ATTROPTS)) != -1) |
| 87 | { |
| 88 | switch (opt) |
| 89 | { |
| 90 | case 'n': |
| 91 | undo = 1; |
| 92 | break; |
| 93 | case 'f': |
| 94 | functions_only = 1; |
| 95 | break; |
| 96 | #if defined (ARRAY_VARS) |
| 97 | case 'a': |
| 98 | arrays_only = 1; |
| 99 | break; |
| 100 | case 'A': |
| 101 | assoc_only = 1; |
| 102 | break; |
| 103 | #endif |
| 104 | case 'p': |
| 105 | break; |
| 106 | default: |
| 107 | builtin_usage (); |
| 108 | return (EX_USAGE); |
| 109 | } |
| 110 | } |
| 111 | list = loptend; |
| 112 | |
| 113 | if (list) |
| 114 | { |
| 115 | if (attribute & att_exported) |
| 116 | array_needs_making = 1; |
| 117 | |
| 118 | /* Cannot undo readonly status, silently disallowed. */ |
| 119 | if (undo && (attribute & att_readonly)) |
| 120 | attribute &= ~att_readonly; |
| 121 | |
| 122 | while (list) |
| 123 | { |
| 124 | name = list->word->word; |
| 125 | |
| 126 | if (functions_only) /* xxx -f name */ |
| 127 | { |
| 128 | var = find_function (name); |
| 129 | if (var == 0) |
| 130 | { |
| 131 | builtin_error (_("%s: not a function"), name); |
| 132 | any_failed++; |
| 133 | } |
| 134 | else |
| 135 | SETVARATTR (var, attribute, undo); |
| 136 | |
| 137 | list = list->next; |
| 138 | continue; |
| 139 | } |
| 140 | |
| 141 | /* xxx [-np] name[=value] */ |
| 142 | assign = assignment (name, 0); |
| 143 | |
| 144 | aflags = 0; |
| 145 | if (assign) |
| 146 | { |
| 147 | name[assign] = '\0'; |
| 148 | if (name[assign - 1] == '+') |
| 149 | { |
| 150 | aflags |= ASS_APPEND; |
| 151 | name[assign - 1] = '\0'; |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | if (legal_identifier (name) == 0) |
| 156 | { |
| 157 | sh_invalidid (name); |
| 158 | if (assign) |
| 159 | assign_error++; |
| 160 | else |
| 161 | any_failed++; |
| 162 | list = list->next; |
| 163 | continue; |
| 164 | } |
| 165 | |
| 166 | if (assign) /* xxx [-np] name=value */ |
| 167 | { |
| 168 | name[assign] = '='; |
| 169 | if (aflags & ASS_APPEND) |
| 170 | name[assign - 1] = '+'; |
| 171 | #if defined (ARRAY_VARS) |
| 172 | /* Let's try something here. Turn readonly -a xxx=yyy into |
| 173 | declare -ra xxx=yyy and see what that gets us. */ |
| 174 | if (arrays_only || assoc_only) |
| 175 | { |
| 176 | tlist = list->next; |
| 177 | list->next = (WORD_LIST *)NULL; |
| 178 | w = arrays_only ? make_word ("-ra") : make_word ("-rA"); |
| 179 | nlist = make_word_list (w, list); |
| 180 | opt = declare_builtin (nlist); |
| 181 | if (opt != EXECUTION_SUCCESS) |
| 182 | assign_error++; |
| 183 | list->next = tlist; |
| 184 | dispose_word (w); |
| 185 | free (nlist); |
| 186 | } |
| 187 | else |
| 188 | #endif |
| 189 | /* This word has already been expanded once with command |
| 190 | and parameter expansion. Call do_assignment_no_expand (), |
| 191 | which does not do command or parameter substitution. If |
| 192 | the assignment is not performed correctly, flag an error. */ |
| 193 | if (do_assignment_no_expand (name) == 0) |
| 194 | assign_error++; |
| 195 | name[assign] = '\0'; |
| 196 | if (aflags & ASS_APPEND) |
| 197 | name[assign - 1] = '\0'; |
| 198 | } |
| 199 | |
| 200 | set_var_attribute (name, attribute, undo); |
| 201 | list = list->next; |
| 202 | } |
| 203 | } |
| 204 | else |
| 205 | { |
| 206 | SHELL_VAR **variable_list; |
| 207 | register int i; |
| 208 | |
| 209 | if ((attribute & att_function) || functions_only) |
| 210 | { |
| 211 | variable_list = all_shell_functions (); |
| 212 | if (attribute != att_function) |
| 213 | attribute &= ~att_function; /* so declare -xf works, for example */ |
| 214 | } |
| 215 | else |
| 216 | variable_list = all_shell_variables (); |
| 217 | |
| 218 | #if defined (ARRAY_VARS) |
| 219 | if (attribute & att_array) |
| 220 | { |
| 221 | arrays_only++; |
| 222 | if (attribute != att_array) |
| 223 | attribute &= ~att_array; |
| 224 | } |
| 225 | else if (attribute & att_assoc) |
| 226 | { |
| 227 | assoc_only++; |
| 228 | if (attribute != att_assoc) |
| 229 | attribute &= ~att_assoc; |
| 230 | } |
| 231 | #endif |
| 232 | |
| 233 | if (variable_list) |
| 234 | { |
| 235 | for (i = 0; var = variable_list[i]; i++) |
| 236 | { |
| 237 | #if defined (ARRAY_VARS) |
| 238 | if (arrays_only && array_p (var) == 0) |
| 239 | continue; |
| 240 | else if (assoc_only && assoc_p (var) == 0) |
| 241 | continue; |
| 242 | #endif |
| 243 | if ((var->attributes & attribute)) |
| 244 | { |
| 245 | show_var_attributes (var, READONLY_OR_EXPORT, nodefs); |
| 246 | if (any_failed = sh_chkwrite (any_failed)) |
| 247 | break; |
| 248 | } |
| 249 | } |
| 250 | free (variable_list); |
| 251 | } |
| 252 | } |
| 253 | |
| 254 | return (assign_error ? EX_BADASSIGN |
| 255 | : ((any_failed == 0) ? EXECUTION_SUCCESS |
| 256 | : EXECUTION_FAILURE)); |
| 257 | } |
| 258 | |
| 259 | /* Show all variable variables (v == 1) or functions (v == 0) with |
| 260 | attributes. */ |
| 261 | int |
| 262 | show_all_var_attributes (v, nodefs) |
| 263 | int v, nodefs; |
| 264 | { |
| 265 | SHELL_VAR **variable_list, *var; |
| 266 | int any_failed; |
| 267 | register int i; |
| 268 | |
| 269 | variable_list = v ? all_shell_variables () : all_shell_functions (); |
| 270 | if (variable_list == 0) |
| 271 | return (EXECUTION_SUCCESS); |
| 272 | |
| 273 | for (i = any_failed = 0; var = variable_list[i]; i++) |
| 274 | { |
| 275 | show_var_attributes (var, READONLY_OR_EXPORT, nodefs); |
| 276 | if (any_failed = sh_chkwrite (any_failed)) |
| 277 | break; |
| 278 | } |
| 279 | free (variable_list); |
| 280 | return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE); |
| 281 | } |
| 282 | |
| 283 | /* Show the attributes for shell variable VAR. If NODEFS is non-zero, |
| 284 | don't show function definitions along with the name. If PATTR is |
| 285 | non-zero, it indicates we're being called from `export' or `readonly'. |
| 286 | In POSIX mode, this prints the name of the calling builtin (`export' |
| 287 | or `readonly') instead of `declare', and doesn't print function defs |
| 288 | when called by `export' or `readonly'. */ |
| 289 | int |
| 290 | show_var_attributes (var, pattr, nodefs) |
| 291 | SHELL_VAR *var; |
| 292 | int pattr, nodefs; |
| 293 | { |
| 294 | char flags[16], *x; |
| 295 | int i; |
| 296 | |
| 297 | i = 0; |
| 298 | |
| 299 | /* pattr == 0 means we are called from `declare'. */ |
| 300 | if (pattr == 0 || posixly_correct == 0) |
| 301 | { |
| 302 | #if defined (ARRAY_VARS) |
| 303 | if (array_p (var)) |
| 304 | flags[i++] = 'a'; |
| 305 | |
| 306 | if (assoc_p (var)) |
| 307 | flags[i++] = 'A'; |
| 308 | #endif |
| 309 | |
| 310 | if (function_p (var)) |
| 311 | flags[i++] = 'f'; |
| 312 | |
| 313 | if (integer_p (var)) |
| 314 | flags[i++] = 'i'; |
| 315 | |
| 316 | if (nameref_p (var)) |
| 317 | flags[i++] = 'n'; |
| 318 | |
| 319 | if (readonly_p (var)) |
| 320 | flags[i++] = 'r'; |
| 321 | |
| 322 | if (trace_p (var)) |
| 323 | flags[i++] = 't'; |
| 324 | |
| 325 | if (exported_p (var)) |
| 326 | flags[i++] = 'x'; |
| 327 | |
| 328 | if (capcase_p (var)) |
| 329 | flags[i++] = 'c'; |
| 330 | |
| 331 | if (lowercase_p (var)) |
| 332 | flags[i++] = 'l'; |
| 333 | |
| 334 | if (uppercase_p (var)) |
| 335 | flags[i++] = 'u'; |
| 336 | } |
| 337 | else |
| 338 | { |
| 339 | #if defined (ARRAY_VARS) |
| 340 | if (array_p (var)) |
| 341 | flags[i++] = 'a'; |
| 342 | |
| 343 | if (assoc_p (var)) |
| 344 | flags[i++] = 'A'; |
| 345 | #endif |
| 346 | |
| 347 | if (function_p (var)) |
| 348 | flags[i++] = 'f'; |
| 349 | } |
| 350 | |
| 351 | flags[i] = '\0'; |
| 352 | |
| 353 | /* If we're printing functions with definitions, print the function def |
| 354 | first, then the attributes, instead of printing output that can't be |
| 355 | reused as input to recreate the current state. */ |
| 356 | if (function_p (var) && nodefs == 0 && (pattr == 0 || posixly_correct == 0)) |
| 357 | { |
| 358 | printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL)); |
| 359 | nodefs++; |
| 360 | if (pattr == 0 && i == 1 && flags[0] == 'f') |
| 361 | return 0; /* don't print `declare -f name' */ |
| 362 | } |
| 363 | |
| 364 | if (pattr == 0 || posixly_correct == 0) |
| 365 | printf ("declare -%s ", i ? flags : "-"); |
| 366 | else if (i) |
| 367 | printf ("%s -%s ", this_command_name, flags); |
| 368 | else |
| 369 | printf ("%s ", this_command_name); |
| 370 | |
| 371 | #if defined (ARRAY_VARS) |
| 372 | if (array_p (var)) |
| 373 | print_array_assignment (var, 1); |
| 374 | else if (assoc_p (var)) |
| 375 | print_assoc_assignment (var, 1); |
| 376 | else |
| 377 | #endif |
| 378 | /* force `readonly' and `export' to not print out function definitions |
| 379 | when in POSIX mode. */ |
| 380 | if (nodefs || (function_p (var) && pattr != 0 && posixly_correct)) |
| 381 | printf ("%s\n", var->name); |
| 382 | else if (function_p (var)) |
| 383 | printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL)); |
| 384 | else if (invisible_p (var) || var_isset (var) == 0) |
| 385 | printf ("%s\n", var->name); |
| 386 | else |
| 387 | { |
| 388 | x = sh_double_quote (value_cell (var)); |
| 389 | printf ("%s=%s\n", var->name, x); |
| 390 | free (x); |
| 391 | } |
| 392 | return (0); |
| 393 | } |
| 394 | |
| 395 | int |
| 396 | show_name_attributes (name, nodefs) |
| 397 | char *name; |
| 398 | int nodefs; |
| 399 | { |
| 400 | SHELL_VAR *var; |
| 401 | |
| 402 | #if 0 |
| 403 | var = find_variable_tempenv (name); |
| 404 | #else |
| 405 | var = find_variable_noref (name); |
| 406 | #endif |
| 407 | |
| 408 | if (var && invisible_p (var) == 0) |
| 409 | { |
| 410 | show_var_attributes (var, READONLY_OR_EXPORT, nodefs); |
| 411 | return (0); |
| 412 | } |
| 413 | else |
| 414 | return (1); |
| 415 | } |
| 416 | |
| 417 | int |
| 418 | show_func_attributes (name, nodefs) |
| 419 | char *name; |
| 420 | int nodefs; |
| 421 | { |
| 422 | SHELL_VAR *var; |
| 423 | |
| 424 | var = find_function (name); |
| 425 | |
| 426 | if (var) |
| 427 | { |
| 428 | show_var_attributes (var, READONLY_OR_EXPORT, nodefs); |
| 429 | return (0); |
| 430 | } |
| 431 | else |
| 432 | return (1); |
| 433 | } |
| 434 | |
| 435 | void |
| 436 | set_var_attribute (name, attribute, undo) |
| 437 | char *name; |
| 438 | int attribute, undo; |
| 439 | { |
| 440 | SHELL_VAR *var, *tv, *v; |
| 441 | char *tvalue; |
| 442 | |
| 443 | if (undo) |
| 444 | var = find_variable (name); |
| 445 | else |
| 446 | { |
| 447 | tv = find_tempenv_variable (name); |
| 448 | /* XXX -- need to handle case where tv is a temp variable in a |
| 449 | function-scope context, since function_env has been merged into |
| 450 | the local variables table. */ |
| 451 | if (tv && tempvar_p (tv)) |
| 452 | { |
| 453 | tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring (""); |
| 454 | |
| 455 | var = bind_variable (tv->name, tvalue, 0); |
| 456 | var->attributes |= tv->attributes & ~att_tempvar; |
| 457 | /* This avoids an error message when propagating a read-only var |
| 458 | later on. */ |
| 459 | if (var->context == 0 && (attribute & att_readonly)) |
| 460 | { |
| 461 | /* Don't bother to set the `propagate to the global variables |
| 462 | table' flag if we've just bound the variable in that table */ |
| 463 | v = find_global_variable (tv->name); |
| 464 | if (v != var) |
| 465 | VSETATTR (tv, att_propagate); |
| 466 | } |
| 467 | else |
| 468 | VSETATTR (tv, att_propagate); |
| 469 | if (var->context != 0) |
| 470 | VSETATTR (var, att_propagate); |
| 471 | SETVARATTR (tv, attribute, undo); /* XXX */ |
| 472 | |
| 473 | stupidly_hack_special_variables (tv->name); |
| 474 | |
| 475 | free (tvalue); |
| 476 | } |
| 477 | else |
| 478 | { |
| 479 | var = find_variable_notempenv (name); |
| 480 | if (var == 0) |
| 481 | { |
| 482 | var = bind_variable (name, (char *)NULL, 0); |
| 483 | VSETATTR (var, att_invisible); |
| 484 | } |
| 485 | else if (var->context != 0) |
| 486 | VSETATTR (var, att_propagate); |
| 487 | } |
| 488 | } |
| 489 | |
| 490 | if (var) |
| 491 | SETVARATTR (var, attribute, undo); |
| 492 | |
| 493 | if (var && (exported_p (var) || (attribute & att_exported))) |
| 494 | array_needs_making++; /* XXX */ |
| 495 | } |