diff options
author | Jari Aalto <jari.aalto@cante.net> | 1997-06-05 14:59:13 +0000 |
---|---|---|
committer | Jari Aalto <jari.aalto@cante.net> | 2009-09-12 16:46:50 +0000 |
commit | d166f048818e10cf3799aa24a174fb22835f1acc (patch) | |
tree | 1ca27f9243900f8b236d0cde6a3862002aea9e19 /subst.c | |
parent | ccc6cda312fea9f0468ee65b8f368e9653e1380b (diff) | |
download | bash-d166f048818e10cf3799aa24a174fb22835f1acc.tar.gz |
Imported from ../bash-2.01.tar.gz.
Diffstat (limited to 'subst.c')
-rw-r--r-- | subst.c | 347 |
1 files changed, 243 insertions, 104 deletions
@@ -43,6 +43,10 @@ #include "pathexp.h" #include "mailcheck.h" +#if !defined (HAVE_RESTARTABLE_SYSCALLS) /* for getc_with_restart */ +#include "input.h" +#endif + #include "builtins/getopt.h" #include "builtins/common.h" @@ -65,12 +69,14 @@ extern int errno; #endif /* !errno */ /* The size that strings change by. */ +#define DEFAULT_INITIAL_ARRAY_SIZE 112 #define DEFAULT_ARRAY_SIZE 128 /* Variable types. */ #define VT_VARIABLE 0 #define VT_POSPARMS 1 #define VT_ARRAYVAR 2 +#define VT_ARRAYMEMBER 3 /* Flags for quoted_strchr */ #define ST_BACKSL 0x01 @@ -274,6 +280,7 @@ quote_escapes (string) return (result); } +#ifdef INCLUDE_UNUSED static char * dequote_escapes (string) char *string; @@ -295,6 +302,7 @@ dequote_escapes (string) *t = '\0'; return result; } +#endif /* Extract a substring from STRING, starting at SINDEX and ending with one of the characters in CHARLIST. Don't make the ending character @@ -1473,6 +1481,30 @@ maybe_expand_string (string, quoted, func) return ret; } +static inline char * +expand_string_to_string (string, quoted, func) + char *string; + int quoted; + WORD_LIST *(*func)(); +{ + WORD_LIST *list; + char *ret; + + if (string == 0 || *string == '\0') + return ((char *)NULL); + + list = (*func) (string, quoted); + if (list) + { + ret = string_list (list); + dispose_words (list); + } + else + ret = (char *)NULL; + + return (ret); +} + #if defined (ARRAY_VARS) SHELL_VAR * do_array_element_assignment (name, value) @@ -1559,7 +1591,10 @@ do_assignment_internal (string, expand) } if (value == 0) - value = savestring (""); + { + value = xmalloc (1); + value[0] = '\0'; + } if (echo_command_at_execute) #if defined (ARRAY_VARS) @@ -1569,7 +1604,7 @@ do_assignment_internal (string, expand) #endif fprintf (stderr, "%s%s=%s\n", indirection_level_string (), name, value); -#define ASSIGN_RETURN(r) FREE (value); free (name); return (r); +#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0) #if defined (ARRAY_VARS) if (t = strchr (name, '[')) @@ -1734,9 +1769,16 @@ call_expand_word_internal (w, q, c, e) result = expand_word_internal (w, q, c, e); if (result == &expand_word_error) - jump_to_top_level (DISCARD); + { + /* By convention, each time this error is returned, w->word has + already been freed. */ + w->word = (char *)NULL; + jump_to_top_level (DISCARD); + /* NOTREACHED */ + } else if (result == &expand_word_fatal) jump_to_top_level (FORCE_EOF); + /* NOTREACHED */ else return (result); } @@ -1754,7 +1796,7 @@ expand_string_internal (string, quoted) if (string == 0 || *string == 0) return ((WORD_LIST *)NULL); - bzero (&td, sizeof (td)); + bzero ((char *)&td, sizeof (td)); td.word = string; tresult = call_expand_word_internal (&td, quoted, (int *)NULL, (int *)NULL); return (tresult); @@ -1825,7 +1867,7 @@ expand_string_for_rhs (string, quoted, dollar_at_p, has_dollar_at) if (string == 0 || *string == '\0') return (WORD_LIST *)NULL; - bzero (&td, sizeof (td)); + bzero ((char *)&td, sizeof (td)); td.word = string; tresult = call_expand_word_internal (&td, quoted, dollar_at_p, has_dollar_at); return (tresult); @@ -2079,9 +2121,12 @@ static int match_pattern_char (pat, string) char *pat, *string; { +#if 0 register char *np; int neg; - char c, c1; + char c1; +#endif + char c; if (*string == 0) return (0); @@ -2093,9 +2138,11 @@ match_pattern_char (pat, string) case '\\': return (*string == *pat); case '?': + return (*string != '\0'); case '*': return (1); case '[': +#if 0 for (np = pat; *np != ']'; np++); if (*np == 0) return (*string == '['); @@ -2113,6 +2160,9 @@ match_pattern_char (pat, string) return (1); pat += 2; } +#else + return (*string != '\0'); +#endif } } @@ -2398,7 +2448,7 @@ make_dev_fd_filename (fd) { char *ret; - ret = xmalloc (16); + ret = xmalloc (sizeof (DEV_FD_PREFIX) + 4); sprintf (ret, "%s%d", DEV_FD_PREFIX, fd); add_fifo_list (fd); return (ret); @@ -2449,6 +2499,10 @@ process_substitute (string, open_for_read_in_child) the pipe in the parent, otherwise the read end. */ parent_pipe_fd = fildes[open_for_read_in_child]; child_pipe_fd = fildes[1 - open_for_read_in_child]; + /* Move the parent end of the pipe to some high file descriptor, to + avoid clashes with FDs used by the script. */ + parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64); + pathname = make_dev_fd_filename (parent_pipe_fd); #endif /* HAVE_DEV_FD */ @@ -2560,7 +2614,7 @@ process_substitute (string, open_for_read_in_child) dev_fd_list[parent_pipe_fd] = 0; #endif /* HAVE_DEV_FD */ - result = parse_and_execute (string, "process substitution", 0); + result = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST)); #if !defined (HAVE_DEV_FD) /* Make sure we close the named pipe in the child before we exit. */ @@ -2572,6 +2626,75 @@ process_substitute (string, open_for_read_in_child) } #endif /* PROCESS_SUBSTITUTION */ +static char * +read_comsub (fd, quoted) + int fd, quoted; +{ + char *istring, buf[128], *bufp; + int bufn, istring_index, istring_size, c; + + istring = (char *)NULL; + istring_index = istring_size = bufn = 0; + + /* Read the output of the command through the pipe. */ + while (1) + { + if (fd < 0) + break; + if (--bufn <= 0) + { + while ((bufn = read (fd, buf, sizeof(buf))) < 0 && errno == EINTR) + ; + if (bufn <= 0) + break; + bufp = buf; + } + c = *bufp++; + + /* Add the character to ISTRING, possibly after resizing it. */ + RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE); + + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || c == CTLESC || c == CTLNUL) + istring[istring_index++] = CTLESC; + + istring[istring_index++] = c; + } + + if (istring) + istring[istring_index] = '\0'; + + /* If we read no output, just return now and save ourselves some + trouble. */ + if (istring_index == 0) + { + FREE (istring); + return (char *)NULL; + } + + /* Strip trailing newlines from the output of the command. */ + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + { + while (istring_index > 0) + { + if (istring[istring_index - 1] == '\n') + { + --istring_index; + + /* If the newline was quoted, remove the quoting char. */ + if (istring[istring_index - 1] == CTLESC) + --istring_index; + } + else + break; + } + istring[istring_index] = '\0'; + } + else + strip_trailing (istring, istring_index - 1, 1); + + return istring; +} + /* Perform command substitution on STRING. This returns a string, possibly quoted. */ static char * @@ -2581,10 +2704,8 @@ command_substitute (string, quoted) { pid_t pid, old_pid, old_pipeline_pgrp; char *istring; - int istring_index, istring_size, c, result, fildes[2]; - FILE *istream; + int result, fildes[2]; - istring_index = istring_size = 0; istring = (char *)NULL; /* Don't fork () if there is no need to. In the case of no command to @@ -2678,49 +2799,18 @@ command_substitute (string, quoted) else if (result) exit (EXECUTION_FAILURE); else - exit (parse_and_execute (string, "command substitution", -1)); + exit (parse_and_execute (string, "command substitution", SEVAL_NOHIST)); } else { - istream = fdopen (fildes[0], "r"); - #if defined (JOB_CONTROL) && defined (PGRP_PIPE) close_pgrp_pipe (); #endif /* JOB_CONTROL && PGRP_PIPE */ close (fildes[1]); - if (istream == 0) - { - sys_error ("cannot reopen pipe to command substitution (fd %d)", fildes[0]); - goto error_exit; - } - - /* Read the output of the command through the pipe. */ - while (1) - { -#if !defined (HAVE_RESTARTABLE_SYSCALLS) - c = getc_with_restart (istream); -#else - c = getc (istream); -#endif /* HAVE_RESTARTABLE_SYSCALLS */ - - if (c == EOF) - break; - - /* Add the character to ISTRING, possibly after resizing it. */ - RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE); - - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || c == CTLESC || c == CTLNUL) - istring[istring_index++] = CTLESC; - - istring[istring_index++] = c; - } - - if (istring) - istring[istring_index] = '\0'; + istring = read_comsub (fildes[0], quoted); - fclose (istream); close (fildes[0]); last_command_exit_value = wait_for (pid); @@ -2740,32 +2830,6 @@ command_substitute (string, quoted) give_terminal_to (pipeline_pgrp); #endif /* JOB_CONTROL */ - /* If we read no output, just return now and save ourselves some - trouble. */ - if (istring_index == 0) - goto error_exit; - - /* Strip trailing newlines from the output of the command. */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - { - while (istring_index > 0) - { - if (istring[istring_index - 1] == '\n') - { - --istring_index; - - /* If the newline was quoted, remove the quoting char. */ - if (istring[istring_index - 1] == CTLESC) - --istring_index; - } - else - break; - } - istring[istring_index] = '\0'; - } - else - strip_trailing (istring, 1); - return (istring); } } @@ -2874,6 +2938,7 @@ list_remove_pattern (list, pattern, patspec, type, quoted) { tword = remove_pattern (l->word->word, pattern, patspec); w = make_bare_word (tword); + free (tword); new = make_word_list (w, new); } @@ -2893,7 +2958,8 @@ parameter_list_remove_pattern (value, type, c, quoted) int type, c, quoted; { int patspec; - char *pattern; + char *pattern, *ret; + WORD_LIST *list; patspec = getpatspec (c, value); if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) @@ -2901,7 +2967,11 @@ parameter_list_remove_pattern (value, type, c, quoted) pattern = getpattern (value, quoted, 1); - return (list_remove_pattern (list_rest_of_args (), pattern, patspec, type, quoted)); + list = list_rest_of_args (); + ret = list_remove_pattern (list, pattern, patspec, type, quoted); + dispose_words (list); + FREE (pattern); + return (ret); } #if defined (ARRAY_VARS) @@ -2933,6 +3003,7 @@ array_remove_pattern (value, aspec, aval, c, quoted) if (array_p (var) == 0) { report_error ("%s: bad array subscript", aspec); + FREE (pattern); return ((char *)NULL); } l = array_to_word_list (array_cell (var)); @@ -2948,6 +3019,7 @@ array_remove_pattern (value, aspec, aval, c, quoted) if (ind < 0) { report_error ("%s: bad array subscript", aspec); + FREE (pattern); return ((char *)NULL); } if (array_p (var) == 0 && ind != 0) @@ -2959,8 +3031,14 @@ array_remove_pattern (value, aspec, aval, c, quoted) ret = remove_pattern (aval, pattern, patspec); #endif if (ret) - quote_escapes (ret); + { + t = quote_escapes (ret); + free (ret); + ret = t; + } } + + FREE (pattern); return ret; } @@ -2998,16 +3076,18 @@ array_expand_index (s, len) int len; { char *exp, *t; - int val; + int val, expok; exp = xmalloc (len); strncpy (exp, s, len - 1); exp[len - 1] = '\0'; t = maybe_expand_string (exp, 0, expand_string); this_command_name = (char *)NULL; - val = evalexp (t); + val = evalexp (t, &expok); free (t); free (exp); + if (expok == 0) + jump_to_top_level (DISCARD); return val; } @@ -3085,7 +3165,7 @@ array_value_internal (s, quoted, allow_all) return ((char *)NULL); } if (array_p (var) == 0) - return (ind == 0 ? value_cell (var) : (char *)NULL); + return (ind == 0 ? savestring (value_cell (var)) : (char *)NULL); retval = array_reference (array_cell (var), ind); if (retval) retval = quote_escapes (retval); @@ -3433,7 +3513,7 @@ verify_substring_values (value, substr, vtype, e1p, e2p) int vtype, *e1p, *e2p; { char *t, *temp1; - int len; + int len, expok; #if defined (ARRAY_VARS) ARRAY *a; #endif @@ -3441,13 +3521,16 @@ verify_substring_values (value, substr, vtype, e1p, e2p) t = strchr (substr, ':'); if (t) *t = '\0'; - temp1 = maybe_expand_string (substr, 1, expand_string); - *e1p = evalexp (temp1); + temp1 = maybe_expand_string (substr, Q_DOUBLE_QUOTES, expand_string); + *e1p = evalexp (temp1, &expok); free (temp1); + if (expok == 0) + return (0); switch (vtype) { case VT_VARIABLE: + case VT_ARRAYMEMBER: len = strlen (value); break; case VT_POSPARMS: @@ -3464,13 +3547,18 @@ verify_substring_values (value, substr, vtype, e1p, e2p) if (*e1p < 0) /* negative offsets count from end */ *e1p += len; + if (*e1p >= len || *e1p < 0) + return (0); + if (t) { t++; - temp1 = maybe_expand_string (t, 1, expand_string); + temp1 = maybe_expand_string (t, Q_DOUBLE_QUOTES, expand_string); t[-1] = ':'; - *e2p = evalexp (temp1); + *e2p = evalexp (temp1, &expok); free (temp1); + if (expok == 0) + return (0); if (*e2p < 0) { internal_error ("%s: substring expression < 0", t); @@ -3547,14 +3635,14 @@ get_var_and_type (varname, value, varp, valp) v = array_variable_part (varname, &temp, (int *)0); if (v && array_p (v)) { - if (temp[0] == '@' && temp[1] == ']') + if ((temp[0] == '@' || temp[0] == '*') && temp[1] == ']') { vtype = VT_ARRAYVAR; *valp = (char *)array_cell (v); } else { - vtype = VT_VARIABLE; + vtype = VT_ARRAYMEMBER; *valp = array_value (varname, 1); } *varp = v; @@ -3598,11 +3686,16 @@ parameter_brace_substring (varname, value, substr, quoted) return ((char *)NULL); if (verify_substring_values (val, substr, vtype, &e1, &e2) == 0) - return (&expand_param_error); + { + if (val && vtype == VT_ARRAYMEMBER) + free (val); + return (&expand_param_error); + } switch (vtype) { case VT_VARIABLE: + case VT_ARRAYMEMBER: temp = quoted ? quoted_substring (value, e1, e2) : substring (value, e1, e2); break; case VT_POSPARMS: @@ -3659,7 +3752,10 @@ pat_subst (string, pat, rep, mflags) /* Now copy the unmatched portion of the input string */ if (*str) - strcpy (ret + rptr, str); + { + RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64); + strcpy (ret + rptr, str); + } else ret[rptr] = '\0'; @@ -3736,15 +3832,20 @@ parameter_brace_patsub (varname, value, patsub, quoted) perform word splitting or filename generation. */ pat = maybe_expand_string (patsub, quoted, expand_string_unsplit); if (rep) - rep = maybe_expand_string (rep, quoted, expand_string_unsplit); + { + if ((mflags & MATCH_QUOTED) == 0) + rep = maybe_expand_string (rep, quoted, expand_string_unsplit); + else + rep = expand_string_to_string (rep, quoted, expand_string_unsplit); + } p = pat; - if (pat[0] == '#') + if (pat && pat[0] == '#') { mflags |= MATCH_BEG; p++; } - else if (pat[0] == '%') + else if (pat && pat[0] == '%') { mflags |= MATCH_END; p++; @@ -3758,6 +3859,7 @@ parameter_brace_patsub (varname, value, patsub, quoted) switch (vtype) { case VT_VARIABLE: + case VT_ARRAYMEMBER: temp = pat_subst (val, p, rep, mflags); break; case VT_POSPARMS: @@ -3770,6 +3872,9 @@ parameter_brace_patsub (varname, value, patsub, quoted) #endif } + if (val && v && array_p (v) && vtype == VT_ARRAYMEMBER) + free (val); + FREE (pat); FREE (rep); @@ -4006,7 +4111,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll FREE (temp); free (name); last_command_exit_value = EXECUTION_FAILURE; - return &expand_param_error; + return (interactive_shell ? &expand_param_error : &expand_param_fatal); } break; @@ -4147,11 +4252,13 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) int had_quoted_null; + int expok; + register int c; /* Current character. */ int number; /* Temporary number value. */ int t_index; /* For calls to string_extract_xxx. */ - istring = xmalloc (istring_size = DEFAULT_ARRAY_SIZE); + istring = xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE); istring[istring_index = 0] = '\0'; quoted_dollar_at = had_quoted_null = 0; @@ -4251,7 +4358,7 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) free (string); free (istring); last_command_exit_value = EXECUTION_FAILURE; - return (&expand_word_error); + return (interactive_shell ? &expand_word_error : &expand_word_fatal); } temp = temp1 ? savestring (temp1) : (char *)NULL; goto dollar_add_string; @@ -4404,28 +4511,38 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) if (temp1[t_index] != ')') { +#if 0 report_error ("%s: bad arithmetic substitution", temp); free (temp); free (string); free (istring); - return &expand_word_error; + return (&expand_word_error); +#else + goto comsub; +#endif } /* Cut off ending `)' */ temp1[t_index] = '\0'; /* Expand variables found inside the expression. */ - temp1 = maybe_expand_string (temp1, 1, expand_string); + temp1 = maybe_expand_string (temp1, Q_DOUBLE_QUOTES, expand_string); /* No error messages. */ this_command_name = (char *)NULL; - number = evalexp (temp1); + number = evalexp (temp1, &expok); free (temp); free (temp1); - + if (expok == 0) + { + free (string); + free (istring); + return (&expand_word_error); + } goto add_number; } + comsub: temp1 = command_substitute (temp, quoted); FREE (temp); temp = temp1; @@ -4440,14 +4557,19 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) sindex = t_index; /* Do initial variable expansion. */ - temp1 = maybe_expand_string (temp, 1, expand_string); + temp1 = maybe_expand_string (temp, Q_DOUBLE_QUOTES, expand_string); /* No error messages. */ this_command_name = (char *)NULL; - number = evalexp (temp1); + number = evalexp (temp1, &expok); free (temp1); free (temp); - + if (expok == 0) + { + free (string); + free (istring); + return (&expand_word_error); + } goto add_number; default: @@ -4504,7 +4626,9 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) free (string); last_command_exit_value = EXECUTION_FAILURE; free (istring); - return &expand_word_error; + return ((unbound_vars_is_error && interactive_shell == 0) + ? &expand_word_fatal + : &expand_word_error); } break; /* End case '$': */ @@ -4895,6 +5019,7 @@ word_quote_removal (word, quoted) t = string_quote_removal (word->word, quoted); w = make_bare_word (t); + free (t); return (w); } @@ -5228,6 +5353,7 @@ expand_word_list_internal (list, do_vars) { register char **expansions; WORD_LIST *braces; + WORD_DESC *w; int eindex; for (braces = disposables = (WORD_LIST *)NULL; tlist; tlist = next) @@ -5247,7 +5373,13 @@ expand_word_list_internal (list, do_vars) for (eindex = 0; temp_string = expansions[eindex]; eindex++) { - braces = make_word_list (make_word (temp_string), braces); + w = make_word (temp_string); + /* If brace expansion didn't change the word, preserve + the flags. We may want to preserve the flags + unconditionally someday -- XXX */ + if (STREQ (temp_string, tlist->word->word)) + w->flags = tlist->word->flags; + braces = make_word_list (w, braces); free (expansions[eindex]); } free (expansions); @@ -5306,7 +5438,7 @@ expand_word_list_internal (list, do_vars) /* Dispose our copy of the original list. */ dispose_words (orig_list); - /* Dispose the new list we're building. */ + /* Dispose the new list we're building. */ dispose_words (new_list); if (expanded == &expand_word_error) @@ -5372,9 +5504,13 @@ expand_word_list_internal (list, do_vars) words are freed. */ next = tlist->next; - /* If the word isn't quoted and there is an unquoted pattern - matching character in the word, then glob it. */ + /* If the word isn't an assignment and contains an unquoted + pattern matching character, then glob it. */ +#if 0 if ((tlist->word->flags & (W_QUOTED|W_ASSIGNMENT)) == 0 && +#else + if ((tlist->word->flags & W_ASSIGNMENT) == 0 && +#endif unquoted_glob_pattern_p (tlist->word->word)) { glob_array = shell_glob_filename (tlist->word->word); @@ -5758,6 +5894,7 @@ sv_ignoreeof (name) temp = tmp_var ? value_cell (tmp_var) : (char *)NULL; if (temp) eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10; + set_shellopts (); /* make sure `ignoreeof' is/is not in $SHELLOPTS */ } void @@ -5799,8 +5936,10 @@ sv_strict_posix (name) SET_INT_VAR (name, posixly_correct); posix_initialize (posixly_correct); #if defined (READLINE) - posix_readline_initialize (posixly_correct); + if (interactive_shell) + posix_readline_initialize (posixly_correct); #endif /* READLINE */ + set_shellopts (); /* make sure `posix' is/is not in $SHELLOPTS */ } void |