- wait_for: make checkwinsize work in subshell commands started from
interactive shells
New feature request by Kerin Millar <kfm@plushkava.net>
+
+print_cmd.c
+ - semicolon: don't return immediately unless a preceding `&' is
+ itself preceded by a space, as the rest of the printing code prints
+ asynchronous commands.
+ Report and patch by Grisha Levit <grishalevit@gmail.com>
+
+ 6/17
+ ----
+arrayfunc.c
+ - arrayvar_copyval: copy an array or hash table from shell variable
+ V1 to V2
+
+arrayfunc.h
+ - arrayvar_copyval: extern declaration
+
+subst.h
+ - ASS_NOTEMPENV: new flag for bind_variable and assignments
+
+variables.c
+ - bind_variable: if ASS_NOTEMPENV is in FLAGS, don't bother calling
+ bind_tempenv_variable
+
+builtins/declare.def
+ - declare_internal: if we find the variable in the temporary
+ environment, call bind_variable with the ASS_NOTEMPENV flag since
+ we are already dealing with a variable from the temporary environment
+ - declare_internal: if we bind a new global variable because we're
+ modifying a variable from the temporary environment, make sure to
+ call arrayvar_copyval to copy array variables from the temporary
+ environment to the global scope
+
+variables.c
+ - push_temp_var: if we are pushing an array variable, make sure to
+ call arrayvar_copyval on the new variable
+ Final fix for bug reported by Wiley Young <wyeth2485@gmail.com>
+ - push_posix_tempvar_internal: call arrayar_copyval instead of using
+ inline code
+
+
return var;
}
+/* Copy the array (ARRAY *) or assoc (HASH_TABLE *) from variable V1 to V2,
+ and return V2. */
+SHELL_VAR *
+arrayvar_copyval (SHELL_VAR *v1, SHELL_VAR *v2)
+{
+ FREE (value_cell (v2));
+ if (array_p (v1))
+ var_setarray (v2, array_copy (array_cell (v1)));
+ else if (assoc_p (v1))
+ var_setassoc (v2, assoc_copy (assoc_cell (v1)));
+ return v2;
+}
+
char *
make_array_variable_value (SHELL_VAR *entry, arrayind_t ind, const char *key, const char *value, int flags)
{
extern SHELL_VAR *convert_var_to_array (SHELL_VAR *);
extern SHELL_VAR *convert_var_to_assoc (SHELL_VAR *);
+extern SHELL_VAR *arrayvar_copyval (SHELL_VAR *, SHELL_VAR *);
+
extern char *make_array_variable_value (SHELL_VAR *, arrayind_t, const char *, const char *, int);
extern SHELL_VAR *bind_array_variable (const char *, arrayind_t, const char *, int);
if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var))
{
SHELL_VAR *tv;
- char *tvalue;
/* Temporary environment? Or in the local variable context? */
tv = find_tempenv_variable (name_cell (var));
if (tv)
{
- tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring ("");
- tv = bind_variable (name_cell (var), tvalue, 0);
+ /* We don't bother with modifying the temporary env because
+ we're already using it. */
+ tv = bind_variable (name_cell (var), value_cell (var), ASS_NOTEMPENV);
+
if (tv)
{
+#if defined (ARRAY_VARS)
+ /* copy array value if array variable */
+ if ((array_p (var) || assoc_p (var)))
+ arrayvar_copyval (var, tv);
+#endif
+ /* then copy attributes */
tv->attributes |= var->attributes & ~att_tempvar;
if (tv->context > 0 && local_p (var) == 0) /* just paranoia here */
VSETATTR (tv, att_propagate);
}
- free (tvalue);
}
/* XXX - don't propagate local variables back to a previous scope,
even in posix mode. */
group_command_nesting++;
cprintf ("{ ");
- if (inside_function_def == 0)
+ if (inside_function_def == 0 /* && pretty_print_mode == 0 */)
skip_this_indent++;
else
{
make_command_string_internal (group_command->command);
PRINT_DEFERRED_HEREDOCS ("");
- if (inside_function_def)
+ if (inside_function_def /* || pretty_print_mode */)
{
cprintf ("\n");
indentation -= indentation_amount;
static void
semicolon (void)
{
- if (command_string_index > 0 &&
- (the_printed_command[command_string_index - 1] == '&' ||
- the_printed_command[command_string_index - 1] == '\n'))
+ if ((command_string_index > 0 &&
+ the_printed_command[command_string_index - 1] == '\n') ||
+ (command_string_index > 1 &&
+ the_printed_command[command_string_index - 1] == '&' &&
+ the_printed_command[command_string_index - 2] == ' '))
return;
cprintf (";");
}
extern int shell_compatibility_level;
extern int running_under_emacs;
+extern int pretty_print_mode;
+
extern int posixly_correct;
extern int no_line_editing;
#define ASS_NOINVIS 0x0400 /* don't resolve local invisible variables */
#define ASS_ALLOWALLSUB 0x0800 /* allow * and @ as associative array keys */
#define ASS_ONEWORD 0x1000 /* don't check array subscripts, assume higher level has done that */
+#define ASS_NOTEMPENV 0x2000 /* don't assign into temporary environment */
/* Flags for the string extraction functions. */
#define SX_NOALLOC 0x0001 /* just skip; don't return substring */
static SHELL_VAR *make_new_variable (const char *, HASH_TABLE *);
static SHELL_VAR *bind_variable_internal (const char *, const char *, HASH_TABLE *, int, int);
+static void init_shell_variable (SHELL_VAR *);
+
static void dispose_variable_value (SHELL_VAR *);
static void free_variable_hash_data (PTR_T);
new_var = make_new_variable (name, vc->table);
else
{
+#if 0
+ /* This handles the case where a variable is found in both the temporary
+ environment *and* declared as a local variable. If we want to avoid
+ multiple entries with the same name in VC->table (that might mess up
+ unset), we need to use the existing variable entry and destroy the
+ current value. Currently disabled because it doesn't matter -- the
+ right things happen. */
+ new_var = 0;
+ if (was_tmpvar && (new_var = hash_lookup (name, vc->table)))
+ {
+ dispose_variable_value (new_var);
+ init_variable (new_var);
+ }
+ if (new_var == 0)
+#endif
new_var = make_new_variable (name, vc->table);
/* If we found this variable in one of the temporary environments,
return (new_var);
}
-/* Create a new shell variable with name NAME. */
-static SHELL_VAR *
-new_shell_variable (const char *name)
+static void
+init_variable (SHELL_VAR *entry)
{
- SHELL_VAR *entry;
-
- entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
-
- entry->name = savestring (name);
var_setvalue (entry, (char *)NULL);
CLEAR_EXPORTSTR (entry);
make_local_variable has the responsibility of changing the
variable context. */
entry->context = 0;
+}
+/* Create a new shell variable with name NAME. */
+static SHELL_VAR *
+new_shell_variable (const char *name)
+{
+ SHELL_VAR *entry;
+
+ entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
+
+ entry->name = savestring (name);
+ init_variable (entry);
return (entry);
}
and, if found, modify the value there before modifying it in the
shell_variables table. This allows sourced scripts to modify values
given to them in a temporary environment while modifying the variable
- value that the caller sees. */
- if (temporary_env && value) /* XXX - can value be null here? */
+ value that the caller sees. The caller can inhibit this by setting
+ ASS_NOTEMPENV in FLAGS. */
+ if (temporary_env && value && (flags & ASS_NOTEMPENV) == 0) /* XXX - can value be null here? */
bind_tempenv_variable (name, value);
/* XXX -- handle local variables here. */
v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, ASS_FORCE|ASS_NOLONGJMP);
+#if defined (ARRAY_VARS)
+ if (v && (array_p (var) || assoc_p (var)))
+ arrayvar_copyval (var, v);
+#endif
+
/* XXX - should we set the context here? It shouldn't matter because of how
assign_in_env works, but we do it anyway. */
if (v)
set_current_options (value_cell (var));
set_shellopts ();
}
+
/* This takes variable assignments preceding special builtins that can execute
multiple commands (source, eval, etc.) and performs the equivalent of
an assignment statement to modify the closest enclosing variable (the
#if defined (ARRAY_VARS)
if (v && (array_p (var) || assoc_p (var)))
- {
- FREE (value_cell (v));
- if (array_p (var))
- var_setarray (v, array_copy (array_cell (var)));
- else
- var_setassoc (v, assoc_copy (assoc_cell (var)));
- }
-#endif
+ arrayvar_copyval (var, v);
+#endif
dispose_variable (var);
}