mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-30 17:09:50 +02:00
commit bash-20150501 snapshot
This commit is contained in:
+105
@@ -8413,3 +8413,108 @@ lib/readline/{rltty,terminal}.c
|
||||
- sys/ioctl.h: include unconditionally for ioctl declaration, avoid issues
|
||||
with `implicit declaration' warnings. Issue originally raised on gdb
|
||||
list by Chen Gang <xili_gchen_5257@hotmail.com>
|
||||
|
||||
4/27
|
||||
----
|
||||
lib/malloc/table.c
|
||||
- mem_table: now a circular buffer showing the state of the last
|
||||
REG_TABLE_SIZE allocations rather than a hash table that quickly fills
|
||||
up
|
||||
|
||||
builtins/declare.def
|
||||
- typeset_builtin: add -n to list of supported options. Omission reported
|
||||
by Valentin Bajrami <valentin.bajrami@gmail.com>
|
||||
|
||||
unwind_prot.c
|
||||
- use object caches instead of malloc/free to allocate and deallocate
|
||||
unwind-protect elements
|
||||
- uwp_init: initialize unwind-protect element object cache
|
||||
|
||||
unwind_prot.h
|
||||
- uwp_init: extern declaration
|
||||
|
||||
shell.c
|
||||
- main: call uwp_init right after calling cmd_init -- initialize all the
|
||||
object caches at the same place
|
||||
|
||||
lib/malloc/table.[ch]
|
||||
- mlocation_table: new table to keep track of allocation locations by
|
||||
file and line, functions to initialize table, record an allocation,
|
||||
and dump the table to stderr
|
||||
- mregister_alloc: call mlocation_register_alloc to record the location
|
||||
(source file/line) for each allocation to pinpoint malloc hot spots
|
||||
by number of calls. More detail than gprof
|
||||
|
||||
parse.y
|
||||
- set_line_mbstate: replace free/xmalloc pair with xrealloc call
|
||||
- read_token_word: call alloc_word_desc instead of xmalloc so we can take
|
||||
advantage of the WORD_DESC cache
|
||||
|
||||
4/28
|
||||
----
|
||||
execute_cmd.c
|
||||
- execute_simple_command: if command execution fails because the command
|
||||
is a directory, and the `autocd' option is set, add a `--' argument
|
||||
to the constructed `cd' command to protect against command names with
|
||||
the same name as options to `cd'. Report and fix from
|
||||
isabella parakiss <izaberina@gmail.com>
|
||||
|
||||
4/30
|
||||
----
|
||||
jobs.c
|
||||
- printable_job_status, j_strsignal: change calls to strcpy and sprintf
|
||||
that write to retcode_name_buffer to use strncpy and snprintf to
|
||||
avoid buffer overflows caused by malicious translations. Bug and fix
|
||||
from Trammell Hudson <Trammell.Hudson@twosigma.com>
|
||||
|
||||
5/1
|
||||
---
|
||||
strtrans.c
|
||||
- ansicstr: make sure the buffer is at least 12 bytes to ensure enough
|
||||
space for any eventual call to u32cesc for one multibyte char
|
||||
|
||||
5/4
|
||||
---
|
||||
jobs.c
|
||||
- wait_for: if an interactive shell is running a loop and waiting for
|
||||
a non-builtin command to exit, and the command exits due to SIGINT,
|
||||
act as if the shell received the SIGINT as well and break the loop.
|
||||
This matches the behavior when the shell is running a builtin command
|
||||
in a loop, and when running a non-builtin command outside a loop, and
|
||||
seems more broadly useful than running the trap handler over and over
|
||||
again. Report originally from Kaz Kylheku <kkylheku@gnu.org>
|
||||
|
||||
builtins/set.def
|
||||
- unset_builtin: use different variables for keeping the state of the
|
||||
-f and -v options than the loop uses to decide whether or not to
|
||||
treat a name as a function or a variable. Fixes problem with
|
||||
unset_function setting `sticking' after you unset a function when
|
||||
invoked with no options. Bug report from Dreamcat4
|
||||
<dreamcat4@gmail.com>
|
||||
|
||||
shell.c
|
||||
- open_shell_script: set running_shell_script to 1, set to 0 in every
|
||||
other case (new variable)
|
||||
- main: when checking whether or not to call start_debugger, test
|
||||
running_shell_script instead of dollar_vars[1]. The goal is to not
|
||||
invoke the debugger for interactive shells but allow it to run for
|
||||
things like `bash --debugger -i /tmp/script'. Problem reported by
|
||||
Rocky Bernstein <rocky@gnu.org>
|
||||
|
||||
lib/readline/histexpand.c
|
||||
- history_event_delimiter_chars: new (as yet undocumented) variable
|
||||
containing by default characters that can delimit a history event
|
||||
specifier without requiring a `:': "^$*%-" as the documentation has
|
||||
always said. Fixes bug reported by Anders Granlund
|
||||
<anders.granlund.0@gmail.com>
|
||||
|
||||
5/10
|
||||
----
|
||||
lib/glob/gmisc.c
|
||||
- match_pattern_char, match_pattern_wchar: if passed an empty string,
|
||||
return a match if the first character of the pattern is `*'
|
||||
|
||||
subst.c
|
||||
- pat_subst: change to allow empty strings to be replaced as long as
|
||||
pattern matches empty string. Report and fix from isabella parakiss
|
||||
<izaberina@gmail.com>
|
||||
|
||||
@@ -857,6 +857,7 @@ tests/builtins2.sub f
|
||||
tests/builtins3.sub f
|
||||
tests/builtins4.sub f
|
||||
tests/builtins5.sub f
|
||||
tests/builtins6.sub f
|
||||
tests/source1.sub f
|
||||
tests/source2.sub f
|
||||
tests/source3.sub f
|
||||
@@ -872,6 +873,7 @@ tests/casemod.right f
|
||||
tests/comsub.tests f
|
||||
tests/comsub.right f
|
||||
tests/comsub1.sub f
|
||||
tests/comsub2.sub f
|
||||
tests/comsub-eof.tests f
|
||||
tests/comsub-eof0.sub f
|
||||
tests/comsub-eof1.sub f
|
||||
@@ -929,6 +931,8 @@ tests/errors.right f
|
||||
tests/errors1.sub f
|
||||
tests/errors2.sub f
|
||||
tests/errors3.sub f
|
||||
tests/errors4.sub f
|
||||
tests/errors5.sub f
|
||||
tests/execscript f
|
||||
tests/exec.right f
|
||||
tests/exec1.sub f 755
|
||||
@@ -1043,6 +1047,7 @@ tests/nameref5.sub f
|
||||
tests/nameref6.sub f
|
||||
tests/nameref7.sub f
|
||||
tests/nameref8.sub f
|
||||
tests/nameref9.sub f
|
||||
tests/nameref.right f
|
||||
tests/new-exp.tests f
|
||||
tests/new-exp1.sub f
|
||||
@@ -1261,6 +1266,7 @@ tests/vredir3.sub f
|
||||
tests/vredir4.sub f
|
||||
tests/vredir5.sub f
|
||||
tests/vredir6.sub f
|
||||
tests/vredir7.sub f
|
||||
tests/misc/dev-tcp.tests f
|
||||
tests/misc/perf-script f
|
||||
tests/misc/perftest f
|
||||
|
||||
@@ -171,7 +171,7 @@ find_compopt (name)
|
||||
/* Build the actions and compspec options from the options specified in LIST.
|
||||
ACTP is a pointer to an unsigned long in which to place the bitmap of
|
||||
actions. OPTP is a pointer to an unsigned long in which to place the
|
||||
btmap of compspec options (arguments to `-o'). PP, if non-null, gets 1
|
||||
bitmap of compspec options (arguments to `-o'). PP, if non-null, gets 1
|
||||
if -p is supplied; RP, if non-null, gets 1 if -r is supplied.
|
||||
If either is null, the corresponding option generates an error.
|
||||
This also sets variables corresponding to options that take arguments as
|
||||
|
||||
@@ -62,7 +62,7 @@ $END
|
||||
|
||||
$BUILTIN typeset
|
||||
$FUNCTION declare_builtin
|
||||
$SHORT_DOC typeset [-aAfFgilrtux] [-p] name[=value] ...
|
||||
$SHORT_DOC typeset [-aAfFgilnrtux] [-p] name[=value] ...
|
||||
Set variable values and attributes.
|
||||
|
||||
Obsolete. See `help declare'.
|
||||
|
||||
+8
-3
@@ -796,9 +796,11 @@ unset_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int unset_function, unset_variable, unset_array, opt, nameref, any_failed;
|
||||
int global_unset_func, global_unset_var;
|
||||
char *name;
|
||||
|
||||
unset_function = unset_variable = unset_array = nameref = any_failed = 0;
|
||||
global_unset_func = global_unset_var = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "fnv")) != -1)
|
||||
@@ -806,10 +808,10 @@ unset_builtin (list)
|
||||
switch (opt)
|
||||
{
|
||||
case 'f':
|
||||
unset_function = 1;
|
||||
global_unset_func = 1;
|
||||
break;
|
||||
case 'v':
|
||||
unset_variable = 1;
|
||||
global_unset_var = 1;
|
||||
break;
|
||||
case 'n':
|
||||
nameref = 1;
|
||||
@@ -822,7 +824,7 @@ unset_builtin (list)
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (unset_function && unset_variable)
|
||||
if (global_unset_func && global_unset_var)
|
||||
{
|
||||
builtin_error (_("cannot simultaneously unset a function and a variable"));
|
||||
return (EXECUTION_FAILURE);
|
||||
@@ -840,6 +842,9 @@ unset_builtin (list)
|
||||
|
||||
name = list->word->word;
|
||||
|
||||
unset_function = global_unset_func;
|
||||
unset_variable = global_unset_var;
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
unset_array = 0;
|
||||
if (!unset_function && valid_array_reference (name, 0))
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ static int display_traps __P((WORD_LIST *));
|
||||
trap -p [sigspec ...]
|
||||
trap [--]
|
||||
|
||||
Set things up so that ARG is executed when SIGNAL(s) N is recieved.
|
||||
Set things up so that ARG is executed when SIGNAL(s) N is received.
|
||||
If ARG is the empty string, then ignore the SIGNAL(s). If there is
|
||||
no ARG, then set the trap for SIGNAL(s) to its original value. Just
|
||||
plain "trap" means to print out the list of commands associated with
|
||||
|
||||
+6
-5
@@ -643,7 +643,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
|
||||
if (s)
|
||||
subshell_exit (last_command_exit_value);
|
||||
else
|
||||
exit (last_command_exit_value);
|
||||
sh_exit (last_command_exit_value);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
else
|
||||
@@ -3926,7 +3926,7 @@ is_dirname (pathname)
|
||||
int ret;
|
||||
|
||||
temp = search_for_command (pathname, 0);
|
||||
ret = (temp ? file_isdir (temp) : file_isdir (pathname));
|
||||
ret = temp ? file_isdir (temp) : file_isdir (pathname);
|
||||
free (temp);
|
||||
return ret;
|
||||
}
|
||||
@@ -4086,7 +4086,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
|
||||
pipe_in, pipe_out,
|
||||
already_forked ? 0 : async);
|
||||
if (already_forked)
|
||||
exit (result);
|
||||
sh_exit (result);
|
||||
else
|
||||
{
|
||||
bind_lastarg ((char *)NULL);
|
||||
@@ -4283,6 +4283,7 @@ run_builtin:
|
||||
|
||||
if (autocd && interactive && words->word && is_dirname (words->word->word))
|
||||
{
|
||||
words = make_word_list (make_word ("--"), words);
|
||||
words = make_word_list (make_word ("cd"), words);
|
||||
xtrace_print_word_list (words, 0);
|
||||
goto run_builtin;
|
||||
@@ -4850,14 +4851,14 @@ execute_subshell_builtin_or_function (words, redirects, builtin, var,
|
||||
fflush (stdout);
|
||||
if (r == EX_USAGE)
|
||||
r = EX_BADUSAGE;
|
||||
exit (r);
|
||||
sh_exit (r);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
r = execute_function (var, words, flags, fds_to_close, async, 1);
|
||||
fflush (stdout);
|
||||
exit (r);
|
||||
sh_exit (r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -407,9 +407,7 @@ fd_ispipe (fd)
|
||||
int fd;
|
||||
{
|
||||
errno = 0;
|
||||
if (lseek ((fd), 0L, SEEK_CUR) < 0)
|
||||
return (errno == ESPIPE);
|
||||
return 0;
|
||||
return ((lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE));
|
||||
}
|
||||
|
||||
/* There is a bug in the NeXT 2.1 rlogind that causes opens
|
||||
|
||||
@@ -124,7 +124,7 @@ typedef struct {
|
||||
int token;
|
||||
} STRING_INT_ALIST;
|
||||
|
||||
/* A macro to avoid making an unneccessary function call. */
|
||||
/* A macro to avoid making an unnecessary function call. */
|
||||
#define REVERSE_LIST(list, type) \
|
||||
((list && list->next) ? (type)list_reverse ((GENERIC_LIST *)list) \
|
||||
: (type)(list))
|
||||
|
||||
@@ -1489,7 +1489,7 @@ j_strsignal (s)
|
||||
if (x == 0)
|
||||
{
|
||||
x = retcode_name_buffer;
|
||||
sprintf (x, _("Signal %d"), s);
|
||||
snprintf (x, sizeof(retcode_name_buffer), _("Signal %d"), s);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
@@ -1512,7 +1512,7 @@ printable_job_status (j, p, format)
|
||||
else
|
||||
{
|
||||
temp = retcode_name_buffer;
|
||||
sprintf (temp, _("Stopped(%s)"), signal_name (WSTOPSIG (p->status)));
|
||||
snprintf (temp, sizeof(retcode_name_buffer), _("Stopped(%s)"), signal_name (WSTOPSIG (p->status)));
|
||||
}
|
||||
}
|
||||
else if (RUNNING (j))
|
||||
@@ -1528,11 +1528,14 @@ printable_job_status (j, p, format)
|
||||
temp = retcode_name_buffer;
|
||||
es = WEXITSTATUS (p->status);
|
||||
if (es == 0)
|
||||
strcpy (temp, _("Done"));
|
||||
{
|
||||
strncpy (temp, _("Done"), sizeof (retcode_name_buffer) - 1);
|
||||
temp[sizeof (retcode_name_buffer) - 1] = '\0';
|
||||
}
|
||||
else if (posixly_correct)
|
||||
sprintf (temp, _("Done(%d)"), es);
|
||||
snprintf (temp, sizeof(retcode_name_buffer), _("Done(%d)"), es);
|
||||
else
|
||||
sprintf (temp, _("Exit %d"), es);
|
||||
snprintf (temp, sizeof(retcode_name_buffer), _("Exit %d"), es);
|
||||
}
|
||||
else
|
||||
temp = _("Unknown status");
|
||||
@@ -2709,6 +2712,14 @@ if (job == NO_JOB)
|
||||
SIGINT signal handler; maybe it should. */
|
||||
if (signal_is_trapped (SIGINT) == 0 && (loop_level || (shell_compatibility_level > 32 && executing_list)))
|
||||
ADDINTERRUPT;
|
||||
/* Call any SIGINT trap handler if the shell is running a loop, so
|
||||
the loop can be broken. This seems more useful and matches the
|
||||
behavior when the shell is running a builtin command in a loop
|
||||
when it is interrupted. Change ADDINTERRUPT to
|
||||
trap_handler (SIGINT) to run the trap without interrupting the
|
||||
loop. */
|
||||
else if (signal_is_trapped (SIGINT) && loop_level)
|
||||
ADDINTERRUPT;
|
||||
else
|
||||
{
|
||||
putchar ('\n');
|
||||
|
||||
+2
-2
@@ -64,7 +64,7 @@ match_pattern_wchar (wpat, wstring, flags)
|
||||
wchar_t wc;
|
||||
|
||||
if (*wstring == 0)
|
||||
return (0);
|
||||
return (*wpat == L'*'); /* XXX - allow only * to match empty string */
|
||||
|
||||
switch (wc = *wpat++)
|
||||
{
|
||||
@@ -249,7 +249,7 @@ match_pattern_char (pat, string, flags)
|
||||
char c;
|
||||
|
||||
if (*string == 0)
|
||||
return (0);
|
||||
return (*pat == '*'); /* XXX - allow only * to match empty string */
|
||||
|
||||
switch (c = *pat++)
|
||||
{
|
||||
|
||||
+141
-43
@@ -37,14 +37,25 @@ extern int malloc_register;
|
||||
|
||||
#ifdef MALLOC_REGISTER
|
||||
|
||||
#define FIND_ALLOC 0x01 /* allocate new entry or find existing */
|
||||
#define FIND_EXIST 0x02 /* find existing entry */
|
||||
extern FILE *_imalloc_fopen __P((char *, char *, char *, char *, size_t));
|
||||
|
||||
#define FIND_ALLOC 0x01 /* find slot for new allocation */
|
||||
#define FIND_EXIST 0x02 /* find slot for existing entry for free() or search */
|
||||
|
||||
static int table_count = 0;
|
||||
static int table_allocated = 0;
|
||||
static int table_bucket_index = REG_TABLE_SIZE-1;
|
||||
static mr_table_t mem_table[REG_TABLE_SIZE];
|
||||
static mr_table_t mem_overflow;
|
||||
|
||||
#ifndef STREQ
|
||||
#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0)
|
||||
#endif
|
||||
|
||||
static int location_table_index = 0;
|
||||
static int location_table_count = 0;
|
||||
static ma_table_t mlocation_table[REG_TABLE_SIZE];
|
||||
|
||||
/*
|
||||
* NOTE: taken from dmalloc (http://dmalloc.com) and modified.
|
||||
*/
|
||||
@@ -72,8 +83,15 @@ which_bucket (mem)
|
||||
{
|
||||
return (mt_hash ((unsigned char *)mem) & (REG_TABLE_SIZE-1));
|
||||
}
|
||||
|
||||
#else
|
||||
#define which_bucket(mem) (mt_hash ((unsigned char *)(mem)) & (REG_TABLE_SIZE-1));
|
||||
|
||||
#define next_bucket() ((table_bucket_index + 1) & (REG_TABLE_SIZE-1))
|
||||
#define next_entry(mem) ((mem == mem_table + REG_TABLE_SIZE - 1) ? mem_table : ++mem)
|
||||
|
||||
#define prev_bucket() (table_bucket_index == 0 ? REG_TABLE_SIZE-1 : table_bucket_index-1)
|
||||
#define prev_entry(mem) ((mem == mem_table) ? mem_table + REG_TABLE_SIZE - 1 : mem - 1)
|
||||
#endif
|
||||
|
||||
static mr_table_t *
|
||||
@@ -83,60 +101,37 @@ find_entry (mem, flags)
|
||||
{
|
||||
unsigned int bucket;
|
||||
register mr_table_t *tp;
|
||||
mr_table_t *endp, *lastp;
|
||||
mr_table_t *endp;
|
||||
|
||||
if (mem_overflow.mem == mem)
|
||||
return (&mem_overflow);
|
||||
|
||||
bucket = which_bucket (mem); /* get initial hash */
|
||||
tp = endp = mem_table + bucket;
|
||||
lastp = mem_table + REG_TABLE_SIZE;
|
||||
/* If we want to insert an allocation entry just use the next slot */
|
||||
if (flags & FIND_ALLOC)
|
||||
{
|
||||
table_bucket_index = next_bucket();
|
||||
table_count++;
|
||||
tp = mem_table + table_bucket_index;
|
||||
memset(tp, 0, sizeof (mr_table_t)); /* overwrite next existing entry */
|
||||
return tp;
|
||||
}
|
||||
|
||||
tp = endp = mem_table + table_bucket_index;
|
||||
|
||||
/* search for last allocation corresponding to MEM, return entry pointer */
|
||||
while (1)
|
||||
{
|
||||
if (tp->mem == mem)
|
||||
return (tp);
|
||||
if (tp->mem == 0 && (flags & FIND_ALLOC))
|
||||
{
|
||||
table_count++;
|
||||
return (tp);
|
||||
}
|
||||
|
||||
tp++;
|
||||
tp = prev_entry (tp);
|
||||
|
||||
if (tp == lastp) /* wrap around */
|
||||
tp = mem_table;
|
||||
|
||||
if (tp == endp && (flags & FIND_EXIST))
|
||||
/* if we went all the way around and didn't find it, return NULL */
|
||||
if (tp == endp)
|
||||
return ((mr_table_t *)NULL);
|
||||
|
||||
if (tp == endp && (flags & FIND_ALLOC))
|
||||
break;
|
||||
}
|
||||
|
||||
/* oops. table is full. replace an existing free entry. */
|
||||
do
|
||||
{
|
||||
/* If there are no free entries, punt right away without searching. */
|
||||
if (table_allocated == REG_TABLE_SIZE)
|
||||
break;
|
||||
|
||||
if (tp->flags & MT_FREE)
|
||||
{
|
||||
memset(tp, 0, sizeof (mr_table_t));
|
||||
return (tp);
|
||||
}
|
||||
tp++;
|
||||
|
||||
if (tp == lastp)
|
||||
tp = mem_table;
|
||||
}
|
||||
while (tp != endp);
|
||||
|
||||
/* wow. entirely full. return mem_overflow dummy entry. */
|
||||
tp = &mem_overflow;
|
||||
memset (tp, 0, sizeof (mr_table_t));
|
||||
return tp;
|
||||
return (mr_table_t *)NULL;
|
||||
}
|
||||
|
||||
mr_table_t *
|
||||
@@ -186,6 +181,8 @@ mregister_alloc (tag, mem, size, file, line)
|
||||
blocked_sigs = 1;
|
||||
}
|
||||
|
||||
mlocation_register_alloc (file, line);
|
||||
|
||||
tentry = find_entry (mem, FIND_ALLOC);
|
||||
|
||||
if (tentry == 0)
|
||||
@@ -293,7 +290,9 @@ _register_dump_table(fp)
|
||||
{
|
||||
entry = mem_table[i];
|
||||
if (entry.mem)
|
||||
fprintf (fp, "[%d] %p:%d:%s:%s:%s:%d:%d:%d\n", i,
|
||||
fprintf (fp, "%s[%d] %p:%d:%s:%s:%s:%d:%d:%d\n",
|
||||
(i == table_bucket_index) ? "*" : "",
|
||||
i,
|
||||
entry.mem, entry.size,
|
||||
_entry_flags(entry.flags),
|
||||
entry.func ? entry.func : "unknown",
|
||||
@@ -317,6 +316,105 @@ mregister_table_init ()
|
||||
table_count = 0;
|
||||
}
|
||||
|
||||
/* Simple for now */
|
||||
|
||||
static ma_table_t *
|
||||
find_location_entry (file, line)
|
||||
const char *file;
|
||||
int line;
|
||||
{
|
||||
register ma_table_t *tp, *endp;
|
||||
|
||||
endp = mlocation_table + location_table_count;
|
||||
for (tp = mlocation_table; tp <= endp; tp++)
|
||||
{
|
||||
if (tp->line == line && STREQ (file, tp->file))
|
||||
return tp;
|
||||
}
|
||||
return (ma_table_t *)NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mlocation_register_alloc (file, line)
|
||||
const char *file;
|
||||
int line;
|
||||
{
|
||||
ma_table_t *lentry;
|
||||
char *nfile;
|
||||
|
||||
if (file == 0)
|
||||
{
|
||||
mlocation_table[0].nalloc++;
|
||||
return;
|
||||
}
|
||||
|
||||
nfile = strrchr (file, '/');
|
||||
if (nfile)
|
||||
nfile++;
|
||||
else
|
||||
nfile = file;
|
||||
|
||||
lentry = find_location_entry (nfile, line);
|
||||
if (lentry == 0)
|
||||
{
|
||||
location_table_index++;
|
||||
if (location_table_index == REG_TABLE_SIZE)
|
||||
location_table_index = 1; /* slot 0 reserved */
|
||||
lentry = mlocation_table + location_table_index;
|
||||
lentry->file = nfile;
|
||||
lentry->line = line;
|
||||
lentry->nalloc = 1;
|
||||
if (location_table_count < REG_TABLE_SIZE)
|
||||
location_table_count++; /* clamp at REG_TABLE_SIZE for now */
|
||||
}
|
||||
else
|
||||
lentry->nalloc++;
|
||||
}
|
||||
|
||||
static void
|
||||
_location_dump_table (fp)
|
||||
FILE *fp;
|
||||
{
|
||||
register ma_table_t *tp, *endp;
|
||||
|
||||
endp = mlocation_table + location_table_count;
|
||||
for (tp = mlocation_table; tp < endp; tp++)
|
||||
fprintf (fp, "%s:%d\t%d\n", tp->file ? tp->file : "unknown",
|
||||
tp->line ? tp->line : 0,
|
||||
tp->nalloc);
|
||||
}
|
||||
|
||||
void
|
||||
mlocation_dump_table ()
|
||||
{
|
||||
_location_dump_table (stderr);
|
||||
}
|
||||
|
||||
#define LOCROOT "/var/tmp/maltrace/locations."
|
||||
|
||||
void
|
||||
mlocation_write_table ()
|
||||
{
|
||||
FILE *fp;
|
||||
char defname[sizeof (LOCROOT) + 64];
|
||||
|
||||
fp = _imalloc_fopen ((char *)NULL, (char *)NULL, LOCROOT, defname, sizeof (defname));
|
||||
if (fp == 0)
|
||||
return; /* XXX - no error message yet */
|
||||
_location_dump_table (fp);
|
||||
fclose (fp);
|
||||
}
|
||||
|
||||
void
|
||||
mlocation_table_init ()
|
||||
{
|
||||
memset (mlocation_table, 0, sizeof (ma_table_t) * REG_TABLE_SIZE);
|
||||
mlocation_table[0].file = ""; /* reserve slot 0 for unknown locations */
|
||||
mlocation_table[0].line = 0;
|
||||
mlocation_table[0].nalloc = 0;
|
||||
location_table_count = 1;
|
||||
}
|
||||
|
||||
#endif /* MALLOC_REGISTER */
|
||||
|
||||
int
|
||||
|
||||
@@ -64,6 +64,17 @@ extern void mregister_describe_mem ();
|
||||
extern void mregister_dump_table __P((void));
|
||||
extern void mregister_table_init __P((void));
|
||||
|
||||
typedef struct ma_table {
|
||||
char *file;
|
||||
int line;
|
||||
int nalloc;
|
||||
} ma_table_t;
|
||||
|
||||
extern void mlocation_register_alloc __P((const char *, int));
|
||||
extern void mlocation_table_init __P((void));
|
||||
extern void mlocation_dump_table __P((void));
|
||||
extern void mlocation_write_table __P((void));
|
||||
|
||||
/* NOTE: HASH_MIX taken from dmalloc (http://dmalloc.com) */
|
||||
|
||||
/*
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
|
||||
#define HISTORY_WORD_DELIMITERS " \t\n;&()|<>"
|
||||
#define HISTORY_QUOTE_CHARACTERS "\"'`"
|
||||
#define HISTORY_EVENT_DELIMITERS "^$*%-"
|
||||
|
||||
#define slashify_in_quotes "\\`\"$"
|
||||
|
||||
@@ -62,6 +63,10 @@ static char *subst_rhs;
|
||||
static int subst_lhs_len;
|
||||
static int subst_rhs_len;
|
||||
|
||||
/* Characters that delimit history event specifications and separate event
|
||||
specifications from word designators. Static for now */
|
||||
static char *history_event_delimiter_chars = HISTORY_EVENT_DELIMITERS;
|
||||
|
||||
static char *get_history_word_specifier PARAMS((char *, char *, int *));
|
||||
static int history_tokenize_word PARAMS((const char *, int));
|
||||
static char **history_tokenize_internal PARAMS((const char *, int, int *));
|
||||
@@ -112,7 +117,6 @@ rl_linebuf_func_t *history_inhibit_expansion_function;
|
||||
|
||||
/* The last string searched for by a !?string? search. */
|
||||
static char *search_string;
|
||||
|
||||
/* The last string matched by a !?string? search. */
|
||||
static char *search_match;
|
||||
|
||||
@@ -225,6 +229,7 @@ get_history_event (string, caller_index, delimiting_quote)
|
||||
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
if ((!substring_okay && (whitespace (c) || c == ':' ||
|
||||
(history_event_delimiter_chars && member (c, history_event_delimiter_chars)) ||
|
||||
(history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||
|
||||
string[i] == delimiting_quote)) ||
|
||||
string[i] == '\n' ||
|
||||
@@ -873,7 +878,7 @@ history_expand_internal (string, start, qc, end_index_ptr, ret_string, current_l
|
||||
1) If expansions did take place
|
||||
2) If the `p' modifier was given and the caller should print the result
|
||||
|
||||
If an error ocurred in expansion, then OUTPUT contains a descriptive
|
||||
If an error occurred in expansion, then OUTPUT contains a descriptive
|
||||
error message. */
|
||||
|
||||
#define ADD_STRING(s) \
|
||||
|
||||
+4
-1
@@ -60,7 +60,10 @@ ansicstr (string, len, flags, sawc, rlen)
|
||||
return ((char *)NULL);
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
ret = (char *)xmalloc (4*len + 1);
|
||||
temp = 4*len + 1;
|
||||
if (temp < 12)
|
||||
temp = 12; /* ensure enough for eventual u32cesc */
|
||||
ret = (char *)xmalloc (temp);
|
||||
#else
|
||||
ret = (char *)xmalloc (2*len + 1); /* 2*len for possible CTLESC */
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -236,7 +236,7 @@ u32toutf16 (c, s)
|
||||
}
|
||||
|
||||
/* convert a single unicode-32 character into a multibyte string and put the
|
||||
result in S, which must be large enough (at least MB_LEN_MAX bytes) */
|
||||
result in S, which must be large enough (at least max(10,MB_LEN_MAX) bytes) */
|
||||
int
|
||||
u32cconv (c, s)
|
||||
unsigned long c;
|
||||
|
||||
@@ -4912,7 +4912,7 @@ got_token:
|
||||
#endif
|
||||
CHECK_FOR_RESERVED_WORD (token);
|
||||
|
||||
the_word = (WORD_DESC *)xmalloc (sizeof (WORD_DESC));
|
||||
the_word = alloc_word_desc ();
|
||||
the_word->word = (char *)xmalloc (1 + token_index);
|
||||
the_word->flags = 0;
|
||||
strcpy (the_word->word, token);
|
||||
@@ -6258,8 +6258,7 @@ set_line_mbstate ()
|
||||
if (shell_input_line == NULL)
|
||||
return;
|
||||
len = strlen (shell_input_line); /* XXX - shell_input_line_len ? */
|
||||
FREE (shell_input_line_property);
|
||||
shell_input_line_property = (char *)xmalloc (len + 1);
|
||||
shell_input_line_property = (char *)xrealloc (shell_input_line_property, len + 1);
|
||||
|
||||
memset (&prevs, '\0', sizeof (mbstate_t));
|
||||
for (i = previ = 0; i < len; i++)
|
||||
|
||||
@@ -118,10 +118,13 @@ redirection_error (temp, error)
|
||||
allocname = 0;
|
||||
if ((temp->rflags & REDIR_VARASSIGN) && error < 0)
|
||||
filename = allocname = savestring (temp->redirector.filename->word);
|
||||
else if (temp->redirector.dest < 0)
|
||||
else if ((temp->rflags & REDIR_VARASSIGN) == 0 && temp->redirector.dest < 0)
|
||||
/* This can happen when read_token_word encounters overflow, like in
|
||||
exec 4294967297>x */
|
||||
{
|
||||
itrace("redirection_error: temp->redirector.dest = %d", temp->redirector.dest);
|
||||
filename = _("file descriptor out of range");
|
||||
}
|
||||
#ifdef EBADF
|
||||
/* This error can never involve NOCLOBBER */
|
||||
else if (error != NOCLOBBER_REDIRECT && temp->redirector.dest >= 0 && error == EBADF)
|
||||
|
||||
@@ -160,6 +160,7 @@ int autocd = 0;
|
||||
This is a superset of the information provided by interactive_shell.
|
||||
*/
|
||||
int startup_state = 0;
|
||||
int reading_shell_script = 0;
|
||||
|
||||
/* Special debugging helper. */
|
||||
int debugging_login_shell = 0;
|
||||
@@ -390,7 +391,7 @@ main (argc, argv, env)
|
||||
xtrace_init ();
|
||||
|
||||
#if defined (USING_BASH_MALLOC) && defined (DEBUG) && !defined (DISABLE_MALLOC_WRAPPERS)
|
||||
malloc_set_register (0); /* XXX - change to 1 for malloc debugging */
|
||||
malloc_set_register (1); /* XXX - change to 1 for malloc debugging */
|
||||
#endif
|
||||
|
||||
check_dev_tty ();
|
||||
@@ -680,7 +681,8 @@ main (argc, argv, env)
|
||||
}
|
||||
#endif
|
||||
|
||||
cmd_init(); /* initialize the command object caches */
|
||||
cmd_init (); /* initialize the command object caches */
|
||||
uwp_init ();
|
||||
|
||||
if (command_execution_string)
|
||||
{
|
||||
@@ -721,7 +723,7 @@ main (argc, argv, env)
|
||||
/* Bind remaining args to $1 ... $n */
|
||||
arg_index = bind_args (argv, arg_index, argc, 1);
|
||||
|
||||
if (debugging_mode && locally_skip_execution == 0 && running_setuid == 0 && (dollar_vars[1] || interactive_shell == 0))
|
||||
if (debugging_mode && locally_skip_execution == 0 && running_setuid == 0 && (reading_shell_script || interactive_shell == 0))
|
||||
start_debugger ();
|
||||
|
||||
/* Do the things that should be done only for interactive shells. */
|
||||
@@ -965,6 +967,7 @@ sh_exit (s)
|
||||
#if defined (MALLOC_DEBUG) && defined (USING_BASH_MALLOC)
|
||||
if (malloc_trace_at_exit)
|
||||
trace_malloc_stats (get_name_for_error (), (char *)NULL);
|
||||
/* mlocation_write_table (); */
|
||||
#endif
|
||||
|
||||
exit (s);
|
||||
@@ -1465,7 +1468,7 @@ open_shell_script (script_name)
|
||||
{
|
||||
e = errno;
|
||||
file_error (filename);
|
||||
exit ((e == ENOENT) ? EX_NOTFOUND : EX_NOINPUT);
|
||||
sh_exit ((e == ENOENT) ? EX_NOTFOUND : EX_NOINPUT);
|
||||
}
|
||||
|
||||
free (dollar_vars[0]);
|
||||
@@ -1484,7 +1487,7 @@ open_shell_script (script_name)
|
||||
errno = EINVAL;
|
||||
#endif
|
||||
file_error (filename);
|
||||
exit (EX_NOINPUT);
|
||||
sh_exit (EX_NOINPUT);
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
@@ -1586,6 +1589,8 @@ open_shell_script (script_name)
|
||||
init_interactive_script ();
|
||||
|
||||
free (filename);
|
||||
|
||||
reading_shell_script = 1;
|
||||
return (fd);
|
||||
}
|
||||
|
||||
|
||||
@@ -595,6 +595,7 @@ quoted_strchr (s, c, flags)
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
#if defined (INCLUDE_UNUSED)
|
||||
/* Return 1 if CHARACTER appears in an unquoted portion of
|
||||
STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */
|
||||
static int
|
||||
@@ -679,6 +680,7 @@ unquoted_substring (substr, string)
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Most of the substitutions must be done in parallel. In order
|
||||
to avoid using tons of unclear goto's, I have some functions
|
||||
@@ -4435,7 +4437,7 @@ match_pattern (string, pat, mtype, sp, ep)
|
||||
size_t slen, plen, mslen, mplen;
|
||||
#endif
|
||||
|
||||
if (string == 0 || *string == 0 || pat == 0 || *pat == 0)
|
||||
if (string == 0 || pat == 0 || *pat == 0)
|
||||
return (0);
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
@@ -4709,7 +4711,7 @@ string_var_assignment (v, s)
|
||||
|
||||
val = sh_quote_reusable (s, 0);
|
||||
i = var_attribute_string (v, 0, flags);
|
||||
ret = (char *)xmalloc (i + strlen (val) + strlen (v->name) + 16);
|
||||
ret = (char *)xmalloc (i + strlen (val) + strlen (v->name) + 16 + MAX_ATTRIBUTES);
|
||||
if (i > 0)
|
||||
sprintf (ret, "declare -%s %s=%s", flags, v->name, val);
|
||||
else
|
||||
@@ -7001,6 +7003,7 @@ parameter_brace_substring (varname, value, ind, substr, quoted, flags)
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
#if 0 /* Unused */
|
||||
static int
|
||||
shouldexp_replacement (s)
|
||||
char *s;
|
||||
@@ -7016,6 +7019,7 @@ shouldexp_replacement (s)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *
|
||||
pat_subst (string, pat, rep, mflags)
|
||||
@@ -7041,6 +7045,8 @@ pat_subst (string, pat, rep, mflags)
|
||||
* with REP and return the result.
|
||||
* 2. A null pattern with mtype == MATCH_END means to append REP to
|
||||
* STRING and return the result.
|
||||
* 3. A null STRING with a matching pattern 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))
|
||||
@@ -7062,11 +7068,17 @@ pat_subst (string, pat, rep, mflags)
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
else if (*string == 0 && (match_pattern (string, pat, mtype, &s, &e) != 0))
|
||||
{
|
||||
ret = (char *)xmalloc (STRLEN (rep) + 1);
|
||||
strcpy (ret, rep);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
ret = (char *)xmalloc (rsize = 64);
|
||||
ret[0] = '\0';
|
||||
|
||||
for (replen = STRLEN (rep), rptr = 0, str = string;;)
|
||||
for (replen = STRLEN (rep), rptr = 0, str = string; *str;)
|
||||
{
|
||||
if (match_pattern (str, pat, mtype, &s, &e) == 0)
|
||||
break;
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
|
||||
+6
-4
@@ -141,6 +141,8 @@ ok
|
||||
-7
|
||||
7
|
||||
7
|
||||
2
|
||||
2
|
||||
./arith1.sub: line 2: 4-- : syntax error: operand expected (error token is "- ")
|
||||
./arith1.sub: line 3: 4++ : syntax error: operand expected (error token is "+ ")
|
||||
./arith1.sub: line 4: 4 -- : syntax error: operand expected (error token is "- ")
|
||||
@@ -235,13 +237,13 @@ ok
|
||||
0, 0
|
||||
0, 1
|
||||
8 12
|
||||
./arith.tests: line 286: ((: x=9 y=41 : syntax error in expression (error token is "y=41 ")
|
||||
./arith.tests: line 290: a b: syntax error in expression (error token is "b")
|
||||
./arith.tests: line 291: ((: a b: syntax error in expression (error token is "b")
|
||||
./arith.tests: line 290: ((: x=9 y=41 : syntax error in expression (error token is "y=41 ")
|
||||
./arith.tests: line 294: a b: syntax error in expression (error token is "b")
|
||||
./arith.tests: line 295: ((: a b: syntax error in expression (error token is "b")
|
||||
42
|
||||
42
|
||||
42
|
||||
42
|
||||
42
|
||||
42
|
||||
./arith.tests: line 302: b[c]d: syntax error in expression (error token is "d")
|
||||
./arith.tests: line 306: b[c]d: syntax error in expression (error token is "d")
|
||||
|
||||
@@ -260,6 +260,10 @@ echo $(( -7 ))
|
||||
echo $(( ++7 ))
|
||||
echo $(( --7 ))
|
||||
|
||||
# combinations of expansions
|
||||
echo $(( "`echo 1+1`" ))
|
||||
echo $(( `echo 1+1` ))
|
||||
|
||||
${THIS_SH} ./arith1.sub
|
||||
${THIS_SH} ./arith2.sub
|
||||
${THIS_SH} ./arith3.sub
|
||||
|
||||
+11
-6
@@ -14,9 +14,10 @@ declare -Ai chaff=([one]="10" [zero]="5" )
|
||||
declare -Ar waste=([version]="4.0-devel" [source]="./assoc.tests" [lineno]="28" [pid]="42134" )
|
||||
declare -A wheat=([two]="b" [three]="c" [one]="a" [zero]="0" )
|
||||
declare -A chaff=([one]="10" ["hello world"]="flip" [zero]="5" )
|
||||
./assoc.tests: line 38: unset: waste: cannot unset: readonly variable
|
||||
./assoc.tests: line 39: chaff[*]: bad array subscript
|
||||
./assoc.tests: line 40: [*]=12: invalid associative array key
|
||||
./assoc.tests: line 38: waste: readonly variable
|
||||
./assoc.tests: line 39: unset: waste: cannot unset: readonly variable
|
||||
./assoc.tests: line 40: chaff[*]: bad array subscript
|
||||
./assoc.tests: line 41: [*]=12: invalid associative array key
|
||||
declare -A chaff=([one]="a" ["hello world"]="flip" )
|
||||
flip
|
||||
argv[1] = <a>
|
||||
@@ -31,9 +32,9 @@ argv[2] = <flip>
|
||||
argv[3] = <multiple>
|
||||
argv[4] = <words>
|
||||
argv[1] = <a flip multiple words>
|
||||
./assoc.tests: line 57: declare: chaff: cannot destroy array variables in this way
|
||||
./assoc.tests: line 59: chaff[*]: bad array subscript
|
||||
./assoc.tests: line 60: [*]=12: invalid associative array key
|
||||
./assoc.tests: line 58: declare: chaff: cannot destroy array variables in this way
|
||||
./assoc.tests: line 60: chaff[*]: bad array subscript
|
||||
./assoc.tests: line 61: [*]=12: invalid associative array key
|
||||
declare -A wheat=([six]="6" ["foo bar"]="qux qix" )
|
||||
argv[1] = <qux>
|
||||
argv[2] = <qix>
|
||||
@@ -190,3 +191,7 @@ declare -A foo=(["bar\${foo}bie"]="doll" )
|
||||
bar
|
||||
after printf
|
||||
after use: 0
|
||||
declare -A assoc=([0]="assoc" )
|
||||
assoc
|
||||
declare -A assoc=([two]="twoless" [three]="three" [one]="onemore" )
|
||||
declare -Ar assoc=([two]="twoless" [three]="three" [one]="onemore" )
|
||||
|
||||
@@ -35,6 +35,7 @@ chaff[hello world]=flip
|
||||
declare -p chaff
|
||||
|
||||
# TEST - errors
|
||||
waste[stuff]=other
|
||||
unset waste
|
||||
chaff[*]=12
|
||||
chaff=( [one]=a [*]=12 )
|
||||
@@ -186,3 +187,21 @@ ${THIS_SH} ./assoc5.sub
|
||||
${THIS_SH} ./assoc6.sub
|
||||
|
||||
${THIS_SH} ./assoc7.sub
|
||||
|
||||
# test converting between scalars and assoc arrays
|
||||
unset assoc
|
||||
assoc=assoc
|
||||
declare -A assoc
|
||||
declare -p assoc
|
||||
echo ${assoc[@]}
|
||||
|
||||
# weird syntax required to append to multiple existing array elements using
|
||||
# compound assignment syntax
|
||||
unset assoc
|
||||
declare -A assoc
|
||||
assoc=( [one]=one [two]=two [three]=three )
|
||||
assoc+=( [one]+=more [two]+=less )
|
||||
declare -p assoc
|
||||
|
||||
readonly -A assoc
|
||||
declare -p assoc
|
||||
|
||||
+42
-1
@@ -194,4 +194,45 @@ scalar: 0
|
||||
scalar: 1
|
||||
scalar: 0
|
||||
scalar: 0
|
||||
./builtins.tests: line 263: exit: status: numeric argument required
|
||||
all set:
|
||||
one
|
||||
two
|
||||
f1 ()
|
||||
{
|
||||
echo f1
|
||||
}
|
||||
f2 ()
|
||||
{
|
||||
echo f2
|
||||
}
|
||||
all unset:
|
||||
unset1
|
||||
unset2
|
||||
./builtins6.sub: line 28: declare: f1: not found
|
||||
./builtins6.sub: line 28: declare: f2: not found
|
||||
all reset:
|
||||
one-one
|
||||
two-one
|
||||
f1 ()
|
||||
{
|
||||
echo f1
|
||||
}
|
||||
f2 ()
|
||||
{
|
||||
echo f2
|
||||
}
|
||||
vars unset:
|
||||
unset1
|
||||
unset2
|
||||
f1 ()
|
||||
{
|
||||
echo f1
|
||||
}
|
||||
f2 ()
|
||||
{
|
||||
echo f2
|
||||
}
|
||||
funcs unset:
|
||||
one-two
|
||||
two-two
|
||||
./builtins.tests: line 266: exit: status: numeric argument required
|
||||
|
||||
@@ -259,6 +259,9 @@ ${THIS_SH} ./builtins4.sub
|
||||
# test behavior of set and unset array variables
|
||||
${THIS_SH} ./builtins5.sub
|
||||
|
||||
# test behavior of unset builtin with -f and -v options
|
||||
${THIS_SH} ./builtins6.sub
|
||||
|
||||
# this must be last -- it is a fatal error
|
||||
exit status
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
f1()
|
||||
{
|
||||
echo f1
|
||||
}
|
||||
|
||||
f2()
|
||||
{
|
||||
echo f2
|
||||
}
|
||||
|
||||
v1=one
|
||||
v2=two
|
||||
|
||||
echo all set:
|
||||
|
||||
echo ${v1-unset1}
|
||||
echo ${v2-unset2}
|
||||
|
||||
declare -f -p f1 f2
|
||||
|
||||
unset v1 f1 v2 f2
|
||||
|
||||
echo all unset:
|
||||
|
||||
echo ${v1-unset1}
|
||||
echo ${v2-unset2}
|
||||
|
||||
declare -f -p f1 f2
|
||||
|
||||
f1()
|
||||
{
|
||||
echo f1
|
||||
}
|
||||
|
||||
f2()
|
||||
{
|
||||
echo f2
|
||||
}
|
||||
|
||||
v1=one-one
|
||||
v2=two-one
|
||||
|
||||
echo all reset:
|
||||
echo ${v1-unset1}
|
||||
echo ${v2-unset2}
|
||||
|
||||
declare -f -p f1 f2
|
||||
|
||||
unset -v v1 f1 v2 f2
|
||||
|
||||
echo vars unset:
|
||||
|
||||
echo ${v1-unset1}
|
||||
echo ${v2-unset2}
|
||||
|
||||
declare -f -p f1 f2
|
||||
|
||||
v1=one-two
|
||||
v2=two-two
|
||||
|
||||
unset -f v1 f1 v2 f2
|
||||
|
||||
echo funcs unset:
|
||||
|
||||
echo ${v1-unset1}
|
||||
echo ${v2-unset2}
|
||||
|
||||
declare -f f1 f2
|
||||
@@ -43,3 +43,7 @@ Be Conservative in what you send and Liberal in what you accept
|
||||
BE CONSERVATIVE IN WHAT YOU SEND AND LIBERAL IN WHAT YOU ACCEPT
|
||||
Be conservative in what you send and liberal in what you accept
|
||||
BE CONSERVATIVE IN WHAT YOU SEND AND LIBERAL IN WHAT YOU ACCEPT
|
||||
AcknOwlEdgEmEnt acknOwlEdgEmEnt
|
||||
oeNoPHiLe OEnOphIlE
|
||||
abcdexyz
|
||||
ABCDEXYZ
|
||||
|
||||
@@ -97,3 +97,17 @@ echo ${TEXT^^}
|
||||
|
||||
echo ${TEXT2^}
|
||||
echo ${TEXT2^^}
|
||||
|
||||
M1=${S1^^[aeiou]}
|
||||
M2=${U2,,[AEIOU]}
|
||||
|
||||
echo ${M1} ${M1~}
|
||||
echo ${M2} ${M2~~}
|
||||
|
||||
declare -l lower=aBcDe
|
||||
lower+=XyZ
|
||||
echo $lower
|
||||
|
||||
declare -u upper=aBcDe
|
||||
upper+=xYZ
|
||||
echo $upper
|
||||
|
||||
@@ -71,3 +71,4 @@ swap32_posix ()
|
||||
done
|
||||
}
|
||||
yes
|
||||
ab cde
|
||||
|
||||
@@ -217,3 +217,6 @@ unset x
|
||||
# fixed after bash-4.0 released
|
||||
: $(case a in a) echo ;; # comment
|
||||
esac)
|
||||
|
||||
# recommended to be parsed as a nested comsub instead of arithsub
|
||||
echo $(( echo ab cde ) )
|
||||
|
||||
@@ -27,3 +27,8 @@ ok 3
|
||||
ok 4
|
||||
ok 5
|
||||
ok 6
|
||||
xyz
|
||||
\/tmp\/foo\/bar
|
||||
/tmp/foo/bar
|
||||
/tmp/foo/bar
|
||||
/tmp/foo/bar
|
||||
|
||||
@@ -42,3 +42,4 @@ echo $(recho 'foo\
|
||||
bar')
|
||||
|
||||
${THIS_SH} ./comsub1.sub
|
||||
${THIS_SH} ./comsub2.sub
|
||||
|
||||
@@ -46,3 +46,9 @@ esac)
|
||||
echo $(case a in (a) echo ok 6 # comment
|
||||
;;
|
||||
esac)
|
||||
|
||||
echo $( # we just took and pasted in some
|
||||
# code from another script inside a
|
||||
# command substitution
|
||||
echo xyz
|
||||
)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
qpath='\/tmp\/foo\/bar'
|
||||
|
||||
echo "$qpath"
|
||||
|
||||
# it's crazy that all three of these produce the same result
|
||||
echo ${qpath//\\/}
|
||||
echo ${qpath//"`echo \\`"/}
|
||||
echo ${qpath//`echo "\\\\\\\\"`/}
|
||||
+13
-1
@@ -110,4 +110,16 @@ after f
|
||||
./errors3.sub: line 5: no_such_file: No such file or directory
|
||||
TEST
|
||||
./errors3.sub: line 7: no_such_file: No such file or directory
|
||||
./errors.tests: line 271: `!!': not a valid identifier
|
||||
1
|
||||
2
|
||||
./errors4.sub: line 7: var: readonly variable
|
||||
after readonly assignment
|
||||
./errors4.sub: line 13: break: x: numeric argument required
|
||||
1
|
||||
2
|
||||
./errors4.sub: line 7: var: readonly variable
|
||||
./errors5.sub: line 6: array: unbound variable
|
||||
./errors5.sub: line 7: array: unbound variable
|
||||
./errors5.sub: line 10: 7: unbound variable
|
||||
./errors5.sub: line 11: 7: unbound variable
|
||||
./errors.tests: line 275: `!!': not a valid identifier
|
||||
|
||||
@@ -262,6 +262,10 @@ echo $?
|
||||
${THIS_SH} ./errors1.sub
|
||||
${THIS_SH} ./errors2.sub
|
||||
${THIS_SH} ./errors3.sub
|
||||
${THIS_SH} ./errors4.sub
|
||||
${THIS_SH} -o posix ./errors4.sub
|
||||
|
||||
${THIS_SH} ./errors5.sub
|
||||
|
||||
# this must be last!
|
||||
# in posix mode, a function name must be a valid identifier
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# test effect of assigning to readonly vars on loops and non-interactive shells
|
||||
# fatal error when in posix mode
|
||||
var=foo
|
||||
readonly var
|
||||
for num in 1 2 3 4 5; do
|
||||
if [ $num -eq 3 ]; then
|
||||
var=bar
|
||||
fi
|
||||
echo $num
|
||||
done
|
||||
echo after readonly assignment
|
||||
|
||||
# non-numeric arguments to break are fatal errors for all non-interactive shells
|
||||
for f in 1 2 3 4 5
|
||||
do
|
||||
break x
|
||||
done
|
||||
echo after loop
|
||||
@@ -0,0 +1,11 @@
|
||||
array[1]=one
|
||||
array[2]=two
|
||||
|
||||
set -u
|
||||
|
||||
( echo ${#array} )
|
||||
( echo ${array} )
|
||||
|
||||
set -- 1 2 3
|
||||
( echo ${#7} )
|
||||
( echo ${7} )
|
||||
@@ -4,6 +4,11 @@ argv[1] = <^?>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <bar>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <abcdefgh>
|
||||
argv[1] = <abcdefgh>
|
||||
argv[1] = <abcdefgh>
|
||||
|
||||
@@ -31,6 +31,18 @@ recho `echo `
|
||||
expect "<^?>"
|
||||
recho `echo `
|
||||
|
||||
expect "bar"
|
||||
recho ${foo:-"`echo bar`"}
|
||||
expect "<^A>"
|
||||
recho ${foo:-"`echo `"}
|
||||
expect "<^?>"
|
||||
recho ${foo:-"`echo `"}
|
||||
|
||||
expect "<^A>"
|
||||
recho "`echo `"
|
||||
expect "<^?>"
|
||||
recho "`echo `"
|
||||
|
||||
# Test null strings without variable expansion
|
||||
expect "<abcdefgh>"
|
||||
recho abcd""efgh
|
||||
|
||||
@@ -127,3 +127,6 @@ echo '!!' \!\!
|
||||
ok 1
|
||||
ok 2
|
||||
ok 3
|
||||
echo shopt a
|
||||
shopt a
|
||||
echo a b c d 2 > /dev/null
|
||||
|
||||
@@ -122,3 +122,8 @@ echo ${!var2}
|
||||
# Bash-2.01[.1] fails this test -- it attempts history expansion after the
|
||||
# history_comment_char
|
||||
echo ok 3 # !1200
|
||||
|
||||
shopt a b c d 2>/dev/null
|
||||
echo !shopt-1
|
||||
|
||||
echo !shopt*
|
||||
|
||||
@@ -34,6 +34,8 @@ one
|
||||
./nameref.tests: line 106: foo: readonly variable
|
||||
./nameref.tests: line 103: foo: readonly variable
|
||||
one
|
||||
abxde
|
||||
abxde
|
||||
one
|
||||
bar
|
||||
|
||||
@@ -127,3 +129,7 @@ local
|
||||
./nameref8.sub: line 54: warning: x: circular name reference
|
||||
./nameref8.sub: line 55: warning: x: circular name reference
|
||||
x =
|
||||
idx2
|
||||
idX2
|
||||
idx2
|
||||
idX2
|
||||
|
||||
@@ -108,6 +108,13 @@ readonly foo=one
|
||||
assignvar foo two three four
|
||||
echo $foo
|
||||
|
||||
var=abcde
|
||||
x=var
|
||||
declare -n v=var
|
||||
# these two should display the same
|
||||
echo ${!x//c/x}
|
||||
echo ${v//c/x}
|
||||
|
||||
${THIS_SH} ./nameref1.sub
|
||||
${THIS_SH} ./nameref2.sub
|
||||
${THIS_SH} ./nameref3.sub
|
||||
@@ -116,3 +123,4 @@ ${THIS_SH} ./nameref5.sub
|
||||
${THIS_SH} ./nameref6.sub
|
||||
${THIS_SH} ./nameref7.sub
|
||||
${THIS_SH} ./nameref8.sub
|
||||
${THIS_SH} ./nameref9.sub
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
arr=( idx1 idx2 )
|
||||
i='arr[1]'
|
||||
echo ${!i}
|
||||
echo ${!i/x/X}
|
||||
|
||||
typeset -n f='arr[1]'
|
||||
echo ${f}
|
||||
echo ${f/x/X}
|
||||
+20
-13
@@ -59,8 +59,15 @@ argv[1] = <4>
|
||||
argv[1] = <op>
|
||||
argv[1] = <abcdefghijklmnop>
|
||||
argv[1] = <abcdefghijklmnop>
|
||||
./new-exp.tests: line 172: ABX: unbound variable
|
||||
./new-exp.tests: line 176: $6: cannot assign in this way
|
||||
argv[1] = <a>
|
||||
argv[2] = <b>
|
||||
argv[3] = <c>
|
||||
argv[4] = <d>
|
||||
argv[1] = <a>
|
||||
argv[2] = <b c>
|
||||
argv[3] = <d>
|
||||
./new-exp.tests: line 180: ABX: unbound variable
|
||||
./new-exp.tests: line 184: $6: cannot assign in this way
|
||||
argv[1] = <xxcde>
|
||||
argv[1] = <axxde>
|
||||
argv[1] = <abxyz>
|
||||
@@ -169,7 +176,7 @@ this is test 2
|
||||
./new-exp2.sub: line 42: 1111111111111111111111: command not found
|
||||
|
||||
argv[1] = <6>
|
||||
./new-exp.tests: line 277: ${#:}: bad substitution
|
||||
./new-exp.tests: line 285: ${#:}: bad substitution
|
||||
argv[1] = <'>
|
||||
argv[1] = <">
|
||||
argv[1] = <"hello">
|
||||
@@ -398,13 +405,13 @@ argv[6] = <w>
|
||||
argv[7] = <x>
|
||||
argv[8] = <y>
|
||||
argv[9] = <z>
|
||||
./new-exp.tests: line 482: $9: unbound variable
|
||||
./new-exp.tests: line 483: 9: unbound variable
|
||||
./new-exp.tests: line 484: UNSET: unbound variable
|
||||
./new-exp.tests: line 485: UNSET: unbound variable
|
||||
./new-exp.tests: line 486: UNSET: unbound variable
|
||||
./new-exp.tests: line 487: UNSET: unbound variable
|
||||
./new-exp.tests: line 488: UNSET: unbound variable
|
||||
./new-exp.tests: line 490: $9: unbound variable
|
||||
./new-exp.tests: line 491: 9: unbound variable
|
||||
./new-exp.tests: line 492: UNSET: unbound variable
|
||||
./new-exp.tests: line 493: UNSET: unbound variable
|
||||
./new-exp.tests: line 494: UNSET: unbound variable
|
||||
./new-exp.tests: line 495: UNSET: unbound variable
|
||||
./new-exp.tests: line 496: UNSET: unbound variable
|
||||
argv[1] = <5>
|
||||
argv[1] = <#>
|
||||
argv[1] = <#>
|
||||
@@ -433,7 +440,7 @@ Case05---3---A:B:C---
|
||||
Case06---1---A B C::---
|
||||
Case07---3---A:B:C---
|
||||
Case08---3---A:B:C---
|
||||
./new-exp.tests: line 508: ${$(($#-1))}: bad substitution
|
||||
./new-exp.tests: line 516: ${$(($#-1))}: bad substitution
|
||||
argv[1] = <a>
|
||||
argv[2] = <b>
|
||||
argv[3] = <c>
|
||||
@@ -450,7 +457,7 @@ argv[1] = <a>
|
||||
argv[1] = <a>
|
||||
argv[2] = <b>
|
||||
argv[1] = <>
|
||||
./new-exp.tests: line 527: $(($# - 2)): substring expression < 0
|
||||
./new-exp.tests: line 535: $(($# - 2)): substring expression < 0
|
||||
argv[1] = <bin>
|
||||
argv[2] = <bin>
|
||||
argv[3] = <ucb>
|
||||
@@ -614,4 +621,4 @@ a b c d e
|
||||
a5b
|
||||
argv[1] = </>
|
||||
argv[1] = </>
|
||||
./new-exp.tests: line 587: ABXD: parameter unset
|
||||
./new-exp.tests: line 595: ABXD: parameter unset
|
||||
|
||||
@@ -167,6 +167,14 @@ recho ${a-$z}
|
||||
expect nothing
|
||||
recho ${!1-$z}
|
||||
|
||||
set -- a 'b c' d
|
||||
unset foo
|
||||
foo=@
|
||||
expect '<a> <b> <c> <d>'
|
||||
recho ${!foo}
|
||||
expect '<a> <b c> <d>'
|
||||
recho "${!foo}"
|
||||
|
||||
set -u
|
||||
expect $0: ABX: unbound variable
|
||||
( recho ${ABX} )
|
||||
|
||||
@@ -76,6 +76,9 @@ declare -ar myvar=([0]="0")
|
||||
declare -ir myvar="1"
|
||||
declare -rx tempvar1='foo'
|
||||
declare -rx tempvar2='qux'
|
||||
./varenv7.sub: line 44: local: var: readonly variable
|
||||
inside: outside
|
||||
outside: outside
|
||||
a=z
|
||||
a=b
|
||||
a=z
|
||||
|
||||
@@ -35,3 +35,16 @@ echo ${tempvar1@A}
|
||||
|
||||
tempvar2=bar declare -r tempvar2=qux
|
||||
echo ${tempvar2@A}
|
||||
|
||||
unset foo
|
||||
readonly var=outside
|
||||
|
||||
func()
|
||||
{
|
||||
local var=inside
|
||||
echo "inside: $var"
|
||||
}
|
||||
|
||||
func
|
||||
echo outside: $var
|
||||
|
||||
|
||||
@@ -90,3 +90,14 @@ ok 1
|
||||
./vredir6.sub: redirection error: cannot duplicate fd: Invalid argument
|
||||
./vredir6.sub: line 13: /dev/null: Invalid argument
|
||||
unset
|
||||
12 10
|
||||
a
|
||||
a
|
||||
swizzle is a function
|
||||
swizzle ()
|
||||
{
|
||||
exec {fd[0]}<&0;
|
||||
exec {fd[1]}>&1;
|
||||
exec {stdin}<&${fd[0]}-;
|
||||
exec {stdout}>&${fd[1]}-
|
||||
}
|
||||
|
||||
@@ -43,4 +43,6 @@ ${THIS_SH} ./vredir5.sub
|
||||
|
||||
${THIS_SH} ./vredir6.sub
|
||||
|
||||
${THIS_SH} ./vredir7.sub
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
swizzle()
|
||||
{
|
||||
exec {fd[0]}<&0
|
||||
exec {fd[1]}>&1
|
||||
|
||||
exec {stdin}<&${fd[0]}-
|
||||
exec {stdout}>&${fd[1]}-
|
||||
}
|
||||
|
||||
swizzle
|
||||
|
||||
echo $stdin $stdout
|
||||
|
||||
read line <&$stdin <<EOF
|
||||
a
|
||||
EOF
|
||||
|
||||
echo $line
|
||||
echo $line >&$stdout
|
||||
|
||||
type swizzle
|
||||
|
||||
exit 0
|
||||
+17
-1
@@ -49,6 +49,7 @@
|
||||
#include "sig.h"
|
||||
#include "quit.h"
|
||||
#include "error.h" /* for internal_warning */
|
||||
#include "ocache.h"
|
||||
|
||||
/* Structure describing a saved variable and the value to restore it to. */
|
||||
typedef struct {
|
||||
@@ -75,7 +76,6 @@ typedef union uwp {
|
||||
} sv;
|
||||
} UNWIND_ELT;
|
||||
|
||||
|
||||
static void without_interrupts __P((VFunction *, char *, char *));
|
||||
static void unwind_frame_discard_internal __P((char *, char *));
|
||||
static void unwind_frame_run_internal __P((char *, char *));
|
||||
@@ -88,8 +88,24 @@ static void unwind_protect_mem_internal __P((char *, char *));
|
||||
|
||||
static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
|
||||
|
||||
/* Allocating from a cache of unwind-protect elements */
|
||||
#define UWCACHESIZE 128
|
||||
|
||||
sh_obj_cache_t uwcache = {0, 0, 0};
|
||||
|
||||
#if 0
|
||||
#define uwpalloc(elt) (elt) = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT))
|
||||
#define uwpfree(elt) free(elt)
|
||||
#else
|
||||
#define uwpalloc(elt) ocache_alloc (uwcache, UNWIND_ELT, elt)
|
||||
#define uwpfree(elt) ocache_free (uwcache, UNWIND_ELT, elt)
|
||||
#endif
|
||||
|
||||
void
|
||||
uwp_init ()
|
||||
{
|
||||
ocache_create (uwcache, UNWIND_ELT, UWCACHESIZE);
|
||||
}
|
||||
|
||||
/* Run a function without interrupts. This relies on the fact that the
|
||||
FUNCTION cannot change the value of interrupt_immediately. (I.e., does
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#if !defined (_UNWIND_PROT_H)
|
||||
#define _UNWIND_PROT_H
|
||||
|
||||
extern void uwp_init __P((void));
|
||||
|
||||
/* Run a function without interrupts. */
|
||||
extern void begin_unwind_frame __P((char *));
|
||||
extern void discard_unwind_frame __P((char *));
|
||||
|
||||
Reference in New Issue
Block a user