X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=arrayfunc.c;h=6bc248a7d0b0512948fae3ba14a3cd4dbae8d130;hb=f1be666c7d78939ad775078d290bec2758fa29a2;hp=4fe4f33390e232e76c1e8a62a0782c637f24d517;hpb=f73dda092b33638d2d5e9c35375f687a607b5403;p=platform%2Fupstream%2Fbash.git diff --git a/arrayfunc.c b/arrayfunc.c index 4fe4f33..6bc248a 100644 --- a/arrayfunc.c +++ b/arrayfunc.c @@ -1,6 +1,6 @@ /* arrayfunc.c -- High-level array functions used by other parts of the shell. */ -/* Copyright (C) 2001 Free Software Foundation, Inc. +/* Copyright (C) 2001-2006 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -27,14 +27,25 @@ #endif #include +#include "bashintl.h" + #include "shell.h" + +#include "shmbutil.h" + #include "builtins/common.h" extern char *this_command_name; extern int last_command_exit_value; +extern int array_needs_making; + +static SHELL_VAR *bind_array_var_internal __P((SHELL_VAR *, arrayind_t, char *, int)); static void quote_array_assignment_chars __P((WORD_LIST *)); -static char *array_value_internal __P((char *, int, int)); +static char *array_value_internal __P((char *, int, int, int *)); + +/* Standard error message to use when encountering an invalid array subscript */ +char *bash_badsub_errmsg = N_("bad array subscript"); /* **************************************************************** */ /* */ @@ -52,13 +63,20 @@ convert_var_to_array (var) ARRAY *array; oldval = value_cell (var); - array = new_array (); - array_add_element (array, 0, oldval); + array = array_create (); + if (oldval) + array_insert (array, 0, oldval); FREE (value_cell (var)); - var->value = (char *)array; + var_setarray (var, array); + + /* these aren't valid anymore */ + var->dynamic_value = (sh_var_value_func_t *)NULL; + var->assign_func = (sh_var_assign_func_t *)NULL; INVALIDATE_EXPORTSTR (var); + if (exported_p (var)) + array_needs_making++; VSETATTR (var, att_array); VUNSETATTR (var, att_invisible); @@ -66,6 +84,49 @@ convert_var_to_array (var) return var; } +static SHELL_VAR * +bind_array_var_internal (entry, ind, value, flags) + SHELL_VAR *entry; + arrayind_t ind; + char *value; + int flags; +{ + SHELL_VAR *dentry; + char *newval; + + /* If we're appending, we need the old value of the array reference, so + fake out make_variable_value with a dummy SHELL_VAR */ + if (flags & ASS_APPEND) + { + dentry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + dentry->name = savestring (entry->name); + newval = array_reference (array_cell (entry), ind); + if (newval) + dentry->value = savestring (newval); + else + { + dentry->value = (char *)xmalloc (1); + dentry->value[0] = '\0'; + } + dentry->exportstr = 0; + dentry->attributes = entry->attributes & ~(att_array|att_exported); + /* Leave the rest of the members uninitialized; the code doesn't look + at them. */ + newval = make_variable_value (dentry, value, flags); + dispose_variable (dentry); + } + else + newval = make_variable_value (entry, value, flags); + + if (entry->assign_func) + (*entry->assign_func) (entry, newval, ind); + else + array_insert (array_cell (entry), ind, newval); + FREE (newval); + + return (entry); +} + /* Perform an array assignment name[ind]=value. If NAME already exists and is not an array, and IND is 0, perform name=value instead. If NAME exists and is not an array, and IND is not 0, convert it into an array with the @@ -74,13 +135,13 @@ convert_var_to_array (var) If NAME does not exist, just create an array variable, no matter what IND's value may be. */ SHELL_VAR * -bind_array_variable (name, ind, value) +bind_array_variable (name, ind, value, flags) char *name; arrayind_t ind; char *value; + int flags; { SHELL_VAR *entry; - char *newval; entry = var_lookup (name, shell_variables); @@ -89,28 +150,22 @@ bind_array_variable (name, ind, value) else if (readonly_p (entry) || noassign_p (entry)) { if (readonly_p (entry)) - report_error ("%s: readonly variable", name); + err_readonly (name); return (entry); } else if (array_p (entry) == 0) entry = convert_var_to_array (entry); /* ENTRY is an array variable, and ARRAY points to the value. */ - newval = make_variable_value (entry, value); - if (entry->assign_func) - (*entry->assign_func) (entry, ind, newval); - else - array_add_element (array_cell (entry), ind, newval); - FREE (newval); - - return (entry); + return (bind_array_var_internal (entry, ind, value, flags)); } /* Parse NAME, a lhs of an assignment statement of the form v[s], and assign VALUE to that array element by calling bind_array_variable(). */ SHELL_VAR * -assign_array_element (name, value) +assign_array_element (name, value, flags) char *name, *value; + int flags; { char *sub, *vname; arrayind_t ind; @@ -125,7 +180,7 @@ assign_array_element (name, value) if ((ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']') || (sublen <= 1)) { free (vname); - report_error ("%s: bad array subscript", name); + err_badarraysub (name); return ((SHELL_VAR *)NULL); } @@ -133,11 +188,11 @@ assign_array_element (name, value) if (ind < 0) { free (vname); - report_error ("%s: bad array subscript", name); + err_badarraysub (name); return ((SHELL_VAR *)NULL); } - entry = bind_array_variable (vname, ind, value); + entry = bind_array_variable (vname, ind, value, flags); free (vname); return (entry); @@ -162,7 +217,7 @@ find_or_make_array_variable (name, check_flags) else if (check_flags && (readonly_p (var) || noassign_p (var))) { if (readonly_p (var)) - report_error ("%s: readonly variable", name); + err_readonly (name); return ((SHELL_VAR *)NULL); } else if (array_p (var) == 0) @@ -174,8 +229,9 @@ find_or_make_array_variable (name, check_flags) /* Perform a compound assignment statement for array NAME, where VALUE is the text between the parens: NAME=( VALUE ) */ SHELL_VAR * -assign_array_from_string (name, value) +assign_array_from_string (name, value, flags) char *name, *value; + int flags; { SHELL_VAR *var; @@ -183,53 +239,48 @@ assign_array_from_string (name, value) if (var == 0) return ((SHELL_VAR *)NULL); - return (assign_array_var_from_string (var, value)); + return (assign_array_var_from_string (var, value, flags)); } /* Sequentially assign the indices of indexed array variable VAR from the words in LIST. */ SHELL_VAR * -assign_array_var_from_word_list (var, list) +assign_array_var_from_word_list (var, list, flags) SHELL_VAR *var; WORD_LIST *list; + int flags; { register arrayind_t i; register WORD_LIST *l; ARRAY *a; - for (a = array_cell (var), l = list, i = 0; l; l = l->next, i++) + a = array_cell (var); + i = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0; + + for (l = list; l; l = l->next, i++) if (var->assign_func) - (*var->assign_func) (var, i, l->word->word); + (*var->assign_func) (var, l->word->word, i); else - array_add_element (a, i, l->word->word); + array_insert (a, i, l->word->word); return var; } -/* Perform a compound array assignment: VAR->name=( VALUE ). The - VALUE has already had the parentheses stripped. */ -SHELL_VAR * -assign_array_var_from_string (var, value) - SHELL_VAR *var; +WORD_LIST * +expand_compound_array_assignment (value, flags) char *value; + int flags; { - ARRAY *a; WORD_LIST *list, *nlist; - char *w, *val, *nval; - int ni, len; - arrayind_t ind, last_ind; + char *val; + int ni; - if (value == 0) - return var; - - /* If this is called from declare_builtin, value[0] == '(' and - strchr(value, ')') != 0. In this case, we need to extract - the value from between the parens before going on. */ + /* I don't believe this condition is ever true any more. */ if (*value == '(') /*)*/ { ni = 1; val = extract_array_assignment_list (value, &ni); if (val == 0) - return var; + return (WORD_LIST *)NULL; } else val = value; @@ -238,7 +289,7 @@ assign_array_var_from_string (var, value) shell expansions including pathname generation and word splitting. */ /* First we split the string on whitespace, using the shell parser (ksh93 seems to do this). */ - list = parse_string_to_word_list (val, "array assign"); + list = parse_string_to_word_list (val, 1, "array assign"); /* If we're using [subscript]=value, we need to quote each [ and ] to prevent unwanted filename expansion. */ @@ -254,29 +305,47 @@ assign_array_var_from_string (var, value) if (val != value) free (val); + return nlist; +} + +void +assign_compound_array_list (var, nlist, flags) + SHELL_VAR *var; + WORD_LIST *nlist; + int flags; +{ + ARRAY *a; + WORD_LIST *list; + char *w, *val, *nval; + int len, iflags; + arrayind_t ind, last_ind; + a = array_cell (var); /* Now that we are ready to assign values to the array, kill the existing value. */ - if (a) - empty_array (a); + if (a && (flags & ASS_APPEND) == 0) + array_flush (a); + last_ind = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0; - for (last_ind = 0, list = nlist; list; list = list->next) + for (list = nlist; list; list = list->next) { + iflags = flags; w = list->word->word; /* We have a word of the form [ind]=value */ - if (w[0] == '[') + if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[') { len = skipsubscript (w, 0); - if (w[len] != ']' || w[len+1] != '=') + /* XXX - changes for `+=' */ + if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '='))) { - nval = make_variable_value (var, w); + nval = make_variable_value (var, w, flags); if (var->assign_func) - (*var->assign_func) (var, last_ind, nval); + (*var->assign_func) (var, nval, last_ind); else - array_add_element (a, last_ind, nval); + array_insert (a, last_ind, nval); FREE (nval); last_ind++; continue; @@ -284,24 +353,31 @@ assign_array_var_from_string (var, value) if (len == 1) { - report_error ("%s: bad array subscript", w); + err_badarraysub (w); continue; } if (ALL_ELEMENT_SUB (w[1]) && len == 2) { - report_error ("%s: cannot assign to non-numeric index", w); + report_error (_("%s: cannot assign to non-numeric index"), w); continue; } ind = array_expand_index (w + 1, len); if (ind < 0) { - report_error ("%s: bad array subscript", w); + err_badarraysub (w); continue; } last_ind = ind; - val = w + len + 2; + /* XXX - changes for `+=' -- just accept the syntax. ksh93 doesn't do this */ + if (w[len + 1] == '+' && w[len + 2] == '=') + { + iflags |= ASS_APPEND; + val = w + len + 3; + } + else + val = w + len + 2; } else /* No [ind]=value, just a stray `=' */ { @@ -311,16 +387,29 @@ assign_array_var_from_string (var, value) if (integer_p (var)) this_command_name = (char *)NULL; /* no command name for errors */ - nval = make_variable_value (var, val); - if (var->assign_func) - (*var->assign_func) (var, ind, nval); - else - array_add_element (a, ind, nval); - FREE (nval); + bind_array_var_internal (var, ind, val, iflags); last_ind++; } +} + +/* Perform a compound array assignment: VAR->name=( VALUE ). The + VALUE has already had the parentheses stripped. */ +SHELL_VAR * +assign_array_var_from_string (var, value, flags) + SHELL_VAR *var; + char *value; + int flags; +{ + WORD_LIST *nlist; + + if (value == 0) + return var; + + nlist = expand_compound_array_assignment (value, flags); + assign_compound_array_list (var, nlist, flags); - dispose_words (nlist); + if (nlist) + dispose_words (nlist); return (var); } @@ -340,7 +429,7 @@ quote_array_assignment_chars (list) if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0') continue; /* should not happen, but just in case... */ /* Don't bother if it doesn't look like [ind]=value */ - if (l->word->word[0] != '[' || strchr (l->word->word, '=') == 0) /* ] */ + if (l->word->word[0] != '[' || xstrchr (l->word->word, '=') == 0) /* ] */ continue; s = nword = (char *)xmalloc (strlen (l->word->word) * 2 + 1); saw_eq = 0; @@ -366,14 +455,54 @@ skipsubscript (s, i) int i; { int count, c; +#if defined (HANDLE_MULTIBYTE) + mbstate_t state, state_bak; + size_t slength, mblength; +#endif - for (count = 1; count && (c = s[++i]); ) +#if defined (HANDLE_MULTIBYTE) + memset (&state, '\0', sizeof (mbstate_t)); + slength = strlen (s + i); +#endif + + count = 1; + while (count) { - if (c == '[') + /* Advance one (possibly multibyte) character in S starting at I. */ +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1) + { + state_bak = state; + mblength = mbrlen (s + i, slength, &state); + + if (MB_INVALIDCH (mblength)) + { + state = state_bak; + i++; + slength--; + } + else if (MB_NULLWCH (mblength)) + return i; + else + { + i += mblength; + slength -= mblength; + } + } + else +#endif + ++i; + + c = s[i]; + + if (c == 0) + break; + else if (c == '[') count++; else if (c == ']') count--; } + return i; } @@ -392,25 +521,25 @@ unbind_array_element (var, sub) len = skipsubscript (sub, 0); if (sub[len] != ']' || len == 0) { - builtin_error ("%s[%s: bad array subscript", var->name, sub); + builtin_error ("%s[%s: %s", var->name, sub, _(bash_badsub_errmsg)); return -1; } sub[len] = '\0'; if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0) { - makunbound (var->name, shell_variables); + unbind_variable (var->name); return (0); } ind = array_expand_index (sub, len+1); if (ind < 0) { - builtin_error ("[%s]: bad array subscript", sub); + builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg)); return -1; } - ae = array_delete_element (array_cell (var), ind); + ae = array_remove (array_cell (var), ind); if (ae) - destroy_array_element (ae); + array_dispose_element (ae); return 0; } @@ -423,10 +552,7 @@ print_array_assignment (var, quoted) { char *vstr; - if (quoted) - vstr = quoted_array_assignment_string (array_cell (var)); - else - vstr = array_to_assignment_string (array_cell (var)); + vstr = array_to_assign (array_cell (var), quoted); if (vstr == 0) printf ("%s=%s\n", var->name, quoted ? "'()'" : "()"); @@ -451,7 +577,7 @@ valid_array_reference (name) char *t; int r, len; - t = strchr (name, '['); /* ] */ + t = xstrchr (name, '['); /* ] */ if (t) { *t = '\0'; @@ -484,7 +610,7 @@ array_expand_index (s, len) exp = (char *)xmalloc (len); strncpy (exp, s, len - 1); exp[len - 1] = '\0'; - t = expand_string_to_string (exp, 0); + t = expand_arith_string (exp, 0); this_command_name = (char *)NULL; val = evalexp (t, &expok); free (t); @@ -492,6 +618,8 @@ array_expand_index (s, len) if (expok == 0) { last_command_exit_value = EXECUTION_FAILURE; + + top_level_cleanup (); jump_to_top_level (DISCARD); } return val; @@ -509,14 +637,24 @@ array_variable_name (s, subp, lenp) char *t, *ret; int ind, ni; - t = strchr (s, '['); + t = xstrchr (s, '['); if (t == 0) - return ((char *)NULL); + { + if (subp) + *subp = t; + if (lenp) + *lenp = 0; + return ((char *)NULL); + } ind = t - s; ni = skipsubscript (s, ind); if (ni <= ind + 1 || s[ni] != ']') { - report_error ("%s: bad array subscript", s); + err_badarraysub (s); + if (subp) + *subp = t; + if (lenp) + *lenp = 0; return ((char *)NULL); } @@ -549,16 +687,18 @@ array_variable_part (s, subp, lenp) var = find_variable (t); free (t); - return var; + return (var == 0 || invisible_p (var)) ? (SHELL_VAR *)0 : var; } /* Return a string containing the elements in the array and subscript described by S. If the subscript is * or @, obeys quoting rules akin - to the expansion of $* and $@ including double quoting. */ + to the expansion of $* and $@ including double quoting. If RTYPE + is non-null it gets 1 if the array reference is name[@] or name[*] + and 0 otherwise. */ static char * -array_value_internal (s, quoted, allow_all) +array_value_internal (s, quoted, allow_all, rtype) char *s; - int quoted, allow_all; + int quoted, allow_all, *rtype; { int len; arrayind_t ind; @@ -568,22 +708,30 @@ array_value_internal (s, quoted, allow_all) var = array_variable_part (s, &t, &len); + /* Expand the index, even if the variable doesn't exist, in case side + effects are needed, like ${w[i++]} where w is unset. */ +#if 0 if (var == 0) return (char *)NULL; +#endif + + if (len == 0) + return ((char *)NULL); /* error message already printed */ /* [ */ if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') { + if (rtype) + *rtype = (t[0] == '*') ? 1 : 2; if (allow_all == 0) { - report_error ("%s: bad array subscript", s); + err_badarraysub (s); return ((char *)NULL); } + else if (var == 0 || value_cell (var) == 0) + return ((char *)NULL); else if (array_p (var) == 0) - { - l = (WORD_LIST *)NULL; - l = add_string_to_list (value_cell (var), l); - } + l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL); else { l = array_to_word_list (array_cell (var)); @@ -604,17 +752,26 @@ array_value_internal (s, quoted, allow_all) } else { + if (rtype) + *rtype = 0; ind = array_expand_index (t, len); if (ind < 0) { - report_error ("%s: bad array subscript", var->name); + if (var) + err_badarraysub (var->name); + else + { + t[-1] = '\0'; + err_badarraysub (s); + t[-1] = '['; /* ] */ + } return ((char *)NULL); } + if (var == 0) + return ((char *)NULL); if (array_p (var) == 0) - return (ind == 0 ? savestring (value_cell (var)) : (char *)NULL); + return (ind == 0 ? value_cell (var) : (char *)NULL); retval = array_reference (array_cell (var), ind); - if (retval) - retval = quote_escapes (retval); } return retval; @@ -623,11 +780,11 @@ array_value_internal (s, quoted, allow_all) /* Return a string containing the elements described by the array and subscript contained in S, obeying quoting for subscripts * and @. */ char * -array_value (s, quoted) +array_value (s, quoted, rtype) char *s; - int quoted; + int quoted, *rtype; { - return (array_value_internal (s, quoted, 1)); + return (array_value_internal (s, quoted, 1, rtype)); } /* Return the value of the array indexing expression S as a single string. @@ -635,11 +792,48 @@ array_value (s, quoted) by other parts of the shell such as the arithmetic expression evaluator in expr.c. */ char * -get_array_value (s, allow_all) +get_array_value (s, allow_all, rtype) char *s; - int allow_all; + int allow_all, *rtype; { - return (array_value_internal (s, 0, allow_all)); + return (array_value_internal (s, 0, allow_all, rtype)); } +char * +array_keys (s, quoted) + char *s; + int quoted; +{ + int len; + char *retval, *t, *temp; + WORD_LIST *l; + SHELL_VAR *var; + + var = array_variable_part (s, &t, &len); + + /* [ */ + if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']') + return (char *)NULL; + + if (array_p (var) == 0) + l = add_string_to_list ("0", (WORD_LIST *)NULL); + else + { + l = array_keys_to_word_list (array_cell (var)); + if (l == (WORD_LIST *)NULL) + return ((char *) NULL); + } + + if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + { + temp = string_list_dollar_star (l); + retval = quote_string (temp); + free (temp); + } + else /* ${!name[@]} or unquoted ${!name[*]} */ + retval = string_list_dollar_at (l, quoted); + + dispose_words (l); + return retval; +} #endif /* ARRAY_VARS */