]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20150501 snapshot
authorChet Ramey <chet.ramey@case.edu>
Fri, 15 May 2015 15:05:19 +0000 (11:05 -0400)
committerChet Ramey <chet.ramey@case.edu>
Fri, 15 May 2015 15:05:19 +0000 (11:05 -0400)
56 files changed:
CWRU/CWRU.chlog
MANIFEST
builtins/complete.def
builtins/declare.def
builtins/set.def
builtins/trap.def
execute_cmd.c
general.c
general.h
jobs.c
lib/glob/gmisc.c
lib/malloc/table.c
lib/malloc/table.h
lib/readline/histexpand.c
lib/sh/strtrans.c
lib/sh/unicode.c
parse.y
redir.c
shell.c
subst.c
tests/RUN-ONE-TEST
tests/arith.right
tests/arith.tests
tests/assoc.right
tests/assoc.tests
tests/builtins.right
tests/builtins.tests
tests/builtins6.sub [new file with mode: 0644]
tests/casemod.right
tests/casemod.tests
tests/comsub-posix.right
tests/comsub-posix.tests
tests/comsub.right
tests/comsub.tests
tests/comsub1.sub
tests/comsub2.sub [new file with mode: 0644]
tests/errors.right
tests/errors.tests
tests/errors4.sub [new file with mode: 0644]
tests/errors5.sub [new file with mode: 0644]
tests/exp.right
tests/exp.tests
tests/histexp.right
tests/histexp.tests
tests/nameref.right
tests/nameref.tests
tests/nameref9.sub [new file with mode: 0644]
tests/new-exp.right
tests/new-exp.tests
tests/varenv.right
tests/varenv7.sub
tests/vredir.right
tests/vredir.tests
tests/vredir7.sub [new file with mode: 0644]
unwind_prot.c
unwind_prot.h

index 52697fd9c77427a224d2ad01cb0ff7d4b528a773..1edc56040fcc3cb3da411635cb150f1185b94248 100644 (file)
@@ -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>
index 0d3328b691d38561b5ed2f83410588a667f9d3a3..c8dc1324cc2978f09543d5414717ee36e2ad037c 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -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
index 57d45f1bc8caef5553264cc087eff72759ecbbe1..450d7ecf77e7a6a458ed411c225ced16a6a7c467 100644 (file)
@@ -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
index a41d8c9c6883da8065247057650b131144e21575..4c0f514a843e7301aa27fcb90924ff881650799a 100644 (file)
@@ -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'.
index 35b2025ca6daa93bd46937a58a5d0a7726d63fe8..e31b017cf83a7436468efbec10cdc33d25d4fb66 100644 (file)
@@ -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))
index 2119f5b3cb818273ffb053d3c0f9e42b506c19f1..3179c28c98712e16d509aa8912402548f9209f21 100644 (file)
@@ -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
index ad4d290cf709f4db3189c3fcd87bf443f4c77acc..d0488fe0ee7eca0823d937627e8272415e76fc0a 100644 (file)
@@ -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);
     }
 }
 
index 61a5f0e2a6afb2ae6eb798f453977cb5f2de8ad3..65a29128ba3eb7dd0d751b37d693dc7100663e3b 100644 (file)
--- a/general.c
+++ b/general.c
@@ -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
index e252af569641eed835e2f837f0f82521266615ba..d34bb3d4aec6b671f9844aef9c842ec6ed62cc34 100644 (file)
--- a/general.h
+++ b/general.h
@@ -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))
diff --git a/jobs.c b/jobs.c
index 706738dd9dd92da8c5f5431f46cda92239316254..bebae1b46a7eae4aec22e52ae9059a5db0b66aec 100644 (file)
--- a/jobs.c
+++ b/jobs.c
@@ -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');
index c28f7b12a6873b4f54806adb53758f79169d5d24..31906a4f2c8baa70b2a3015a3bd56f942d774f1a 100644 (file)
@@ -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++)
     {
index dfa29e222db5e6ead39130c7d7ae58e3ce3f7d32..1e642d33404f30e6d15fbc4e6f753dd51e192d06 100644 (file)
@@ -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++;
 
-      if (tp == lastp)         /* wrap around */
-        tp = mem_table;
+      tp = prev_entry (tp);
 
-      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
index 41ce9f72d2282495a340dbae004d66493c70a219..f9c5f1c4a8b7ca2f17f93ec3f59a6d0edc1d3feb 100644 (file)
@@ -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) */
 
 /*
index b4d695744283a9f3eab00fc3540136b22f597135..fc133036493d826d436c732b06ced22551202b29 100644 (file)
@@ -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) \
index ae88e694db67e6e9349c318a5de736873d6e60b7..02f5c89afd42e1c7ff2ddb3c0447d94e41b59296 100644 (file)
@@ -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
index 798260ecdeae03259db3a5eed3ba6294237e5c7b..a34336ef10511f5dcdbdd20f6e85fdc218b4047f 100644 (file)
@@ -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;
diff --git a/parse.y b/parse.y
index cefe7beb42e2ab1bc0a8ddf1916745ee146aaaee..5b476b09abeef5e28d8c01689ed73a0f5755bae0 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -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++)
diff --git a/redir.c b/redir.c
index 4cc237ceaf58800ad378abf6929fb5de8b13a4e0..539af00d9837f2bee20e867aaf7a35611047eec5 100644 (file)
--- a/redir.c
+++ b/redir.c
@@ -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)
diff --git a/shell.c b/shell.c
index b145af351f8f3fc3aa06d05f58efd44e24e14a5b..2b3f0ca4101fdeed28b5a23fba6af28b87d74a47 100644 (file)
--- a/shell.c
+++ b/shell.c
@@ -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);
 }
 
diff --git a/subst.c b/subst.c
index cb453299bb9f65188825264d7325579d1ae14887..388e58828013b20ae5263393c2ba4a605c35d7de 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -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;
index 3efcf32d68e9722024b6ca9d67f9e81b2aa5ac04..72ec06a2c1fd8dde92acea5e8ac773e35f1d061b 100755 (executable)
@@ -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
 
index 680d9a954f6406b5bf98ef10ede99ab9d0e1d3df..69e7491d89674374601588ed74b62c6a45fb9ea9 100644 (file)
@@ -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")
index 7dcc36d8d8024867ecd5458e320ccc7aab9e2f6e..394422d2fe63b319fc80806a2317d18598642e46 100644 (file)
@@ -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
index 315b0cec4250dd23fb987efb40c50dec6937213d..d51cc91ee68ff354624d21b5aefa8a17ea66b8bd 100644 (file)
@@ -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" )
index c3fb18e607bfdca192bb707992d0ca1559609393..1d4f4e5a52f9e749dc7d1019f5ae6cddb701dab6 100644 (file)
@@ -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
index 8a5e3f925c8aa80537f7a2a89cbeeae307176cb9..32db2a53522136763bc8323972cc5df72f3636c6 100644 (file)
@@ -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
index ccf55a87e74f08b2716d5aadece4dc945027aaa6..ac74fe6fa3f444e9519190052ebe4af4b2c989d5 100644 (file)
@@ -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
 
diff --git a/tests/builtins6.sub b/tests/builtins6.sub
new file mode 100644 (file)
index 0000000..c18b476
--- /dev/null
@@ -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
index 958b28dc6678995011f74a254cb6d1738bb6c30e..ca1de49a9200c2393dbea1d27b68c0777a60bfb7 100644 (file)
@@ -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
index 3c7ad23feebc8732292358fc45b2f8823274048f..dacdb0a87465ae464108e96ef3d699558fccaac3 100644 (file)
@@ -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
index ab04c52aef094df495cbb76d9ae73e6cbba3ff62..2290aa6dc7604a40ef6b315593cf942db85428ff 100644 (file)
@@ -71,3 +71,4 @@ swap32_posix ()
     done
 }
 yes
+ab cde
index bcfeede08f442cbac2410933e6d254689d50d1a0..b2cb4418207c1bbf32f060c5b7cf5ae396dd1155 100644 (file)
@@ -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 ) )
index 9894529c05442a71903bfe5220a32982f548237d..2b5a2304323a20cb241a713ad9d69bd3663be360 100644 (file)
@@ -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
index 493bbda07fd78c6d72d84ee70c172f355e596676..862fc264b3d16a964d51c355e5aecd68953c46ea 100644 (file)
@@ -42,3 +42,4 @@ echo $(recho 'foo\
 bar')
 
 ${THIS_SH} ./comsub1.sub
+${THIS_SH} ./comsub2.sub
index 86565e2c445047d38284ff579f672da182c50958..216e03f1f74e4c5d9861e0af380a57a6b653a7f2 100644 (file)
@@ -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
+)
diff --git a/tests/comsub2.sub b/tests/comsub2.sub
new file mode 100644 (file)
index 0000000..a2d58ad
--- /dev/null
@@ -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 "\\\\\\\\"`/}
index 1ac9735fc3cd03648e30106f3cebeed20a8b123a..da9415335af6eb4198d94636a6bec62eb0d32fb5 100644 (file)
@@ -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
index 14eeb08bb9d53445c97f86612dd9e43ae467543d..fb47bf0a11e879bc073c6e3447a8b66a87262c97 100644 (file)
@@ -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
diff --git a/tests/errors4.sub b/tests/errors4.sub
new file mode 100644 (file)
index 0000000..8451b96
--- /dev/null
@@ -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
diff --git a/tests/errors5.sub b/tests/errors5.sub
new file mode 100644 (file)
index 0000000..7d9068b
--- /dev/null
@@ -0,0 +1,11 @@
+array[1]=one
+array[2]=two
+
+set -u
+
+( echo ${#array} )
+( echo ${array} )
+
+set -- 1 2 3
+( echo ${#7} )
+( echo ${7} )
index c027036ed60416af4c8b950031895a2a0f1231cc..3c5fb8a5d108cf6f0c65e89d19cbf487e323b592 100644 (file)
@@ -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>
index 9f77a7f93f018d7d9d08a8ce4d5a0eacabd0d2d6..53eeaa85dbe0b47209dbe58560d7775a052f7aeb 100644 (file)
@@ -31,6 +31,18 @@ recho `echo \ 1`
 expect "<^?>"
 recho `echo \7f`
 
+expect "bar"
+recho ${foo:-"`echo bar`"}
+expect "<^A>"
+recho ${foo:-"`echo \ 1`"}
+expect "<^?>"
+recho ${foo:-"`echo \7f`"}
+
+expect "<^A>"
+recho "`echo \ 1`"
+expect "<^?>"
+recho "`echo \7f`"
+
 # Test null strings without variable expansion
 expect "<abcdefgh>"
 recho abcd""efgh
index f1c9e9d9adc09af5ed287d94fc5d7d8a883fd81c..2b848bbecd7a3dec2984e700e0cad7933a7d6c76 100644 (file)
@@ -127,3 +127,6 @@ echo '!!' \!\!
 ok 1
 ok 2
 ok 3
+echo shopt a
+shopt a
+echo a b c d 2 > /dev/null
index add2a67476edb91718dc7247238e5a8b5ad1fb6a..d9be836ddf2e051696e396dab7d12dcfbdf85d1b 100644 (file)
@@ -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*
index 53215348859936fd5c1efce88281752940ab35d2..c35fac1e302803391a793105f1eb7e4833a9db22 100644 (file)
@@ -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
index 438133c64d3869441ba16af8a0a0c17827b50448..bce8a68066824349243747094fe5de9af3167781 100644 (file)
@@ -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
diff --git a/tests/nameref9.sub b/tests/nameref9.sub
new file mode 100644 (file)
index 0000000..e76c21b
--- /dev/null
@@ -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}
index e0f64d53fda38b3169d61c33bf1b90ac87fe8f89..7366e07aea49e83f21dd6110f609577d9059d8e5 100644 (file)
@@ -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
index aa4eb626e6602a0845a4427bef2dd353ce3dbc22..666d8a9d2452ef752bb10bc528c72d223ccd4450 100644 (file)
@@ -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} )
index 7765e5c4d618f5ba9c56b8ee9397158844810878..62b3c13981bb8dbc7d4b2f02310588041b2027dd 100644 (file)
@@ -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
index cb7a47105d371a62cbfd2cfb0ad609066a63a7f0..4741d23804bb3f35e30c8dba610e4d57bce77fb0 100644 (file)
@@ -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
+
index 5e081bee2a7201357c033e07f62e6d03a4d6efa0..3985f22dfaed0de48acf80d20896e2b7223a38a6 100644 (file)
@@ -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]}-
+}
index 5158fe397bfb06ab2080b6b2f46cfcb0a96ed36c..b81c671c2eff06e95b4cf481ecbb7e99305cb589 100644 (file)
@@ -43,4 +43,6 @@ ${THIS_SH} ./vredir5.sub
 
 ${THIS_SH} ./vredir6.sub
 
+${THIS_SH} ./vredir7.sub
+
 exit 0
diff --git a/tests/vredir7.sub b/tests/vredir7.sub
new file mode 100644 (file)
index 0000000..8cb80ed
--- /dev/null
@@ -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
index 0e480bf7a728ba111c6812e27b6fd429cbe4a437..c9196dc1cd86c70acf5669533eca08a203af04a5 100644 (file)
@@ -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
index 4a1b256b1d65ac3c4bdb0ee9965208878100daf2..cbfc97ca22551a3596fb7b04bb3d427f125837cf 100644 (file)
@@ -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 *));