From 641d8f00aba934981e2ecadd0ea3570947d9f7ad Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Wed, 7 Dec 2011 09:07:29 -0500 Subject: [PATCH] commit bash-20070503 snapshot --- CWRU/CWRU.chlog | 43 +- CWRU/CWRU.chlog~ | 43 ++ builtins/alias.def | 2 +- builtins/bind.def | 2 +- builtins/cd.def | 16 +- builtins/common.c | 13 + builtins/common.h | 1 + builtins/complete.def | 3 +- builtins/declare.def | 15 +- builtins/echo.def | 9 +- builtins/fc.def | 9 +- builtins/history.def | 4 +- builtins/pushd.def | 6 +- builtins/set.def | 8 +- builtins/setattr.def | 8 +- builtins/shopt.def | 14 +- builtins/times.def | 2 +- builtins/trap.def | 4 +- builtins/type.def | 5 +- builtins/ulimit.def | 2 +- builtins/umask.def | 3 +- doc/bash.1 | 12 +- doc/bashref.texi | 11 +- doc/version.texi | 6 +- lib/readline/examples/x | 1 + lib/readline/input.c | 14 +- print_cmd.c | 49 +- print_cmd.c~ | 1322 +++++++++++++++++++++++++++++++++++++++ tests/RUN-ONE-TEST | 2 +- 29 files changed, 1539 insertions(+), 90 deletions(-) create mode 100644 lib/readline/examples/x create mode 100644 print_cmd.c~ diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 50934714a..4e7ea3e8f 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -14537,6 +14537,45 @@ redir.c make sure all output is flushed before changing the underlying fd out from underneath stdio. Fix suggested by Eric Blake + + 4/30 + ---- + +builtins/common.c + - new function, sh_chkwrite(int), fflushes stdout and checks for error; + printing an error message and returning a new exit status if there's + an error on stdout. Takes exit status as argument; returns new exit + status (EXECUTION_FAILURE if write error) + +builtins/common.h + - new extern declaration for sh_chkwrite + +builtins/{alias,cd,complete,echo,fc,history,pushd,shopt,times,trap,type,ulimit,umask}.def + - change to use sh_chkwrite to report write errors + +builtins/fc.def + - if an error occurs while writing commands from the history to a file + to be executed, report a write error and return failure without + attempting to execute any commands + + 5/1 + --- +builtins/{bind,declare,set,setattr}.def + - change to use sh_chkwrite to report write errors + + 5/2 + --- lib/readline/input.c - - fix probable off-by-one error in ibuffer_space () prompted by bug - report from Tom Bjorkholm + - fix off-by-one errors in _rl_get_char (pop_index) and rl_stuff_char + (push_index) that caused the 511th character in the buffer to be + discarded. Fixes bug reported by Tom Bjorkholm + + 5/5 + --- +print_cmd.c + - added logic (inside_pipeline variable) to print_connection code and + print_redirection to handle the case of a command with a here + document inside a pipeline. In that case, print_redirection prints + the `|' before the here document text, so the parser knows the + command is continued. Fixes problem with exporting functions with + pipelines like this reported by Chris Lesner diff --git a/CWRU/CWRU.chlog~ b/CWRU/CWRU.chlog~ index 2329b2246..9aee4086c 100644 --- a/CWRU/CWRU.chlog~ +++ b/CWRU/CWRU.chlog~ @@ -14536,3 +14536,46 @@ redir.c is the same one used by the stdout stream, call fflush(stdout) to make sure all output is flushed before changing the underlying fd out from underneath stdio. Fix suggested by Eric Blake + + + 4/30 + ---- + +builtins/common.c + - new function, sh_chkwrite(int), fflushes stdout and checks for error; + printing an error message and returning a new exit status if there's + an error on stdout. Takes exit status as argument; returns new exit + status (EXECUTION_FAILURE if write error) + +builtins/common.h + - new extern declaration for sh_chkwrite + +builtins/{alias,cd,complete,echo,fc,history,pushd,shopt,times,trap,type,ulimit,umask}.def + - change to use sh_chkwrite to report write errors + +builtins/fc.def + - if an error occurs while writing commands from the history to a file + to be executed, report a write error and return failure without + attempting to execute any commands + + 5/1 + --- +builtins/{bind,declare,set,setattr}.def + - change to use sh_chkwrite to report write errors + + 5/2 + --- +lib/readline/input.c + - fix off-by-one errors in _rl_get_char (pop_index) and rl_stuff_char + (push_index) that caused the 511th character in the buffer to be + discarded. Fixes bug reported by Tom Bjorkholm + + 5/5 + --- +print_cmd.c + - added logic (inside_pipeline variable) to print_connection code and + print_redirection to handle the case of a command with a here + document inside a pipeline. In that case, print_redirection prints + the `|' before the here document text, so the parser knows the + command is continued. Fixes problem reported by Chris Lesner + diff --git a/builtins/alias.def b/builtins/alias.def index 572910bc4..db13869e8 100644 --- a/builtins/alias.def +++ b/builtins/alias.def @@ -103,7 +103,7 @@ alias_builtin (list) free (alias_list); /* XXX - Do not free the strings. */ if (list == 0) - return (EXECUTION_SUCCESS); + return (sh_chkwrite (EXECUTION_SUCCESS)); } any_failed = 0; diff --git a/builtins/bind.def b/builtins/bind.def index ce246dde5..0cbab504c 100644 --- a/builtins/bind.def +++ b/builtins/bind.def @@ -266,7 +266,7 @@ bind_builtin (list) run_unwind_frame ("bind_builtin"); - return (return_code); + return (sh_chkwrite (return_code)); } static int diff --git a/builtins/cd.def b/builtins/cd.def index 7d3ff4617..f6258eb91 100644 --- a/builtins/cd.def +++ b/builtins/cd.def @@ -108,9 +108,11 @@ bindpwd (no_symlinks) int no_symlinks; { char *dirname, *pwdvar; - int old_anm; + int old_anm, r; SHELL_VAR *tvar; + r = sh_chkwrite (EXECUTION_SUCCESS); + #define tcwd the_current_working_directory dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd) : get_working_directory ("cd"); @@ -131,7 +133,7 @@ bindpwd (no_symlinks) if (dirname && dirname != the_current_working_directory) free (dirname); - return (EXECUTION_SUCCESS); + return (r); } /* Call get_working_directory to reset the value of @@ -375,15 +377,7 @@ pwd_builtin (list) setpwd (directory); if (directory != the_current_working_directory) free (directory); - fflush (stdout); - if (ferror (stdout)) - { - sh_wrerror (); - clearerr (stdout); - return (EXECUTION_FAILURE); - } - - return (EXECUTION_SUCCESS); + return (sh_chkwrite (EXECUTION_SUCCESS)); } else return (EXECUTION_FAILURE); diff --git a/builtins/common.c b/builtins/common.c index 5d9b189fc..dcc5a4d40 100644 --- a/builtins/common.c +++ b/builtins/common.c @@ -277,6 +277,19 @@ sh_wrerror () builtin_error (_("write error: %s"), strerror (errno)); } +int +sh_chkwrite (s) +{ + fflush (stdout); + if (ferror (stdout)) + { + sh_wrerror (); + clearerr (stdout); + return (EXECUTION_FAILURE); + } + return (s); +} + /* **************************************************************** */ /* */ /* Shell positional parameter manipulation */ diff --git a/builtins/common.h b/builtins/common.h index 1233d667a..0a46d2001 100644 --- a/builtins/common.h +++ b/builtins/common.h @@ -78,6 +78,7 @@ extern void sh_nojobs __P((char *)); extern void sh_restricted __P((char *)); extern void sh_notbuiltin __P((char *)); extern void sh_wrerror __P((void)); +extern int sh_chkwrite __P((int)); extern char **make_builtin_argv __P((WORD_LIST *, int *)); extern void remember_args __P((WORD_LIST *, int)); diff --git a/builtins/complete.def b/builtins/complete.def index aab43153f..24707a744 100644 --- a/builtins/complete.def +++ b/builtins/complete.def @@ -528,7 +528,8 @@ print_cmd_completions (list) ret = EXECUTION_FAILURE; } } - return (ret); + + return (sh_chkwrite (ret)); } $BUILTIN compgen diff --git a/builtins/declare.def b/builtins/declare.def index a806f10a5..2bb9e1d2d 100644 --- a/builtins/declare.def +++ b/builtins/declare.def @@ -191,16 +191,12 @@ declare_internal (list, local_var) free (vlist); } } + else if (flags_on == 0) + return (set_builtin ((WORD_LIST *)NULL)); else - { - if (flags_on == 0) - set_builtin ((WORD_LIST *)NULL); - else - set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs); - } + set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs); - fflush (stdout); - return (EXECUTION_SUCCESS); + return (sh_chkwrite (EXECUTION_SUCCESS)); } if (pflag) /* declare -p [-afFirtx] name [name...] */ @@ -214,7 +210,7 @@ declare_internal (list, local_var) any_failed++; } } - return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS); + return (sh_chkwrite (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS)); } #define NEXT_VARIABLE() free (name); list = list->next; continue @@ -338,6 +334,7 @@ declare_internal (list, local_var) t = nodefs ? var->name : named_function_string (name, function_cell (var), 1); printf ("%s\n", t); + any_failed = sh_chkwrite (any_failed); } } else /* declare -[fF] -[rx] name [name...] */ diff --git a/builtins/echo.def b/builtins/echo.def index 4291d7c16..483f93bc9 100644 --- a/builtins/echo.def +++ b/builtins/echo.def @@ -177,12 +177,5 @@ just_echo: if (display_return) putchar ('\n'); - fflush (stdout); - if (ferror (stdout)) - { - sh_wrerror (); - clearerr (stdout); - return (EXECUTION_FAILURE); - } - return (EXECUTION_SUCCESS); + return (sh_chkwrite (EXECUTION_SUCCESS)); } diff --git a/builtins/fc.def b/builtins/fc.def index a807309da..5d6d530ea 100644 --- a/builtins/fc.def +++ b/builtins/fc.def @@ -368,8 +368,15 @@ fc_builtin (list) } if (listing) - return (EXECUTION_SUCCESS); + return (sh_chkwrite (EXECUTION_SUCCESS)); + fflush (stream); + if (ferror (stream)) + { + sh_wrerror (); + fclose (stream); + return (EXECUTION_FAILURE); + } fclose (stream); /* Now edit the file of commands. */ diff --git a/builtins/history.def b/builtins/history.def index 972079221..434fe271c 100644 --- a/builtins/history.def +++ b/builtins/history.def @@ -170,7 +170,7 @@ history_builtin (list) { if (list) return (expand_and_print_history (list)); - return (EXECUTION_SUCCESS); + return (sh_chkwrite (EXECUTION_SUCCESS)); } #endif else if (flags & DFLAG) @@ -193,7 +193,7 @@ history_builtin (list) else if ((flags & (AFLAG|RFLAG|NFLAG|WFLAG|CFLAG)) == 0) { display_history (list); - return (EXECUTION_SUCCESS); + return (sh_chkwrite (EXECUTION_SUCCESS)); } filename = list ? list->word->word : get_string_value ("HISTFILE"); diff --git a/builtins/pushd.def b/builtins/pushd.def index 86f0b9459..c69e11b2a 100644 --- a/builtins/pushd.def +++ b/builtins/pushd.def @@ -448,7 +448,7 @@ dirs_builtin (list) if (index_flag) { putchar ('\n'); - return EXECUTION_SUCCESS; + return (sh_chkwrite (EXECUTION_SUCCESS)); } } @@ -473,8 +473,8 @@ dirs_builtin (list) printf ("%s%s", (vflag & 1) ? "\n" : " ", DIRSTACK_ENTRY (i)); putchar ('\n'); - fflush (stdout); - return (EXECUTION_SUCCESS); + + return (sh_chkwrite (EXECUTION_SUCCESS)); } static void diff --git a/builtins/set.def b/builtins/set.def index 9de094c25..ee87a2746 100644 --- a/builtins/set.def +++ b/builtins/set.def @@ -580,17 +580,18 @@ int set_builtin (list) WORD_LIST *list; { - int on_or_off, flag_name, force_assignment, opts_changed; + int on_or_off, flag_name, force_assignment, opts_changed, rv; register char *arg; char s[3]; if (list == 0) { print_all_shell_variables (); - return (EXECUTION_SUCCESS); + return (sh_chkwrite (EXECUTION_SUCCESS)); } /* Check validity of flag arguments. */ + rv = EXECUTION_SUCCESS; reset_internal_getopt (); while ((flag_name = internal_getopt (list, optflags)) != -1) { @@ -653,6 +654,7 @@ set_builtin (list) if (opt == 0) { list_minus_o_opts (-1, (on_or_off == '+')); + rv = sh_chkwrite (rv); continue; } @@ -699,7 +701,7 @@ set_builtin (list) /* Set up new value of $SHELLOPTS */ if (opts_changed) set_shellopts (); - return (EXECUTION_SUCCESS); + return (rv); } $BUILTIN unset diff --git a/builtins/setattr.def b/builtins/setattr.def index d4fe9871e..8507120bb 100644 --- a/builtins/setattr.def +++ b/builtins/setattr.def @@ -1,7 +1,7 @@ This file is setattr.def, from which is created setattr.c. It implements the builtins "export" and "readonly", in Bash. -Copyright (C) 1987-2006 Free Software Foundation, Inc. +Copyright (C) 1987-2007 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -268,7 +268,11 @@ set_or_show_attributes (list, attribute, nodefs) continue; #endif if ((var->attributes & attribute)) - show_var_attributes (var, READONLY_OR_EXPORT, nodefs); + { + show_var_attributes (var, READONLY_OR_EXPORT, nodefs); + if (any_failed = sh_chkwrite (any_failed)) + break; + } } free (variable_list); } diff --git a/builtins/shopt.def b/builtins/shopt.def index 8055473e5..080a03f40 100644 --- a/builtins/shopt.def +++ b/builtins/shopt.def @@ -352,7 +352,7 @@ list_shopts (list, flags) if ((flags & QFLAG) == 0) print_shopt (shopt_vars[i].name, val, flags); } - return (EXECUTION_SUCCESS); + return (sh_chkwrite (EXECUTION_SUCCESS)); } for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next) @@ -371,7 +371,7 @@ list_shopts (list, flags) print_shopt (l->word->word, val, flags); } - return (rval); + return (sh_chkwrite (rval)); } static int @@ -386,7 +386,7 @@ list_some_shopts (mode, flags) if (((flags & QFLAG) == 0) && mode == val) print_shopt (shopt_vars[i].name, val, flags); } - return (EXECUTION_SUCCESS); + return (sh_chkwrite (EXECUTION_SUCCESS)); } static int @@ -401,7 +401,7 @@ list_shopt_o_options (list, flags) { if ((flags & QFLAG) == 0) list_minus_o_opts (-1, (flags & PFLAG)); - return (EXECUTION_SUCCESS); + return (sh_chkwrite (EXECUTION_SUCCESS)); } for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next) @@ -423,7 +423,7 @@ list_shopt_o_options (list, flags) printf (OPTFMT, l->word->word, val ? on : off); } } - return (rval); + return (sh_chkwrite (rval)); } static int @@ -432,7 +432,7 @@ list_some_o_options (mode, flags) { if ((flags & QFLAG) == 0) list_minus_o_opts (mode, (flags & PFLAG)); - return (EXECUTION_SUCCESS); + return (sh_chkwrite (EXECUTION_SUCCESS)); } static int @@ -540,5 +540,5 @@ shopt_listopt (name, reusable) } print_shopt (name, *shopt_vars[i].value, reusable ? PFLAG : 0); - return (EXECUTION_SUCCESS); + return (sh_chkwrite (EXECUTION_SUCCESS)); } diff --git a/builtins/times.def b/builtins/times.def index db54558d0..42a160f3a 100644 --- a/builtins/times.def +++ b/builtins/times.def @@ -111,5 +111,5 @@ times_builtin (list) # endif /* HAVE_TIMES */ #endif /* !HAVE_TIMES */ - return (EXECUTION_SUCCESS); + return (sh_chkwrite (EXECUTION_SUCCESS)); } diff --git a/builtins/trap.def b/builtins/trap.def index 9e7d76361..7affa1cd1 100644 --- a/builtins/trap.def +++ b/builtins/trap.def @@ -112,9 +112,9 @@ trap_builtin (list) opt = DSIG_NOCASE|DSIG_SIGPREFIX; /* flags for decode_signal */ if (list_signal_names) - return (display_signal_list ((WORD_LIST *)NULL, 1)); + return (sh_chkwrite (display_signal_list ((WORD_LIST *)NULL, 1))); else if (display || list == 0) - return (display_traps (list)); + return (sh_chkwrite (display_traps (list))); else { char *first_arg; diff --git a/builtins/type.def b/builtins/type.def index 39a43162b..370e596c8 100644 --- a/builtins/type.def +++ b/builtins/type.def @@ -185,9 +185,8 @@ type_builtin (list) list = list->next; } - fflush (stdout); - - return ((successful_finds != 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE); + opt = (successful_finds != 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE; + return (sh_chkwrite (opt)); } /* diff --git a/builtins/ulimit.def b/builtins/ulimit.def index 2307c4650..d1ac71df4 100644 --- a/builtins/ulimit.def +++ b/builtins/ulimit.def @@ -356,7 +356,7 @@ ulimit_builtin (list) } #endif print_all_limits (mode == 0 ? LIMIT_SOFT : mode); - return (EXECUTION_SUCCESS); + return (sh_chkwrite (EXECUTION_SUCCESS)); } /* default is `ulimit -f' */ diff --git a/builtins/umask.def b/builtins/umask.def index 489ca3305..23e819941 100644 --- a/builtins/umask.def +++ b/builtins/umask.def @@ -137,8 +137,7 @@ umask_builtin (list) printf ("%04lo\n", (unsigned long)umask_arg); } - fflush (stdout); - return (EXECUTION_SUCCESS); + return (sh_chkwrite (EXECUTION_SUCCESS)); } /* Print the umask in a symbolic form. In the output, a letter is diff --git a/doc/bash.1 b/doc/bash.1 index 181dc6341..5a3d2ee58 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -5,12 +5,12 @@ .\" Case Western Reserve University .\" chet@po.cwru.edu .\" -.\" Last Change: Fri Jan 12 16:29:22 EST 2007 +.\" Last Change: Tue May 1 10:05:17 EDT 2007 .\" .\" bash_builtins, strip all but Built-Ins section .if \n(zZ=1 .ig zZ .if \n(zY=1 .ig zY -.TH BASH 1 "2007 January 12" "GNU Bash-3.2" +.TH BASH 1 "2007 May 1" "GNU Bash-3.2" .\" .\" There's some problem with having a `@' .\" in a tagged paragraph with the BSD man macros. @@ -645,7 +645,8 @@ The return status is the exit status of Note that unlike the metacharacters \fB(\fP and \fB)\fP, \fB{\fP and \fB}\fP are \fIreserved words\fP and must occur where a reserved word is permitted to be recognized. Since they do not cause a word -break, they must be separated from \fIlist\fP by whitespace. +break, they must be separated from \fIlist\fP by whitespace or another +shell metacharacter. .TP ((\fIexpression\fP)) The \fIexpression\fP is evaluated according to the rules described @@ -8318,6 +8319,7 @@ an argument of \fB\-\-\fP as signifying the end of options. .if n .sp 1 Expressions may be combined using the following operators, listed in decreasing order of precedence. +The evaluation depends on the number of arguments; see below. .RS .PD 0 .TP @@ -8375,14 +8377,14 @@ under .BR "CONDITIONAL EXPRESSIONS" , the result of the expression is the result of the binary test using the first and third arguments as operands. +The \fB\-a\fP and \fB\-o\fP operators are considered binary operators +when there are three arguments. If the first argument is \fB!\fP, the value is the negation of the two-argument test using the second and third arguments. If the first argument is exactly \fB(\fP and the third argument is exactly \fB)\fP, the result is the one-argument test of the second argument. Otherwise, the expression is false. -The \fB\-a\fP and \fB\-o\fP operators are considered binary operators -in this case. .TP 4 arguments If the first argument is \fB!\fP, the result is the negation of diff --git a/doc/bashref.texi b/doc/bashref.texi index 78f9c4cb2..62b0c5978 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -1041,7 +1041,8 @@ The semicolon (or newline) following @var{list} is required. In addition to the creation of a subshell, there is a subtle difference between these two constructs due to historical reasons. The braces are @code{reserved words}, so they must be separated from the @var{list} -by @code{blank}s. The parentheses are @code{operators}, and are +by @code{blank}s or other shell metacharacters. +The parentheses are @code{operators}, and are recognized as separate tokens by the shell even if they are not separated from the @var{list} by whitespace. @@ -1092,7 +1093,8 @@ Note that for historical reasons, in the most common usage the curly braces that surround the body of the function must be separated from the body by @code{blank}s or newlines. This is because the braces are reserved words and are only recognized -as such when they are separated by whitespace. +as such when they are separated from the command list +by whitespace or another shell metacharacter. Also, when using the braces, the @var{list} must be terminated by a semicolon, a @samp{&}, or a newline. @@ -2918,6 +2920,7 @@ be a @code{]}. Expressions may be combined using the following operators, listed in decreasing order of precedence. +The evaluation depends on the number of arguments; see below. @table @code @item ! @var{expr} @@ -2958,14 +2961,14 @@ If the second argument is one of the binary conditional operators (@pxref{Bash Conditional Expressions}), the result of the expression is the result of the binary test using the first and third arguments as operands. +The @samp{-a} and @samp{-o} operators are considered binary operators +when there are three arguments. If the first argument is @samp{!}, the value is the negation of the two-argument test using the second and third arguments. If the first argument is exactly @samp{(} and the third argument is exactly @samp{)}, the result is the one-argument test of the second argument. Otherwise, the expression is false. -The @samp{-a} and @samp{-o} operators are considered binary operators -in this case. @item 4 arguments If the first argument is @samp{!}, the result is the negation of diff --git a/doc/version.texi b/doc/version.texi index 79525961d..dc36632b5 100644 --- a/doc/version.texi +++ b/doc/version.texi @@ -2,9 +2,9 @@ Copyright (C) 1988-2007 Free Software Foundation, Inc. @end ignore -@set LASTCHANGE Fri Jan 12 16:29:58 EST 2007 +@set LASTCHANGE Tue May 1 10:05:36 EDT 2007 @set EDITION 3.2 @set VERSION 3.2 -@set UPDATED 12 January 2007 -@set UPDATED-MONTH January 2007 +@set UPDATED 1 May 2007 +@set UPDATED-MONTH May 2007 diff --git a/lib/readline/examples/x b/lib/readline/examples/x new file mode 100644 index 000000000..239dcab6b --- /dev/null +++ b/lib/readline/examples/x @@ -0,0 +1 @@ +N 3149) 5/1 To: peggy.gup@c Re: FW: Phone for Mike Dailey (2413 chars)N 3150) 5/1 Jason Cutcher RE: Phone for Mike Dailey (34705 chars)N 3151) 5/1 Wizards *****SPAM***** Relief (7291 chars)N 3152) 5/1 FCG Help Desk Case HD0000002533519, Medium, h (2537 chars)N 3153) 5/1 To: jrw11@case. HD0000002533519 (2247 chars)N 3154) 5/1 Peggy Watts Gup RE: [tis-staff] Boxes back to m (12903 chars)N 3155) 5/1 Debbie Andrews [firewall-changes] Firewa diff --git a/lib/readline/input.c b/lib/readline/input.c index d4ff47b86..607f5e261 100644 --- a/lib/readline/input.c +++ b/lib/readline/input.c @@ -119,7 +119,7 @@ ibuffer_space () if (pop_index > push_index) return (pop_index - push_index - 1); else - return (ibuffer_len - (push_index - pop_index) - 1); + return (ibuffer_len - (push_index - pop_index)); } /* Get a key from the buffer of characters to be read. @@ -133,8 +133,11 @@ rl_get_char (key) return (0); *key = ibuffer[pop_index++]; - +#if 0 if (pop_index >= ibuffer_len) +#else + if (pop_index > ibuffer_len) +#endif pop_index = 0; return (1); @@ -250,7 +253,8 @@ rl_gather_tyi () while (chars_avail--) { k = (*rl_getc_function) (rl_instream); - rl_stuff_char (k); + if (rl_stuff_char (k) == 0) + break; /* some problem; no more room */ if (k == NEWLINE || k == RETURN) break; } @@ -373,7 +377,11 @@ rl_stuff_char (key) RL_SETSTATE (RL_STATE_INPUTPENDING); } ibuffer[push_index++] = key; +#if 0 if (push_index >= ibuffer_len) +#else + if (push_index > ibuffer_len) +#endif push_index = 0; return 1; diff --git a/print_cmd.c b/print_cmd.c index d1dfd1a78..28bec1b5e 100644 --- a/print_cmd.c +++ b/print_cmd.c @@ -106,7 +106,15 @@ int command_string_index = 0; /* Non-zero means the stuff being printed is inside of a function def. */ static int inside_function_def; + +/* Used to decide where to put the `|' if the command in the pipeline has + here documents associated with it. If non-zero, print_redirection + prints the `|' before the text of the here document and print_connection + suppresses the `|'. */ +static int inside_pipeline; static int skip_this_indent; + +/* Flag indicating we printed a here-document. */ static int was_heredoc; /* The depth of the group commands that we are currently printing. This @@ -133,7 +141,7 @@ char * make_command_string (command) COMMAND *command; { - command_string_index = was_heredoc = 0; + command_string_index = was_heredoc = inside_pipeline = 0; make_command_string_internal (command); return (the_printed_command); } @@ -215,7 +223,11 @@ make_command_string_internal (command) case cm_connection: skip_this_indent++; + if (command->value.Connection->connector == '|') + inside_pipeline = 1; make_command_string_internal (command->value.Connection->first); + if (command->value.Connection->connector == '|') + inside_pipeline = 0; switch (command->value.Connection->connector) { @@ -223,7 +235,10 @@ make_command_string_internal (command) case '|': { char c = command->value.Connection->connector; - cprintf (" %c", c); + if (c == '&' || was_heredoc == 0) + cprintf (" %c", c); + else + was_heredoc = 0; if (c != '&' || command->value.Connection->second) { cprintf (" "); @@ -851,6 +866,10 @@ print_redirection_list (redirects) print the here documents. */ if (heredocs) { +if (inside_pipeline) +{ +itrace("print_redirection_list: here documents inside pipeline"); +} cprintf (" "); for (hdtail = heredocs; hdtail; hdtail = hdtail->next) { @@ -868,6 +887,7 @@ print_redirection (redirect) { int kill_leading, redirector, redir_fd; WORD_DESC *redirectee; + char *x; kill_leading = 0; redirectee = redirect->redirectee.filename; @@ -905,17 +925,16 @@ print_redirection (redirect) if (redirector != 0) cprintf ("%d", redirector); /* If the here document delimiter is quoted, single-quote it. */ - if (redirect->redirectee.filename->flags & W_QUOTED) - { - char *x; - x = sh_single_quote (redirect->here_doc_eof); - cprintf ("<<%s%s\n", kill_leading? "-" : "", x); - free (x); - } - else - cprintf ("<<%s%s\n", kill_leading? "-" : "", redirect->here_doc_eof); - cprintf ("%s%s", - redirect->redirectee.filename->word, redirect->here_doc_eof); + x = (redirect->redirectee.filename->flags & W_QUOTED) + ? sh_single_quote (redirect->here_doc_eof) + : redirect->here_doc_eof; + cprintf ("<<%s%s", kill_leading? "-" : "", x); + if (x != redirect->here_doc_eof) + free (x); +if (inside_pipeline) + cprintf (" |"); + cprintf ("\n"); + cprintf ("%s%s", redirect->redirectee.filename->word, redirect->here_doc_eof); break; case r_reading_string: @@ -991,6 +1010,7 @@ reset_locals () { inside_function_def = 0; indentation = 0; + inside_pipeline = 0; } static void @@ -1010,7 +1030,7 @@ print_function_def (func) inside_function_def++; indentation += indentation_amount; - cmdcopy = copy_command (func->command); + cmdcopy = copy_command (func->command); /* possible mem leak on unwind-protect */ if (cmdcopy->type == cm_group) { func_redirects = cmdcopy->redirects; @@ -1055,6 +1075,7 @@ named_function_string (name, command, multi_line) old_indent = indentation; old_amount = indentation_amount; command_string_index = was_heredoc = 0; + inside_pipeline = 0; if (name && *name) cprintf ("%s ", name); diff --git a/print_cmd.c~ b/print_cmd.c~ new file mode 100644 index 000000000..e68619fed --- /dev/null +++ b/print_cmd.c~ @@ -0,0 +1,1322 @@ +/* print_command -- A way to make readable commands from a command tree. */ + +/* Copyright (C) 1989-2005 Free Software Foundation, Inc. + +This file is part of GNU Bash, the Bourne Again SHell. + +Bash is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +Bash is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with Bash; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#include "config.h" + +#include + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include +# endif +# include +#endif + +#if defined (PREFER_STDARG) +# include +#else +# include +#endif + +#include "bashansi.h" +#include "bashintl.h" + +#include "shell.h" +#include "flags.h" +#include /* use <...> so we pick it up from the build directory */ + +#include "shmbutil.h" + +#include "builtins/common.h" + +#if !HAVE_DECL_PRINTF +extern int printf __P((const char *, ...)); /* Yuck. Double yuck. */ +#endif + +extern int indirection_level; + +static int indentation; +static int indentation_amount = 4; + +#if defined (PREFER_STDARG) +typedef void PFUNC __P((const char *, ...)); + +static void cprintf __P((const char *, ...)) __attribute__((__format__ (printf, 1, 2))); +static void xprintf __P((const char *, ...)) __attribute__((__format__ (printf, 1, 2))); +#else +#define PFUNC VFunction +static void cprintf (); +static void xprintf (); +#endif + +static void reset_locals __P((void)); +static void newline __P((char *)); +static void indent __P((int)); +static void semicolon __P((void)); +static void the_printed_command_resize __P((int)); + +static void make_command_string_internal __P((COMMAND *)); +static void _print_word_list __P((WORD_LIST *, char *, PFUNC *)); +static void command_print_word_list __P((WORD_LIST *, char *)); +static void print_case_clauses __P((PATTERN_LIST *)); +static void print_redirection_list __P((REDIRECT *)); +static void print_redirection __P((REDIRECT *)); + +static void print_for_command __P((FOR_COM *)); +#if defined (ARITH_FOR_COMMAND) +static void print_arith_for_command __P((ARITH_FOR_COM *)); +#endif +#if defined (SELECT_COMMAND) +static void print_select_command __P((SELECT_COM *)); +#endif +static void print_group_command __P((GROUP_COM *)); +static void print_case_command __P((CASE_COM *)); +static void print_while_command __P((WHILE_COM *)); +static void print_until_command __P((WHILE_COM *)); +static void print_until_or_while __P((WHILE_COM *, char *)); +static void print_if_command __P((IF_COM *)); +#if defined (COND_COMMAND) +static void print_cond_node __P((COND_COM *)); +#endif +static void print_function_def __P((FUNCTION_DEF *)); + +#define PRINTED_COMMAND_INITIAL_SIZE 64 +#define PRINTED_COMMAND_GROW_SIZE 128 + +char *the_printed_command = (char *)NULL; +int the_printed_command_size = 0; +int command_string_index = 0; + +/* Non-zero means the stuff being printed is inside of a function def. */ +static int inside_function_def; + +static int inside_pipeline; +static int skip_this_indent; +static int was_heredoc; + +/* The depth of the group commands that we are currently printing. This + includes the group command that is a function body. */ +static int group_command_nesting; + +/* A buffer to indicate the indirection level (PS4) when set -x is enabled. */ +static char indirection_string[100]; + +/* Print COMMAND (a command tree) on standard output. */ +void +print_command (command) + COMMAND *command; +{ + command_string_index = 0; + printf ("%s", make_command_string (command)); +} + +/* Make a string which is the printed representation of the command + tree in COMMAND. We return this string. However, the string is + not consed, so you have to do that yourself if you want it to + remain around. */ +char * +make_command_string (command) + COMMAND *command; +{ + command_string_index = was_heredoc = inside_pipeline = 0; + make_command_string_internal (command); + return (the_printed_command); +} + +/* The internal function. This is the real workhorse. */ +static void +make_command_string_internal (command) + COMMAND *command; +{ + if (command == 0) + cprintf (""); + else + { + if (skip_this_indent) + skip_this_indent--; + else + indent (indentation); + + if (command->flags & CMD_TIME_PIPELINE) + { + cprintf ("time "); + if (command->flags & CMD_TIME_POSIX) + cprintf ("-p "); + } + + if (command->flags & CMD_INVERT_RETURN) + cprintf ("! "); + + switch (command->type) + { + case cm_for: + print_for_command (command->value.For); + break; + +#if defined (ARITH_FOR_COMMAND) + case cm_arith_for: + print_arith_for_command (command->value.ArithFor); + break; +#endif + +#if defined (SELECT_COMMAND) + case cm_select: + print_select_command (command->value.Select); + break; +#endif + + case cm_case: + print_case_command (command->value.Case); + break; + + case cm_while: + print_while_command (command->value.While); + break; + + case cm_until: + print_until_command (command->value.While); + break; + + case cm_if: + print_if_command (command->value.If); + break; + +#if defined (DPAREN_ARITHMETIC) + case cm_arith: + print_arith_command (command->value.Arith->exp); + break; +#endif + +#if defined (COND_COMMAND) + case cm_cond: + print_cond_command (command->value.Cond); + break; +#endif + + case cm_simple: + print_simple_command (command->value.Simple); + break; + + case cm_connection: + + skip_this_indent++; + if (command->value.Connection->connector == '|') + inside_pipeline = 1; + make_command_string_internal (command->value.Connection->first); + if (command->value.Connection->connector == '|') + inside_pipeline = 0; + + switch (command->value.Connection->connector) + { + case '&': + case '|': + { + char c = command->value.Connection->connector; + if (c == '&' || was_heredoc == 0) + cprintf (" %c", c); + else + was_heredoc = 0; + if (c != '&' || command->value.Connection->second) + { + cprintf (" "); + skip_this_indent++; + } + } + break; + + case AND_AND: + cprintf (" && "); + if (command->value.Connection->second) + skip_this_indent++; + break; + + case OR_OR: + cprintf (" || "); + if (command->value.Connection->second) + skip_this_indent++; + break; + + case ';': + if (was_heredoc == 0) + cprintf (";"); + else + was_heredoc = 0; + + if (inside_function_def) + cprintf ("\n"); + else + { + cprintf (" "); + if (command->value.Connection->second) + skip_this_indent++; + } + break; + + default: + cprintf (_("print_command: bad connector `%d'"), + command->value.Connection->connector); + break; + } + + make_command_string_internal (command->value.Connection->second); + break; + + case cm_function_def: + print_function_def (command->value.Function_def); + break; + + case cm_group: + print_group_command (command->value.Group); + break; + + case cm_subshell: + cprintf ("( "); + skip_this_indent++; + make_command_string_internal (command->value.Subshell->command); + cprintf (" )"); + break; + + default: + command_error ("print_command", CMDERR_BADTYPE, command->type, 0); + break; + } + + + if (command->redirects) + { + cprintf (" "); + print_redirection_list (command->redirects); + } + } +} + +static void +_print_word_list (list, separator, pfunc) + WORD_LIST *list; + char *separator; + PFUNC *pfunc; +{ + WORD_LIST *w; + + for (w = list; w; w = w->next) + (*pfunc) ("%s%s", w->word->word, w->next ? separator : ""); +} + +void +print_word_list (list, separator) + WORD_LIST *list; + char *separator; +{ + _print_word_list (list, separator, xprintf); +} + +/* Return a string denoting what our indirection level is. */ + +char * +indirection_level_string () +{ + register int i, j; + char *ps4; + char ps4_firstc[MB_LEN_MAX+1]; + int ps4_firstc_len, ps4_len; + + indirection_string[0] = '\0'; + ps4 = get_string_value ("PS4"); + + if (ps4 == 0 || *ps4 == '\0') + return (indirection_string); + + change_flag ('x', FLAG_OFF); + ps4 = decode_prompt_string (ps4); + change_flag ('x', FLAG_ON); + + if (ps4 == 0 || *ps4 == '\0') + return (indirection_string); + +#if defined (HANDLE_MULTIBYTE) + ps4_len = strnlen (ps4, MB_CUR_MAX); + ps4_firstc_len = MBLEN (ps4, ps4_len); + if (ps4_firstc_len == 1 || ps4_firstc_len == 0 || MB_INVALIDCH (ps4_firstc_len)) + { + ps4_firstc[0] = ps4[0]; + ps4_firstc[ps4_firstc_len = 1] = '\0'; + } + else + memcpy (ps4_firstc, ps4, ps4_firstc_len); +#else + ps4_firstc[0] = ps4[0]; + ps4_firstc[ps4_firstc_len = 1] = '\0'; +#endif + + for (i = j = 0; ps4_firstc[0] && j < indirection_level && i < 99; i += ps4_firstc_len, j++) + { + if (ps4_firstc_len == 1) + indirection_string[i] = ps4_firstc[0]; + else + memcpy (indirection_string+i, ps4_firstc, ps4_firstc_len); + } + + for (j = ps4_firstc_len; *ps4 && ps4[j] && i < 99; i++, j++) + indirection_string[i] = ps4[j]; + + indirection_string[i] = '\0'; + free (ps4); + return (indirection_string); +} + +void +xtrace_print_assignment (name, value, assign_list, xflags) + char *name, *value; + int assign_list, xflags; +{ + char *nval; + + if (xflags) + fprintf (stderr, "%s", indirection_level_string ()); + + /* VALUE should not be NULL when this is called. */ + if (*value == '\0' || assign_list) + nval = value; + else if (sh_contains_shell_metas (value)) + nval = sh_single_quote (value); + else if (ansic_shouldquote (value)) + nval = ansic_quote (value, 0, (int *)0); + else + nval = value; + + if (assign_list) + fprintf (stderr, "%s=(%s)\n", name, nval); + else + fprintf (stderr, "%s=%s\n", name, nval); + + if (nval != value) + FREE (nval); + + fflush (stderr); +} + +/* A function to print the words of a simple command when set -x is on. */ +void +xtrace_print_word_list (list, xtflags) + WORD_LIST *list; + int xtflags; +{ + WORD_LIST *w; + char *t, *x; + + if (xtflags) + fprintf (stderr, "%s", indirection_level_string ()); + + for (w = list; w; w = w->next) + { + t = w->word->word; + if (t == 0 || *t == '\0') + fprintf (stderr, "''%s", w->next ? " " : ""); + else if (sh_contains_shell_metas (t)) + { + x = sh_single_quote (t); + fprintf (stderr, "%s%s", x, w->next ? " " : ""); + free (x); + } + else if (ansic_shouldquote (t)) + { + x = ansic_quote (t, 0, (int *)0); + fprintf (stderr, "%s%s", x, w->next ? " " : ""); + free (x); + } + else + fprintf (stderr, "%s%s", t, w->next ? " " : ""); + } + fprintf (stderr, "\n"); +} + +static void +command_print_word_list (list, separator) + WORD_LIST *list; + char *separator; +{ + _print_word_list (list, separator, cprintf); +} + +void +print_for_command_head (for_command) + FOR_COM *for_command; +{ + cprintf ("for %s in ", for_command->name->word); + command_print_word_list (for_command->map_list, " "); +} + +void +xtrace_print_for_command_head (for_command) + FOR_COM *for_command; +{ + fprintf (stderr, "%s", indirection_level_string ()); + fprintf (stderr, "for %s in ", for_command->name->word); + xtrace_print_word_list (for_command->map_list, 0); +} + +static void +print_for_command (for_command) + FOR_COM *for_command; +{ + print_for_command_head (for_command); + + cprintf (";"); + newline ("do\n"); + indentation += indentation_amount; + make_command_string_internal (for_command->action); + semicolon (); + indentation -= indentation_amount; + newline ("done"); +} + +#if defined (ARITH_FOR_COMMAND) +static void +print_arith_for_command (arith_for_command) + ARITH_FOR_COM *arith_for_command; +{ + cprintf ("for (("); + command_print_word_list (arith_for_command->init, " "); + cprintf ("; "); + command_print_word_list (arith_for_command->test, " "); + cprintf ("; "); + command_print_word_list (arith_for_command->step, " "); + cprintf ("))"); + newline ("do\n"); + indentation += indentation_amount; + make_command_string_internal (arith_for_command->action); + semicolon (); + indentation -= indentation_amount; + newline ("done"); +} +#endif /* ARITH_FOR_COMMAND */ + +#if defined (SELECT_COMMAND) +void +print_select_command_head (select_command) + SELECT_COM *select_command; +{ + cprintf ("select %s in ", select_command->name->word); + command_print_word_list (select_command->map_list, " "); +} + +void +xtrace_print_select_command_head (select_command) + SELECT_COM *select_command; +{ + fprintf (stderr, "%s", indirection_level_string ()); + fprintf (stderr, "select %s in ", select_command->name->word); + xtrace_print_word_list (select_command->map_list, 0); +} + +static void +print_select_command (select_command) + SELECT_COM *select_command; +{ + print_select_command_head (select_command); + + cprintf (";"); + newline ("do\n"); + indentation += indentation_amount; + make_command_string_internal (select_command->action); + semicolon (); + indentation -= indentation_amount; + newline ("done"); +} +#endif /* SELECT_COMMAND */ + +static void +print_group_command (group_command) + GROUP_COM *group_command; +{ + group_command_nesting++; + cprintf ("{ "); + + if (inside_function_def == 0) + skip_this_indent++; + else + { + /* This is a group command { ... } inside of a function + definition, and should be printed as a multiline group + command, using the current indentation. */ + cprintf ("\n"); + indentation += indentation_amount; + } + + make_command_string_internal (group_command->command); + + if (inside_function_def) + { + cprintf ("\n"); + indentation -= indentation_amount; + indent (indentation); + } + else + { + semicolon (); + cprintf (" "); + } + + cprintf ("}"); + + group_command_nesting--; +} + +void +print_case_command_head (case_command) + CASE_COM *case_command; +{ + cprintf ("case %s in ", case_command->word->word); +} + +void +xtrace_print_case_command_head (case_command) + CASE_COM *case_command; +{ + fprintf (stderr, "%s", indirection_level_string ()); + fprintf (stderr, "case %s in\n", case_command->word->word); +} + +static void +print_case_command (case_command) + CASE_COM *case_command; +{ + print_case_command_head (case_command); + + if (case_command->clauses) + print_case_clauses (case_command->clauses); + newline ("esac"); +} + +static void +print_case_clauses (clauses) + PATTERN_LIST *clauses; +{ + indentation += indentation_amount; + while (clauses) + { + newline (""); + command_print_word_list (clauses->patterns, " | "); + cprintf (")\n"); + indentation += indentation_amount; + make_command_string_internal (clauses->action); + indentation -= indentation_amount; + newline (";;"); + clauses = clauses->next; + } + indentation -= indentation_amount; +} + +static void +print_while_command (while_command) + WHILE_COM *while_command; +{ + print_until_or_while (while_command, "while"); +} + +static void +print_until_command (while_command) + WHILE_COM *while_command; +{ + print_until_or_while (while_command, "until"); +} + +static void +print_until_or_while (while_command, which) + WHILE_COM *while_command; + char *which; +{ + cprintf ("%s ", which); + skip_this_indent++; + make_command_string_internal (while_command->test); + semicolon (); + cprintf (" do\n"); /* was newline ("do\n"); */ + indentation += indentation_amount; + make_command_string_internal (while_command->action); + indentation -= indentation_amount; + semicolon (); + newline ("done"); +} + +static void +print_if_command (if_command) + IF_COM *if_command; +{ + cprintf ("if "); + skip_this_indent++; + make_command_string_internal (if_command->test); + semicolon (); + cprintf (" then\n"); + indentation += indentation_amount; + make_command_string_internal (if_command->true_case); + indentation -= indentation_amount; + + if (if_command->false_case) + { + semicolon (); + newline ("else\n"); + indentation += indentation_amount; + make_command_string_internal (if_command->false_case); + indentation -= indentation_amount; + } + semicolon (); + newline ("fi"); +} + +#if defined (DPAREN_ARITHMETIC) +void +print_arith_command (arith_cmd_list) + WORD_LIST *arith_cmd_list; +{ + cprintf ("(("); + command_print_word_list (arith_cmd_list, " "); + cprintf ("))"); +} +#endif + +#if defined (COND_COMMAND) +static void +print_cond_node (cond) + COND_COM *cond; +{ + if (cond->flags & CMD_INVERT_RETURN) + cprintf ("! "); + + if (cond->type == COND_EXPR) + { + cprintf ("( "); + print_cond_node (cond->left); + cprintf (" )"); + } + else if (cond->type == COND_AND) + { + print_cond_node (cond->left); + cprintf (" && "); + print_cond_node (cond->right); + } + else if (cond->type == COND_OR) + { + print_cond_node (cond->left); + cprintf (" || "); + print_cond_node (cond->right); + } + else if (cond->type == COND_UNARY) + { + cprintf ("%s", cond->op->word); + cprintf (" "); + print_cond_node (cond->left); + } + else if (cond->type == COND_BINARY) + { + print_cond_node (cond->left); + cprintf (" "); + cprintf ("%s", cond->op->word); + cprintf (" "); + print_cond_node (cond->right); + } + else if (cond->type == COND_TERM) + { + cprintf ("%s", cond->op->word); /* need to add quoting here */ + } +} + +void +print_cond_command (cond) + COND_COM *cond; +{ + cprintf ("[[ "); + print_cond_node (cond); + cprintf (" ]]"); +} + +#ifdef DEBUG +void +debug_print_cond_command (cond) + COND_COM *cond; +{ + fprintf (stderr, "DEBUG: "); + command_string_index = 0; + print_cond_command (cond); + fprintf (stderr, "%s\n", the_printed_command); +} +#endif + +void +xtrace_print_cond_term (type, invert, op, arg1, arg2) + int type, invert; + WORD_DESC *op; + char *arg1, *arg2; +{ + command_string_index = 0; + fprintf (stderr, "%s", indirection_level_string ()); + fprintf (stderr, "[[ "); + if (invert) + fprintf (stderr, "! "); + + if (type == COND_UNARY) + { + fprintf (stderr, "%s ", op->word); + fprintf (stderr, "%s", (arg1 && *arg1) ? arg1 : "''"); + } + else if (type == COND_BINARY) + { + fprintf (stderr, "%s", (arg1 && *arg1) ? arg1 : "''"); + fprintf (stderr, " %s ", op->word); + fprintf (stderr, "%s", (arg2 && *arg2) ? arg2 : "''"); + } + + fprintf (stderr, " ]]\n"); +} +#endif /* COND_COMMAND */ + +#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) +/* A function to print the words of an arithmetic command when set -x is on. */ +void +xtrace_print_arith_cmd (list) + WORD_LIST *list; +{ + WORD_LIST *w; + + fprintf (stderr, "%s", indirection_level_string ()); + fprintf (stderr, "(( "); + for (w = list; w; w = w->next) + fprintf (stderr, "%s%s", w->word->word, w->next ? " " : ""); + fprintf (stderr, " ))\n"); +} +#endif + +void +print_simple_command (simple_command) + SIMPLE_COM *simple_command; +{ + command_print_word_list (simple_command->words, " "); + + if (simple_command->redirects) + { + cprintf (" "); + print_redirection_list (simple_command->redirects); + } +} + +static void +print_redirection_list (redirects) + REDIRECT *redirects; +{ + REDIRECT *heredocs, *hdtail, *newredir; + + heredocs = (REDIRECT *)NULL; + hdtail = heredocs; + + was_heredoc = 0; + while (redirects) + { + /* Defer printing the here documents until we've printed the + rest of the redirections. */ + if (redirects->instruction == r_reading_until || redirects->instruction == r_deblank_reading_until) + { + newredir = copy_redirect (redirects); + newredir->next = (REDIRECT *)NULL; + if (heredocs) + { + hdtail->next = newredir; + hdtail = newredir; + } + else + hdtail = heredocs = newredir; + } + else if (redirects->instruction == r_duplicating_output_word && redirects->redirector == 1) + { + /* Temporarily translate it as the execution code does. */ + redirects->instruction = r_err_and_out; + print_redirection (redirects); + redirects->instruction = r_duplicating_output_word; + } + else + print_redirection (redirects); + + redirects = redirects->next; + if (redirects) + cprintf (" "); + } + + /* Now that we've printed all the other redirections (on one line), + print the here documents. */ + if (heredocs) + { +if (inside_pipeline) +{ +itrace("print_redirection_list: here documents inside pipeline"); +} + cprintf (" "); + for (hdtail = heredocs; hdtail; hdtail = hdtail->next) + { + print_redirection (hdtail); + cprintf ("\n"); + } + dispose_redirects (heredocs); + was_heredoc = 1; + } +} + +static void +print_redirection (redirect) + REDIRECT *redirect; +{ + int kill_leading, redirector, redir_fd; + WORD_DESC *redirectee; + char *x; + + kill_leading = 0; + redirectee = redirect->redirectee.filename; + redirector = redirect->redirector; + redir_fd = redirect->redirectee.dest; + + switch (redirect->instruction) + { + case r_output_direction: + if (redirector != 1) + cprintf ("%d", redirector); + cprintf ("> %s", redirectee->word); + break; + + case r_input_direction: + if (redirector != 0) + cprintf ("%d", redirector); + cprintf ("< %s", redirectee->word); + break; + + case r_inputa_direction: /* Redirection created by the shell. */ + cprintf ("&"); + break; + + case r_appending_to: + if (redirector != 1) + cprintf ("%d", redirector); + cprintf (">> %s", redirectee->word); + break; + + case r_deblank_reading_until: + kill_leading++; + /* ... */ + case r_reading_until: + if (redirector != 0) + cprintf ("%d", redirector); + /* If the here document delimiter is quoted, single-quote it. */ + x = (redirect->redirectee.filename->flags & W_QUOTED) + ? sh_single_quote (redirect->here_doc_eof) + : redirect->here_doc_eof; + cprintf ("<<%s%s", kill_leading? "-" : "", x); + if (x != redirect->here_doc_eof) + free (x); +if (inside_pipeline) + cprintf (" |"); + cprintf ("\n"); + cprintf ("%s%s", redirect->redirectee.filename->word, redirect->here_doc_eof); + break; + + case r_reading_string: + if (redirector != 0) + cprintf ("%d", redirector); + if (ansic_shouldquote (redirect->redirectee.filename->word)) + { + char *x; + x = ansic_quote (redirect->redirectee.filename->word, 0, (int *)0); + cprintf ("<<< %s", x); + free (x); + } + else + cprintf ("<<< %s", redirect->redirectee.filename->word); + break; + + case r_duplicating_input: + cprintf ("%d<&%d", redirector, redir_fd); + break; + + case r_duplicating_output: + cprintf ("%d>&%d", redirector, redir_fd); + break; + + case r_duplicating_input_word: + cprintf ("%d<&%s", redirector, redirectee->word); + break; + + case r_duplicating_output_word: + cprintf ("%d>&%s", redirector, redirectee->word); + break; + + case r_move_input: + cprintf ("%d<&%d-", redirector, redir_fd); + break; + + case r_move_output: + cprintf ("%d>&%d-", redirector, redir_fd); + break; + + case r_move_input_word: + cprintf ("%d<&%s-", redirector, redirectee->word); + break; + + case r_move_output_word: + cprintf ("%d>&%s-", redirector, redirectee->word); + break; + + case r_close_this: + cprintf ("%d>&-", redirector); + break; + + case r_err_and_out: + cprintf (">&%s", redirectee->word); + break; + + case r_input_output: + if (redirector != 1) + cprintf ("%d", redirector); + cprintf ("<> %s", redirectee->word); + break; + + case r_output_force: + if (redirector != 1) + cprintf ("%d", redirector); + cprintf (">|%s", redirectee->word); + break; + } +} + +static void +reset_locals () +{ + inside_function_def = 0; + indentation = 0; + inside_pipeline = 0; +} + +static void +print_function_def (func) + FUNCTION_DEF *func; +{ + COMMAND *cmdcopy; + REDIRECT *func_redirects; + + func_redirects = NULL; + cprintf ("function %s () \n", func->name->word); + add_unwind_protect (reset_locals, 0); + + indent (indentation); + cprintf ("{ \n"); + + inside_function_def++; + indentation += indentation_amount; + + cmdcopy = copy_command (func->command); /* possible mem leak on unwind-protect */ + if (cmdcopy->type == cm_group) + { + func_redirects = cmdcopy->redirects; + cmdcopy->redirects = (REDIRECT *)NULL; + } + make_command_string_internal (cmdcopy->type == cm_group + ? cmdcopy->value.Group->command + : cmdcopy); + + remove_unwind_protect (); + indentation -= indentation_amount; + inside_function_def--; + + if (func_redirects) + { /* { */ + newline ("} "); + print_redirection_list (func_redirects); + cmdcopy->redirects = func_redirects; + } + else + newline ("}"); + + dispose_command (cmdcopy); +} + +/* Return the string representation of the named function. + NAME is the name of the function. + COMMAND is the function body. It should be a GROUP_COM. + MULTI_LINE is non-zero to pretty-print, or zero for all on one line. + */ +char * +named_function_string (name, command, multi_line) + char *name; + COMMAND *command; + int multi_line; +{ + char *result; + int old_indent, old_amount; + COMMAND *cmdcopy; + REDIRECT *func_redirects; + + old_indent = indentation; + old_amount = indentation_amount; + command_string_index = was_heredoc = 0; + inside_pipeline = 0; + + if (name && *name) + cprintf ("%s ", name); + + cprintf ("() "); + + if (multi_line == 0) + { + indentation = 1; + indentation_amount = 0; + } + else + { + cprintf ("\n"); + indentation += indentation_amount; + } + + inside_function_def++; + + cprintf (multi_line ? "{ \n" : "{ "); + + cmdcopy = copy_command (command); + /* Take any redirections specified in the function definition (which should + apply to the function as a whole) and save them for printing later. */ + func_redirects = (REDIRECT *)NULL; + if (cmdcopy->type == cm_group) + { + func_redirects = cmdcopy->redirects; + cmdcopy->redirects = (REDIRECT *)NULL; + } + make_command_string_internal (cmdcopy->type == cm_group + ? cmdcopy->value.Group->command + : cmdcopy); + + indentation = old_indent; + indentation_amount = old_amount; + inside_function_def--; + + if (func_redirects) + { /* { */ + newline ("} "); + print_redirection_list (func_redirects); + cmdcopy->redirects = func_redirects; + } + else + newline ("}"); + + result = the_printed_command; + + if (!multi_line) + { +#if 0 + register int i; + for (i = 0; result[i]; i++) + if (result[i] == '\n') + { + strcpy (result + i, result + i + 1); + --i; + } +#else + if (result[2] == '\n') /* XXX -- experimental */ + strcpy (result + 2, result + 3); +#endif + } + + dispose_command (cmdcopy); + + return (result); +} + +static void +newline (string) + char *string; +{ + cprintf ("\n"); + indent (indentation); + if (string && *string) + cprintf ("%s", string); +} + +static char *indentation_string; +static int indentation_size; + +static void +indent (amount) + int amount; +{ + register int i; + + RESIZE_MALLOCED_BUFFER (indentation_string, 0, amount, indentation_size, 16); + + for (i = 0; amount > 0; amount--) + indentation_string[i++] = ' '; + indentation_string[i] = '\0'; + cprintf (indentation_string); +} + +static void +semicolon () +{ + if (command_string_index > 0 && + (the_printed_command[command_string_index - 1] == '&' || + the_printed_command[command_string_index - 1] == '\n')) + return; + cprintf (";"); +} + +/* How to make the string. */ +static void +#if defined (PREFER_STDARG) +cprintf (const char *control, ...) +#else +cprintf (control, va_alist) + const char *control; + va_dcl +#endif +{ + register const char *s; + char char_arg[2], *argp, intbuf[INT_STRLEN_BOUND (int) + 1]; + int digit_arg, arg_len, c; + va_list args; + + SH_VA_START (args, control); + + arg_len = strlen (control); + the_printed_command_resize (arg_len + 1); + + char_arg[1] = '\0'; + s = control; + while (s && *s) + { + c = *s++; + argp = (char *)NULL; + if (c != '%' || !*s) + { + char_arg[0] = c; + argp = char_arg; + arg_len = 1; + } + else + { + c = *s++; + switch (c) + { + case '%': + char_arg[0] = c; + argp = char_arg; + arg_len = 1; + break; + + case 's': + argp = va_arg (args, char *); + arg_len = strlen (argp); + break; + + case 'd': + /* Represent an out-of-range file descriptor with an out-of-range + integer value. We can do this because the only use of `%d' in + the calls to cprintf is to output a file descriptor number for + a redirection. */ + digit_arg = va_arg (args, int); + if (digit_arg < 0) + { + sprintf (intbuf, "%u", (unsigned)-1); + argp = intbuf; + } + else + argp = inttostr (digit_arg, intbuf, sizeof (intbuf)); + arg_len = strlen (argp); + break; + + case 'c': + char_arg[0] = va_arg (args, int); + argp = char_arg; + arg_len = 1; + break; + + default: + programming_error (_("cprintf: `%c': invalid format character"), c); + /*NOTREACHED*/ + } + } + + if (argp && arg_len) + { + the_printed_command_resize (arg_len + 1); + FASTCOPY (argp, the_printed_command + command_string_index, arg_len); + command_string_index += arg_len; + } + } + + the_printed_command[command_string_index] = '\0'; +} + +/* Ensure that there is enough space to stuff LENGTH characters into + THE_PRINTED_COMMAND. */ +static void +the_printed_command_resize (length) + int length; +{ + if (the_printed_command == 0) + { + the_printed_command_size = (length + PRINTED_COMMAND_INITIAL_SIZE - 1) & ~(PRINTED_COMMAND_INITIAL_SIZE - 1); + the_printed_command = (char *)xmalloc (the_printed_command_size); + command_string_index = 0; + } + else if ((command_string_index + length) >= the_printed_command_size) + { + int new; + new = command_string_index + length + 1; + + /* Round up to the next multiple of PRINTED_COMMAND_GROW_SIZE. */ + new = (new + PRINTED_COMMAND_GROW_SIZE - 1) & ~(PRINTED_COMMAND_GROW_SIZE - 1); + the_printed_command_size = new; + + the_printed_command = (char *)xrealloc (the_printed_command, the_printed_command_size); + } +} + +#if defined (HAVE_VPRINTF) +/* ``If vprintf is available, you may assume that vfprintf and vsprintf are + also available.'' */ + +static void +#if defined (PREFER_STDARG) +xprintf (const char *format, ...) +#else +xprintf (format, va_alist) + const char *format; + va_dcl +#endif +{ + va_list args; + + SH_VA_START (args, format); + + vfprintf (stdout, format, args); + va_end (args); +} + +#else + +static void +xprintf (format, arg1, arg2, arg3, arg4, arg5) + const char *format; +{ + printf (format, arg1, arg2, arg3, arg4, arg5); +} + +#endif /* !HAVE_VPRINTF */ diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index 3efcf32d6..72ec06a2c 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -1,4 +1,4 @@ -BUILD_DIR=/usr/local/build/chet/bash/bash-current +BUILD_DIR=/usr/local/build/bash/bash-current THIS_SH=$BUILD_DIR/bash PATH=$PATH:$BUILD_DIR -- 2.47.3