execute_cmd.c
- changes to lastpipe code to make `pipefail' option, $PIPESTATUS, and
$? work correctly. Uses append_process and job_exit_status
+
+ 7/10
+ ----
+subst.c
+ - when performing pattern substitution word expansions, a `&' in the
+ replacement string is replaced by the text matched by the pattern.
+ The `&' can be quoted with a backslash to inhibit the expansion
takes info, creates a PROCESS from them, and adds it to the end of
the passed job id's pipeline. lastpipe code uses it to add a dummy
process for the last command in the pipeline
+ - freeze_jobs_list: new utility function so rest of shell can freeze
+ the jobs list. Used by the lastpipe code
execute_cmd.c
- changes to lastpipe code to make `pipefail' option, $PIPESTATUS, and
enable_hostname_completion (perform_hostname_completion);
/* characters that need to be quoted when appearing in filenames. */
-#if 0
- rl_filename_quote_characters = " \t\n\\\"'@<>=;|&()#$`?*[!:{"; /*}*/
-#else
rl_filename_quote_characters = " \t\n\\\"'@<>=;|&()#$`?*[!:{~"; /*}*/
-#endif
+
rl_filename_quoting_function = bash_quote_filename;
rl_filename_dequoting_function = bash_dequote_filename;
rl_char_is_quoted_p = char_is_quoted;
/* bashline.c -- Bash's interface to the readline library. */
-/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2010 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
-.TH BASH 1 "2010 July 2" "GNU Bash-4.1"
+.TH BASH 1 "2010 July 2" "GNU Bash-4.2"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
-.TH BASH 1 "2010 July 2" "GNU Bash-4.1"
+.TH BASH 1 "2010 July 2" "GNU Bash-4.2"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
shell's children.
Care should be taken in cases where this may cause a problem.
.PP
-Functions may be recursive. No limit is imposed on the number
-of recursive calls.
+Functions may be recursive.
+The \fBFUNCNEST\fP variable may be used to limit the depth of the
+function call stack and restrict the number of function invocations.
+By default, no limit is imposed on the number of recursive calls.
.SH "ARITHMETIC EVALUATION"
The shell allows arithmetic expressions to be evaluated, under
certain circumstances (see the \fBlet\fP and \fBdeclare\fP builtin
Each time @var{expr2} evaluates to a non-zero value, @var{commands} are
executed and the arithmetic expression @var{expr3} is evaluated.
If any expression is omitted, it behaves as if it evaluates to 1.
-The return value is the exit status of the last command in @var{list}
+The return value is the exit status of the last command in @var{commands}
that is executed, or false if any of the expressions is invalid.
@end table
shell's children.
Care should be taken in cases where this may cause a problem.
-Functions may be recursive. No limit is placed on the number of
-recursive calls.
+Functions may be recursive.
+The @code{FUNCNEST} variable may be used to limit the depth of the
+function call stack and restrict the number of function invocations.
+By default, no limit is placed on the number of recursive calls.
@node Shell Parameters
@section Shell Parameters
if (prev >= 0)
add_unwind_protect (close, prev);
- /* XXX - might need to temporarily put shell process in pgrp of the pipeline,
- so after we give the terminal to that process group in stop_pipeline, the
- shell can still access it. Would need to give it to
- jobs[lastpipe_jid]->pgrp */
exec_result = execute_command_internal (cmd, asynchronous, prev, pipe_out, fds_to_close);
if (lstdin > 0)
#define KEYMAP_SIZE 257
#define ANYOTHERKEY KEYMAP_SIZE-1
-/* I wanted to make the above structure contain a union of:
- union { rl_command_func_t *function; struct _keymap_entry *keymap; } value;
- but this made it impossible for me to create a static array.
- Maybe I need C lessons. */
-
typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[KEYMAP_SIZE];
typedef KEYMAP_ENTRY *Keymap;
#undef min /* just in case */
+/* format for %+ */
+#ifndef NATIONAL_FORMAT
+#define NATIONAL_FORMAT "%a %b %e %H:%M:%S %Z %Y"
+#endif
+
/* min --- return minimum of two numbers */
static inline int
static char *mb_substring __P((char *, int, int));
static char *parameter_brace_substring __P((char *, char *, char *, int));
+static int shouldexp_replacement __P((char *));
+
static char *pos_params_pat_subst __P((char *, char *, char *, int));
static char *parameter_brace_patsub __P((char *, char *, char *, int));
/* */
/****************************************************************/
+static int
+shouldexp_replacement (s)
+ char *s;
+{
+ register char *p;
+
+ for (p = s; p && *p; p++)
+ {
+ if (*p == '\\')
+ p++;
+ else if (*p == '&')
+ return 1;
+ }
+ return 0;
+}
+
char *
pat_subst (string, pat, rep, mflags)
char *string, *pat, *rep;
int mflags;
{
- char *ret, *s, *e, *str;
- int rsize, rptr, l, replen, mtype;
+ char *ret, *s, *e, *str, *rstr, *mstr;
+ int rsize, rptr, l, replen, mtype, rxpand, rslen, mlen;
mtype = mflags & MATCH_TYPEMASK;
+ rxpand = (rep && *rep) ? shouldexp_replacement (rep) : 0;
+
/* Special cases:
* 1. A null pattern with mtype == MATCH_BEG means to prefix STRING
* with REP and return the result.
* 2. A null pattern with mtype == MATCH_END means to append REP to
* STRING and return the result.
+ * These don't understand or process `&' in the replacement string.
*/
if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
{
if (match_pattern (str, pat, mtype, &s, &e) == 0)
break;
l = s - str;
- RESIZE_MALLOCED_BUFFER (ret, rptr, (l + replen), rsize, 64);
+
+ if (rxpand)
+ {
+ int x;
+ mlen = e - s;
+ mstr = xmalloc (mlen + 1);
+ for (x = 0; x < mlen; x++)
+ mstr[x] = s[x];
+ mstr[mlen] = '\0';
+ rstr = strcreplace (rep, '&', mstr, 0);
+ rslen = strlen (rstr);
+ }
+ else
+ {
+ rstr = rep;
+ rslen = replen;
+ }
+
+ RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64);
/* OK, now copy the leading unmatched portion of the string (from
str to s) to ret starting at rptr (the current offset). Then copy
}
if (replen)
{
- strncpy (ret + rptr, rep, replen);
- rptr += replen;
+ strncpy (ret + rptr, rstr, rslen);
+ rptr += rslen;
}
str = e; /* e == end of match */
+ if (rstr != rep)
+ free (rstr);
+
if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
break;
static char *mb_substring __P((char *, int, int));
static char *parameter_brace_substring __P((char *, char *, char *, int));
+static int shouldexp_replacement __P((char *));
+
static char *pos_params_pat_subst __P((char *, char *, char *, int));
static char *parameter_brace_patsub __P((char *, char *, char *, int));
return ((xret == param) ? savestring (param) : xret);
}
oret = ret = remove_wpattern (wparam, n, wpattern, op);
+ /* Don't bother to convert wparam back to multibyte string if nothing
+ matched; just return copy of original string */
if (ret == wparam)
{
free (wparam);
/* */
/****************************************************************/
+static int
+shouldexp_replacement (s)
+ char *s;
+{
+ register char *p;
+
+ for (p = s; p && *p; p++)
+ {
+ if (*p == '\\')
+ p++;
+ else if (*p == '&')
+ return 1;
+ }
+ return 0;
+}
+
char *
pat_subst (string, pat, rep, mflags)
char *string, *pat, *rep;
int mflags;
{
- char *ret, *s, *e, *str;
- int rsize, rptr, l, replen, mtype;
+ char *ret, *s, *e, *str, *rstr, *mstr;
+ int rsize, rptr, l, replen, mtype, rxpand, rslen, mlen;
mtype = mflags & MATCH_TYPEMASK;
+ rxpand = (rep && *rep) ? shouldexp_replacement (rep) : 0;
+
/* Special cases:
* 1. A null pattern with mtype == MATCH_BEG means to prefix STRING
* with REP and return the result.
if (match_pattern (str, pat, mtype, &s, &e) == 0)
break;
l = s - str;
- RESIZE_MALLOCED_BUFFER (ret, rptr, (l + replen), rsize, 64);
+
+ if (rxpand)
+ {
+ int x;
+ mlen = e - s;
+ mstr = xmalloc (mlen + 1);
+ for (x = 0; x < mlen; x++)
+ mstr[x] = s[x];
+ mstr[mlen] = '\0';
+ rstr = strcreplace (rep, '&', mstr, 0);
+ rslen = strlen (rstr);
+ }
+ else
+ {
+ rstr = rep;
+ rslen = replen;
+ }
+
+ RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64);
/* OK, now copy the leading unmatched portion of the string (from
str to s) to ret starting at rptr (the current offset). Then copy
}
if (replen)
{
- strncpy (ret + rptr, rep, replen);
- rptr += replen;
+ strncpy (ret + rptr, rstr, rslen);
+ rptr += rslen;
}
str = e; /* e == end of match */
+ if (rstr != rep)
+ free (rstr);
+
if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
break;
-BUILD_DIR=/usr/local/build/bash/bash-current
+BUILD_DIR=/usr/local/build/chet/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
+if [ -x /usr/bin/true ]; then
+ bintrue=/usr/bin/true
+elif [ -x /bin/true ]; then
+ bintrue=/bin/true
+else
+ bintrue=true
+fi
+if [ -x /usr/bin/false ]; then
+ binfalse=/usr/bin/false
+elif [ -x /bin/false ]; then
+ binfalse=/bin/false
+else
+ binfalse=true
+fi
+
shopt -s lastpipe
unset foo bar
exit 142 | false
echo $? -- ${PIPESTATUS[@]}
-true | false | /usr/bin/true
+true | false | $bintrue
echo $? -- ${PIPESTATUS[@]}
-true | /usr/bin/true | false
+true | $bintrue | false
echo $? -- ${PIPESTATUS[@]}
set -o pipefail
-true | /usr/bin/true | false
+true | $bintrue | false
echo $? -- ${PIPESTATUS[@]}
-true | /usr/bin/false | true
+true | $binfalse | true
echo $? -- ${PIPESTATUS[@]}
set +o pipefail
printf "epoch time: %(%F %r %z)T\n" 0
printf "random time: %(%F %r %z)T\n" $SECS
-printf "local time: %(%+)T\n" $SECS
+printf "local time: %(%a %b %e %H:%M:%S %Z %Y)T\n" $SECS
# test fieldwidth, justification, precision
-printf "%-40.50(%+)T date-style time\n" $SECS
+printf "%-40.50(%a %b %e %H:%M:%S %Z %Y)T date-style time\n" $SECS
# test fieldwidth, justification, precision, embedded parens
printf "%-40.50(%x (foo) %X)T date-style time\n" $SECS