1/* setattr.c, created from setattr.def. */ 2#line 23 "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 21extern int posixly_correct; 22extern int array_needs_making; 23extern char *this_command_name; 24extern sh_builtin_func_t *this_shell_builtin; 25 26#ifdef ARRAY_VARS 27extern 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 64 "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. */ 40int 41export_builtin (list) 42 register WORD_LIST *list; 43{ 44 return (set_or_show_attributes (list, att_exported, 0)); 45} 46 47#line 88 "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. */ 51int 52readonly_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 "afnp" 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). */ 67int 68set_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, functions_only, arrays_only, any_failed, assign_error, opt; 74 int aflags; 75 char *name; 76#if defined (ARRAY_VARS) 77 WORD_LIST *nlist, *tlist; 78 WORD_DESC *w; 79#endif 80 81 undo = functions_only = arrays_only = any_failed = assign_error = 0; 82 /* Read arguments from the front of the list. */ 83 reset_internal_getopt (); 84 while ((opt = internal_getopt (list, ATTROPTS)) != -1) 85 { 86 switch (opt) 87 { 88 case 'n': 89 undo = 1; 90 break; 91 case 'f': 92 functions_only = 1; 93 break; 94#if defined (ARRAY_VARS) 95 case 'a': 96 arrays_only = 1; 97 break; 98#endif 99 case 'p': 100 break; 101 default: 102 builtin_usage (); 103 return (EX_USAGE); 104 } 105 } 106 list = loptend; 107 108 if (list) 109 { 110 if (attribute & att_exported) 111 array_needs_making = 1; 112 113 /* Cannot undo readonly status, silently disallowed. */ 114 if (undo && (attribute & att_readonly)) 115 attribute &= ~att_readonly; 116 117 while (list) 118 { 119 name = list->word->word; 120 121 if (functions_only) /* xxx -f name */ 122 { 123 var = find_function (name); 124 if (var == 0) 125 { 126 builtin_error (_("%s: not a function"), name); 127 any_failed++; 128 } 129 else 130 SETVARATTR (var, attribute, undo); 131 132 list = list->next; 133 continue; 134 } 135 136 /* xxx [-np] name[=value] */ 137 assign = assignment (name, 0); 138 139 aflags = 0; 140 if (assign) 141 { 142 name[assign] = '\0'; 143 if (name[assign - 1] == '+') 144 { 145 aflags |= ASS_APPEND; 146 name[assign - 1] = '\0'; 147 } 148 } 149 150 if (legal_identifier (name) == 0) 151 { 152 sh_invalidid (name); 153 if (assign) 154 assign_error++; 155 else 156 any_failed++; 157 list = list->next; 158 continue; 159 } 160 161 if (assign) /* xxx [-np] name=value */ 162 { 163 name[assign] = '='; 164 if (aflags & ASS_APPEND) 165 name[assign - 1] = '+'; 166#if defined (ARRAY_VARS) 167 /* Let's try something here. Turn readonly -a xxx=yyy into 168 declare -ra xxx=yyy and see what that gets us. */ 169 if (arrays_only) 170 { 171 tlist = list->next; 172 list->next = (WORD_LIST *)NULL; 173 w = make_word ("-ra"); 174 nlist = make_word_list (w, list); 175 opt = declare_builtin (nlist); 176 if (opt != EXECUTION_SUCCESS) 177 assign_error++; 178 list->next = tlist; 179 dispose_word (w); 180 free (nlist); 181 } 182 else 183#endif 184 /* This word has already been expanded once with command 185 and parameter expansion. Call do_assignment_no_expand (), 186 which does not do command or parameter substitution. If 187 the assignment is not performed correctly, flag an error. */ 188 if (do_assignment_no_expand (name) == 0) 189 assign_error++; 190 name[assign] = '\0'; 191 if (aflags & ASS_APPEND) 192 name[assign - 1] = '\0'; 193 } 194 195 set_var_attribute (name, attribute, undo); 196 list = list->next; 197 } 198 } 199 else 200 { 201 SHELL_VAR **variable_list; 202 register int i; 203 204 if ((attribute & att_function) || functions_only) 205 { 206 variable_list = all_shell_functions (); 207 if (attribute != att_function) 208 attribute &= ~att_function; /* so declare -xf works, for example */ 209 } 210 else 211 variable_list = all_shell_variables (); 212 213#if defined (ARRAY_VARS) 214 if (attribute & att_array) 215 { 216 arrays_only++; 217 if (attribute != att_array) 218 attribute &= ~att_array; 219 } 220#endif 221 222 if (variable_list) 223 { 224 for (i = 0; var = variable_list[i]; i++) 225 { 226#if defined (ARRAY_VARS) 227 if (arrays_only && array_p (var) == 0) 228 continue; 229#endif 230 if ((var->attributes & attribute)) 231 show_var_attributes (var, READONLY_OR_EXPORT, nodefs); 232 } 233 free (variable_list); 234 } 235 } 236 237 return (assign_error ? EX_BADASSIGN 238 : ((any_failed == 0) ? EXECUTION_SUCCESS 239 : EXECUTION_FAILURE)); 240} 241 242/* Show the attributes for shell variable VAR. If NODEFS is non-zero, 243 don't show function definitions along with the name. If PATTR is 244 non-zero, it indicates we're being called from `export' or `readonly'. 245 In POSIX mode, this prints the name of the calling builtin (`export' 246 or `readonly') instead of `declare', and doesn't print function defs 247 when called by `export' or `readonly'. */ 248int 249show_var_attributes (var, pattr, nodefs) 250 SHELL_VAR *var; 251 int pattr, nodefs; 252{ 253 char flags[8], *x; 254 int i; 255 256 i = 0; 257 258 /* pattr == 0 means we are called from `declare'. */ 259 if (pattr == 0 || posixly_correct == 0) 260 { 261#if defined (ARRAY_VARS) 262 if (array_p (var)) 263 flags[i++] = 'a'; 264#endif 265 266 if (function_p (var)) 267 flags[i++] = 'f'; 268 269 if (integer_p (var)) 270 flags[i++] = 'i'; 271 272 if (readonly_p (var)) 273 flags[i++] = 'r'; 274 275 if (trace_p (var)) 276 flags[i++] = 't'; 277 278 if (exported_p (var)) 279 flags[i++] = 'x'; 280 } 281 else 282 { 283#if defined (ARRAY_VARS) 284 if (array_p (var)) 285 flags[i++] = 'a'; 286#endif 287 288 if (function_p (var)) 289 flags[i++] = 'f'; 290 } 291 292 flags[i] = '\0'; 293 294 /* If we're printing functions with definitions, print the function def 295 first, then the attributes, instead of printing output that can't be 296 reused as input to recreate the current state. */ 297 if (function_p (var) && nodefs == 0 && (pattr == 0 || posixly_correct == 0)) 298 { 299 printf ("%s\n", named_function_string (var->name, function_cell (var), 1)); 300 nodefs++; 301 if (pattr == 0 && i == 1 && flags[0] == 'f') 302 return 0; /* don't print `declare -f name' */ 303 } 304 305 if (pattr == 0 || posixly_correct == 0) 306 printf ("declare -%s ", i ? flags : "-"); 307 else if (i) 308 printf ("%s -%s ", this_command_name, flags); 309 else 310 printf ("%s ", this_command_name); 311 312#if defined (ARRAY_VARS) 313 if (array_p (var)) 314 print_array_assignment (var, 1); 315 else 316#endif 317 /* force `readonly' and `export' to not print out function definitions 318 when in POSIX mode. */ 319 if (nodefs || (function_p (var) && pattr != 0 && posixly_correct)) 320 printf ("%s\n", var->name); 321 else if (function_p (var)) 322 printf ("%s\n", named_function_string (var->name, function_cell (var), 1)); 323 else if (invisible_p (var)) 324 printf ("%s\n", var->name); 325 else 326 { 327 x = sh_double_quote (var_isset (var) ? value_cell (var) : ""); 328 printf ("%s=%s\n", var->name, x); 329 free (x); 330 } 331 return (0); 332} 333 334int 335show_name_attributes (name, nodefs) 336 char *name; 337 int nodefs; 338{ 339 SHELL_VAR *var; 340 341 var = find_variable_internal (name, 1); 342 343 if (var && invisible_p (var) == 0) 344 { 345 show_var_attributes (var, READONLY_OR_EXPORT, nodefs); 346 return (0); 347 } 348 else 349 return (1); 350} 351 352void 353set_var_attribute (name, attribute, undo) 354 char *name; 355 int attribute, undo; 356{ 357 SHELL_VAR *var, *tv; 358 char *tvalue; 359 360 if (undo) 361 var = find_variable (name); 362 else 363 { 364 tv = find_tempenv_variable (name); 365 /* XXX -- need to handle case where tv is a temp variable in a 366 function-scope context, since function_env has been merged into 367 the local variables table. */ 368 if (tv && tempvar_p (tv)) 369 { 370 tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring (""); 371 372 var = bind_variable (tv->name, tvalue, 0); 373 var->attributes |= tv->attributes & ~att_tempvar; 374 VSETATTR (tv, att_propagate); 375 if (var->context != 0) 376 VSETATTR (var, att_propagate); 377 SETVARATTR (tv, attribute, undo); /* XXX */ 378 379 stupidly_hack_special_variables (tv->name); 380 381 free (tvalue); 382 } 383 else 384 { 385 var = find_variable_internal (name, 0); 386 if (var == 0) 387 { 388 var = bind_variable (name, (char *)NULL, 0); 389 VSETATTR (var, att_invisible); 390 } 391 else if (var->context != 0) 392 VSETATTR (var, att_propagate); 393 } 394 } 395 396 if (var) 397 SETVARATTR (var, attribute, undo); 398 399 if (var && (exported_p (var) || (attribute & att_exported))) 400 array_needs_making++; /* XXX */ 401} 402