]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20060330 snapshot
authorChet Ramey <chet.ramey@case.edu>
Sun, 4 Dec 2011 03:46:45 +0000 (22:46 -0500)
committerChet Ramey <chet.ramey@case.edu>
Sun, 4 Dec 2011 03:46:45 +0000 (22:46 -0500)
19 files changed:
CWRU/CWRU.chlog
CWRU/CWRU.chlog~
arrayfunc.c
execute_cmd.c
execute_cmd.c~
lib/readline/histfile.c
lib/readline/histfile.c~ [new file with mode: 0644]
lib/sh/strtrans.c
lib/sh/strtrans.c~ [new file with mode: 0644]
make_cmd.c
subst.c
subst.h
tests/RUN-ONE-TEST
tests/array.right
tests/array4.sub
tests/array4.sub~ [new file with mode: 0644]
tests/braces.right
tests/braces.tests
tests/braces.tests~ [new file with mode: 0644]

index 096db69e1f12405f0a3b2b66e9fe06152d3ecee3..a6254a2e97d259361ff157e6141fddf6835be57b 100644 (file)
@@ -13214,3 +13214,30 @@ bashline.c
        - command_word_completion_function returns what it's passed as a
          possible match if it's the name of a directory in the current
          directory (only non-absolute pathnames are so tested).
+
+                                  3/27
+                                  ----
+subst.c
+       - expand_arith_string takes a new argument: quoted.  Either 0 (outside
+         subst.c) or Q_DOUBLE_QUOTES (substitution functions); changed callers
+
+subst.h
+       - changed extern declaration for expand_arith_string
+
+arrayfunc.c
+       - changed call to expand_arith_string in array_expand_index
+
+                                  3/31
+                                  ----
+lib/readline/histfile.c
+       - change read_history_range to allow windows-like \r\n line endings
+
+execute_cmd.c
+       - add new variable, line_number_for_err_trap, currently set but not
+         used
+
+                                   4/2
+                                   ---
+lib/sh/strtrans.c
+       - add code to echo -e and echo with xpg_echo enabled to require
+         a leading 0 to specify octal constants
index 99e706897707eadac1719877dde1a27bc8486e3a..f3dc5ece90e4b5c61f1b10621883ed55b6172dd2 100644 (file)
@@ -13209,8 +13209,29 @@ parse.y, eval.c, input.h
                                   ----
 bashline.c
        - command_word_completion_function keeps track of when it's searching
-         $PATH and doesn't return directory names as matches in that case
+         $PATH and doesn't return directory names as matches in that case.
+         Problem reported by Pascal Terjan <pterjan@mandriva.com>
        - command_word_completion_function returns what it's passed as a
          possible match if it's the name of a directory in the current
-         directory (only non-absolute pathnames are so tested).  Problem
-         reported by Pascal Terjan <pterjan@mandriva.com>
+         directory (only non-absolute pathnames are so tested).
+
+                                  3/27
+                                  ----
+subst.c
+       - expand_arith_string takes a new argument: quoted.  Either 0 (outside
+         subst.c) or Q_DOUBLE_QUOTES (substitution functions); changed callers
+
+subst.h
+       - changed extern declaration for expand_arith_string
+
+arrayfunc.c
+       - changed call to expand_arith_string in array_expand_index
+
+                                  3/31
+                                  ----
+lib/readline/histfile.c
+       - change read_history_range to allow windows-like \r\n line endings
+
+execute_cmd.c
+       - add new variable, line_number_for_err_trap, currently set but not
+         used
index 1353b2d945d72e829cf52430610ee22b3a94c0f6..6073a343623e6c05ffb41cbcbb9d012f12b30664 100644 (file)
@@ -590,7 +590,7 @@ array_expand_index (s, len)
   exp = (char *)xmalloc (len);
   strncpy (exp, s, len - 1);
   exp[len - 1] = '\0';
-  t = expand_arith_string (exp);
+  t = expand_arith_string (exp, 0);
   this_command_name = (char *)NULL;
   val = evalexp (t, &expok);
   free (t);
index 57e9d1136ced0da1ec05d9ff6c9544e0088589b3..e52905d549796e711177f0188751d499611bfc80 100644 (file)
@@ -214,6 +214,8 @@ static int special_builtin_failed;
    report the correct line number.  Kind of a hack. */
 static int showing_function_line;
 
+static int line_number_for_err_trap;
+
 /* For catching RETURN in a function. */
 int return_catch_flag;
 int return_catch_value;
@@ -665,7 +667,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
        if (command->flags & CMD_STDIN_REDIR)
          command->value.Simple->flags |= CMD_STDIN_REDIR;
 
-       line_number = command->value.Simple->line;
+       line_number_for_err_trap = line_number = command->value.Simple->line;
        exec_result =
          execute_simple_command (command->value.Simple, pipe_in, pipe_out,
                                  asynchronous, fds_to_close);
index 8b446b2543a3e31070283a3344c829c2e77c2d5f..57e9d1136ced0da1ec05d9ff6c9544e0088589b3 100644 (file)
@@ -359,6 +359,7 @@ execute_command (command)
     unlink_fifo_list ();
 #endif /* PROCESS_SUBSTITUTION */
 
+  QUIT;
   return (result);
 }
 
index 717bbee6fd73ed22f95c44906df70bf4872c954a..2f051a325631f6755ee54a7d36fa5e0a85fec230 100644 (file)
@@ -256,7 +256,11 @@ read_history_range (filename, from, to)
   for (line_end = line_start; line_end < bufend; line_end++)
     if (*line_end == '\n')
       {
-       *line_end = '\0';
+       /* Change to allow Windows-like \r\n end of line delimiter. */
+       if (line_end > line_start && line_end[-1] == '\r')
+         line_end[-1] = '\0';
+       else
+         *line_end = '\0';
 
        if (*line_start)
          {
diff --git a/lib/readline/histfile.c~ b/lib/readline/histfile.c~
new file mode 100644 (file)
index 0000000..717bbee
--- /dev/null
@@ -0,0 +1,542 @@
+/* histfile.c - functions to manipulate the history file. */
+
+/* Copyright (C) 1989-2003 Free Software Foundation, Inc.
+
+   This file contains the GNU History Library (the Library), a set of
+   routines for managing the text of previously typed lines.
+
+   The Library is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   The Library is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   The GNU General Public License is often shipped with GNU software, and
+   is generally kept in a file called COPYING or LICENSE.  If you do not
+   have a copy of the license, write to the Free Software Foundation,
+   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+/* The goal is to make the implementation transparent, so that you
+   don't have to know what data types are used, just what functions
+   you can call.  I think I have done that. */
+
+#define READLINE_LIBRARY
+
+#if defined (__TANDEM)
+#  include <floss.h>
+#endif
+
+#if defined (HAVE_CONFIG_H)
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include <sys/types.h>
+#if ! defined (_MINIX) && defined (HAVE_SYS_FILE_H)
+#  include <sys/file.h>
+#endif
+#include "posixstat.h"
+#include <fcntl.h>
+
+#if defined (HAVE_STDLIB_H)
+#  include <stdlib.h>
+#else
+#  include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#if defined (__EMX__) || defined (__CYGWIN__)
+#  undef HAVE_MMAP
+#endif
+
+#ifdef HISTORY_USE_MMAP
+#  include <sys/mman.h>
+
+#  ifdef MAP_FILE
+#    define MAP_RFLAGS (MAP_FILE|MAP_PRIVATE)
+#    define MAP_WFLAGS (MAP_FILE|MAP_SHARED)
+#  else
+#    define MAP_RFLAGS MAP_PRIVATE
+#    define MAP_WFLAGS MAP_SHARED
+#  endif
+
+#  ifndef MAP_FAILED
+#    define MAP_FAILED ((void *)-1)
+#  endif
+
+#endif /* HISTORY_USE_MMAP */
+
+/* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment
+   on win 95/98/nt), we want to open files with O_BINARY mode so that there
+   is no \n -> \r\n conversion performed.  On other systems, we don't want to
+   mess around with O_BINARY at all, so we ensure that it's defined to 0. */
+#if defined (__EMX__) || defined (__CYGWIN__)
+#  ifndef O_BINARY
+#    define O_BINARY 0
+#  endif
+#else /* !__EMX__ && !__CYGWIN__ */
+#  undef O_BINARY
+#  define O_BINARY 0
+#endif /* !__EMX__ && !__CYGWIN__ */
+
+#include <errno.h>
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+#include "history.h"
+#include "histlib.h"
+
+#include "rlshell.h"
+#include "xmalloc.h"
+
+/* If non-zero, we write timestamps to the history file in history_do_write() */
+int history_write_timestamps = 0;
+
+/* Does S look like the beginning of a history timestamp entry?  Placeholder
+   for more extensive tests. */
+#define HIST_TIMESTAMP_START(s)                (*(s) == history_comment_char)
+
+/* Return the string that should be used in the place of this
+   filename.  This only matters when you don't specify the
+   filename to read_history (), or write_history (). */
+static char *
+history_filename (filename)
+     const char *filename;
+{
+  char *return_val;
+  const char *home;
+  int home_len;
+
+  return_val = filename ? savestring (filename) : (char *)NULL;
+
+  if (return_val)
+    return (return_val);
+  
+  home = sh_get_env_value ("HOME");
+
+  if (home == 0)
+    {
+      home = ".";
+      home_len = 1;
+    }
+  else
+    home_len = strlen (home);
+
+  return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
+  strcpy (return_val, home);
+  return_val[home_len] = '/';
+#if defined (__MSDOS__)
+  strcpy (return_val + home_len + 1, "_history");
+#else
+  strcpy (return_val + home_len + 1, ".history");
+#endif
+
+  return (return_val);
+}
+
+/* Add the contents of FILENAME to the history list, a line at a time.
+   If FILENAME is NULL, then read from ~/.history.  Returns 0 if
+   successful, or errno if not. */
+int
+read_history (filename)
+     const char *filename;
+{
+  return (read_history_range (filename, 0, -1));
+}
+
+/* Read a range of lines from FILENAME, adding them to the history list.
+   Start reading at the FROM'th line and end at the TO'th.  If FROM
+   is zero, start at the beginning.  If TO is less than FROM, read
+   until the end of the file.  If FILENAME is NULL, then read from
+   ~/.history.  Returns 0 if successful, or errno if not. */
+int
+read_history_range (filename, from, to)
+     const char *filename;
+     int from, to;
+{
+  register char *line_start, *line_end, *p;
+  char *input, *buffer, *bufend, *last_ts;
+  int file, current_line, chars_read;
+  struct stat finfo;
+  size_t file_size;
+#if defined (EFBIG)
+  int overflow_errno = EFBIG;
+#elif defined (EOVERFLOW)
+  int overflow_errno = EOVERFLOW;
+#else
+  int overflow_errno = EIO;
+#endif
+
+  buffer = last_ts = (char *)NULL;
+  input = history_filename (filename);
+  file = open (input, O_RDONLY|O_BINARY, 0666);
+
+  if ((file < 0) || (fstat (file, &finfo) == -1))
+    goto error_and_exit;
+
+  file_size = (size_t)finfo.st_size;
+
+  /* check for overflow on very large files */
+  if (file_size != finfo.st_size || file_size + 1 < file_size)
+    {
+      errno = overflow_errno;
+      goto error_and_exit;
+    }
+
+#ifdef HISTORY_USE_MMAP
+  /* We map read/write and private so we can change newlines to NULs without
+     affecting the underlying object. */
+  buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0);
+  if ((void *)buffer == MAP_FAILED)
+    {
+      errno = overflow_errno;
+      goto error_and_exit;
+    }
+  chars_read = file_size;
+#else
+  buffer = (char *)malloc (file_size + 1);
+  if (buffer == 0)
+    {
+      errno = overflow_errno;
+      goto error_and_exit;
+    }
+
+  chars_read = read (file, buffer, file_size);
+#endif
+  if (chars_read < 0)
+    {
+  error_and_exit:
+      if (errno != 0)
+       chars_read = errno;
+      else
+       chars_read = EIO;
+      if (file >= 0)
+       close (file);
+
+      FREE (input);
+#ifndef HISTORY_USE_MMAP
+      FREE (buffer);
+#endif
+
+      return (chars_read);
+    }
+
+  close (file);
+
+  /* Set TO to larger than end of file if negative. */
+  if (to < 0)
+    to = chars_read;
+
+  /* Start at beginning of file, work to end. */
+  bufend = buffer + chars_read;
+  current_line = 0;
+
+  /* Skip lines until we are at FROM. */
+  for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
+    if (*line_end == '\n')
+      {
+       p = line_end + 1;
+       /* If we see something we think is a timestamp, continue with this
+          line.  We should check more extensively here... */
+       if (HIST_TIMESTAMP_START(p) == 0)
+         current_line++;
+       line_start = p;
+      }
+
+  /* If there are lines left to gobble, then gobble them now. */
+  for (line_end = line_start; line_end < bufend; line_end++)
+    if (*line_end == '\n')
+      {
+       *line_end = '\0';
+
+       if (*line_start)
+         {
+           if (HIST_TIMESTAMP_START(line_start) == 0)
+             {
+               add_history (line_start);
+               if (last_ts)
+                 {
+                   add_history_time (last_ts);
+                   last_ts = NULL;
+                 }
+             }
+           else
+             {
+               last_ts = line_start;
+               current_line--;
+             }
+         }
+
+       current_line++;
+
+       if (current_line >= to)
+         break;
+
+       line_start = line_end + 1;
+      }
+
+  FREE (input);
+#ifndef HISTORY_USE_MMAP
+  FREE (buffer);
+#else
+  munmap (buffer, file_size);
+#endif
+
+  return (0);
+}
+
+/* Truncate the history file FNAME, leaving only LINES trailing lines.
+   If FNAME is NULL, then use ~/.history.  Returns 0 on success, errno
+   on failure. */
+int
+history_truncate_file (fname, lines)
+     const char *fname;
+     int lines;
+{
+  char *buffer, *filename, *bp, *bp1;          /* bp1 == bp+1 */
+  int file, chars_read, rv;
+  struct stat finfo;
+  size_t file_size;
+
+  buffer = (char *)NULL;
+  filename = history_filename (fname);
+  file = open (filename, O_RDONLY|O_BINARY, 0666);
+  rv = 0;
+
+  /* Don't try to truncate non-regular files. */
+  if (file == -1 || fstat (file, &finfo) == -1)
+    {
+      rv = errno;
+      if (file != -1)
+       close (file);
+      goto truncate_exit;
+    }
+
+  if (S_ISREG (finfo.st_mode) == 0)
+    {
+      close (file);
+#ifdef EFTYPE
+      rv = EFTYPE;
+#else
+      rv = EINVAL;
+#endif
+      goto truncate_exit;
+    }
+
+  file_size = (size_t)finfo.st_size;
+
+  /* check for overflow on very large files */
+  if (file_size != finfo.st_size || file_size + 1 < file_size)
+    {
+      close (file);
+#if defined (EFBIG)
+      rv = errno = EFBIG;
+#elif defined (EOVERFLOW)
+      rv = errno = EOVERFLOW;
+#else
+      rv = errno = EINVAL;
+#endif
+      goto truncate_exit;
+    }
+
+  buffer = (char *)malloc (file_size + 1);
+  if (buffer == 0)
+    {
+      close (file);
+      goto truncate_exit;
+    }
+
+  chars_read = read (file, buffer, file_size);
+  close (file);
+
+  if (chars_read <= 0)
+    {
+      rv = (chars_read < 0) ? errno : 0;
+      goto truncate_exit;
+    }
+
+  /* Count backwards from the end of buffer until we have passed
+     LINES lines.  bp1 is set funny initially.  But since bp[1] can't
+     be a comment character (since it's off the end) and *bp can't be
+     both a newline and the history comment character, it should be OK. */
+  for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
+    {
+      if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
+       lines--;
+      bp1 = bp;
+    }
+
+  /* If this is the first line, then the file contains exactly the
+     number of lines we want to truncate to, so we don't need to do
+     anything.  It's the first line if we don't find a newline between
+     the current value of i and 0.  Otherwise, write from the start of
+     this line until the end of the buffer. */
+  for ( ; bp > buffer; bp--)
+    {
+      if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
+        {
+         bp++;
+         break;
+        }
+      bp1 = bp;
+    }
+
+  /* Write only if there are more lines in the file than we want to
+     truncate to. */
+  if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
+    {
+      write (file, bp, chars_read - (bp - buffer));
+
+#if defined (__BEOS__)
+      /* BeOS ignores O_TRUNC. */
+      ftruncate (file, chars_read - (bp - buffer));
+#endif
+
+      close (file);
+    }
+
+ truncate_exit:
+
+  FREE (buffer);
+
+  free (filename);
+  return rv;
+}
+
+/* Workhorse function for writing history.  Writes NELEMENT entries
+   from the history list to FILENAME.  OVERWRITE is non-zero if you
+   wish to replace FILENAME with the entries. */
+static int
+history_do_write (filename, nelements, overwrite)
+     const char *filename;
+     int nelements, overwrite;
+{
+  register int i;
+  char *output;
+  int file, mode, rv;
+#ifdef HISTORY_USE_MMAP
+  size_t cursize;
+
+  mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;
+#else
+  mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
+#endif
+  output = history_filename (filename);
+  rv = 0;
+
+  if ((file = open (output, mode, 0600)) == -1)
+    {
+      FREE (output);
+      return (errno);
+    }
+
+#ifdef HISTORY_USE_MMAP
+  cursize = overwrite ? 0 : lseek (file, 0, SEEK_END);
+#endif
+
+  if (nelements > history_length)
+    nelements = history_length;
+
+  /* Build a buffer of all the lines to write, and write them in one syscall.
+     Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
+  {
+    HIST_ENTRY **the_history;  /* local */
+    register int j;
+    int buffer_size;
+    char *buffer;
+
+    the_history = history_list ();
+    /* Calculate the total number of bytes to write. */
+    for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
+#if 0
+      buffer_size += 2 + HISTENT_BYTES (the_history[i]);
+#else
+      {
+       if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
+         buffer_size += strlen (the_history[i]->timestamp) + 1;
+       buffer_size += strlen (the_history[i]->line) + 1;
+      }
+#endif
+
+    /* Allocate the buffer, and fill it. */
+#ifdef HISTORY_USE_MMAP
+    if (ftruncate (file, buffer_size+cursize) == -1)
+      goto mmap_error;
+    buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize);
+    if ((void *)buffer == MAP_FAILED)
+      {
+mmap_error:
+       rv = errno;
+       FREE (output);
+       close (file);
+       return rv;
+      }
+#else    
+    buffer = (char *)malloc (buffer_size);
+    if (buffer == 0)
+      {
+       rv = errno;
+       FREE (output);
+       close (file);
+       return rv;
+      }
+#endif
+
+    for (j = 0, i = history_length - nelements; i < history_length; i++)
+      {
+       if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
+         {
+           strcpy (buffer + j, the_history[i]->timestamp);
+           j += strlen (the_history[i]->timestamp);
+           buffer[j++] = '\n';
+         }
+       strcpy (buffer + j, the_history[i]->line);
+       j += strlen (the_history[i]->line);
+       buffer[j++] = '\n';
+      }
+
+#ifdef HISTORY_USE_MMAP
+    if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0)
+      rv = errno;
+#else
+    if (write (file, buffer, buffer_size) < 0)
+      rv = errno;
+    free (buffer);
+#endif
+  }
+
+  close (file);
+
+  FREE (output);
+
+  return (rv);
+}
+
+/* Append NELEMENT entries to FILENAME.  The entries appended are from
+   the end of the list minus NELEMENTs up to the end of the list. */
+int
+append_history (nelements, filename)
+     int nelements;
+     const char *filename;
+{
+  return (history_do_write (filename, nelements, HISTORY_APPEND));
+}
+
+/* Overwrite FILENAME with the current history.  If FILENAME is NULL,
+   then write the history list to ~/.history.  Values returned
+   are as in read_history ().*/
+int
+write_history (filename)
+     const char *filename;
+{
+  return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
+}
index acf9d69ba5457427d111877194c16568242e43fc..3f33d41b100cfb70ab7613d1028fbe2bec3749ca 100644 (file)
@@ -81,8 +81,18 @@ ansicstr (string, len, flags, sawc, rlen)
            case 'n': c = '\n'; break;
            case 'r': c = '\r'; break;
            case 't': c = '\t'; break;
-           case '0': case '1': case '2': case '3':
-           case '4': case '5': case '6': case '7':
+           case '1': case '2': case '3':
+           case '4': case '5': case '6':
+           case '7':
+#if 1
+             if (flags & 1)
+               {
+                 *r++ = '\\';
+                 break;
+               }
+           /*FALLTHROUGH*/
+#endif
+           case '0':
              /* If (FLAGS & 1), we're translating a string for echo -e (or
                 the equivalent xpg_echo option), so we obey the SUSv3/
                 POSIX-2001 requirement and accept 0-3 octal digits after
diff --git a/lib/sh/strtrans.c~ b/lib/sh/strtrans.c~
new file mode 100644 (file)
index 0000000..db7b1ba
--- /dev/null
@@ -0,0 +1,284 @@
+/* strtrans.c - Translate and untranslate strings with ANSI-C escape
+               sequences. */
+
+/* Copyright (C) 2000
+   Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   Bash is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2, or (at your option) any later
+   version.
+
+   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Bash; see the file COPYING.  If not, write to the Free Software
+   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include <bashansi.h>
+#include <stdio.h>
+#include <chartypes.h>
+
+#include "shell.h"
+
+#ifdef ESC
+#undef ESC
+#endif
+#define ESC '\033'     /* ASCII */
+
+/* Convert STRING by expanding the escape sequences specified by the
+   ANSI C standard.  If SAWC is non-null, recognize `\c' and use that
+   as a string terminator.  If we see \c, set *SAWC to 1 before
+   returning.  LEN is the length of STRING.  If (FLAGS&1) is non-zero,
+   that we're translating a string for `echo -e', and therefore should not
+   treat a single quote as a character that may be escaped with a backslash.
+   If (FLAGS&2) is non-zero, we're expanding for the parser and want to
+   quote CTLESC and CTLNUL with CTLESC.  If (flags&4) is non-zero, we want
+   to remove the backslash before any unrecognized escape sequence. */
+char *
+ansicstr (string, len, flags, sawc, rlen)
+     char *string;
+     int len, flags, *sawc, *rlen;
+{
+  int c, temp;
+  char *ret, *r, *s;
+
+  if (string == 0 || *string == '\0')
+    return ((char *)NULL);
+
+  ret = (char *)xmalloc (2*len + 1);   /* 2*len for possible CTLESC */
+  for (r = ret, s = string; s && *s; )
+    {
+      c = *s++;
+      if (c != '\\' || *s == '\0')
+       *r++ = c;
+      else
+       {
+         switch (c = *s++)
+           {
+#if defined (__STDC__)
+           case 'a': c = '\a'; break;
+           case 'v': c = '\v'; break;
+#else
+           case 'a': c = '\007'; break;
+           case 'v': c = (int) 0x0B; break;
+#endif
+           case 'b': c = '\b'; break;
+           case 'e': case 'E':         /* ESC -- non-ANSI */
+             c = ESC; break;
+           case 'f': c = '\f'; break;
+           case 'n': c = '\n'; break;
+           case 'r': c = '\r'; break;
+           case 't': c = '\t'; break;
+           case '1': case '2': case '3':
+           case '4': case '5': case '6':
+           case '7':
+#if 1
+             if (flags & 1)
+               {
+                 *r++ = '\\';
+                 break;
+               }
+#endif
+           /*FALLTHROUGH*/
+           case '0':
+             /* If (FLAGS & 1), we're translating a string for echo -e (or
+                the equivalent xpg_echo option), so we obey the SUSv3/
+                POSIX-2001 requirement and accept 0-3 octal digits after
+                a leading `0'. */
+             temp = 2 + ((flags & 1) && (c == '0'));
+             for (c -= '0'; ISOCTAL (*s) && temp--; s++)
+               c = (c * 8) + OCTVALUE (*s);
+             c &= 0xFF;
+             break;
+           case 'x':                   /* Hex digit -- non-ANSI */
+             if ((flags & 2) && *s == '{')
+               {
+                 flags |= 16;          /* internal flag value */
+                 s++;
+               }
+             /* Consume at least two hex characters */
+             for (temp = 2, c = 0; ISXDIGIT ((unsigned char)*s) && temp--; s++)
+               c = (c * 16) + HEXVALUE (*s);
+             /* DGK says that after a `\x{' ksh93 consumes ISXDIGIT chars
+                until a non-xdigit or `}', so potentially more than two
+                chars are consumed. */
+             if (flags & 16)
+               {
+                 for ( ; ISXDIGIT ((unsigned char)*s); s++)
+                   c = (c * 16) + HEXVALUE (*s);
+                 flags &= ~16;
+                 if (*s == '}')
+                   s++;
+               }
+             /* \x followed by non-hex digits is passed through unchanged */
+             else if (temp == 2)
+               {
+                 *r++ = '\\';
+                 c = 'x';
+               }
+             c &= 0xFF;
+             break;
+           case '\\':
+             break;
+           case '\'': case '"': case '?':
+             if (flags & 1)
+               *r++ = '\\';
+             break;
+           case 'c':
+             if (sawc)
+               {
+                 *sawc = 1;
+                 *r = '\0';
+                 if (rlen)
+                   *rlen = r - ret;
+                 return ret;
+               }
+             else if ((flags & 1) == 0 && (c = *s))
+               {
+                 s++;
+                 c = TOCTRL(c);
+                 break;
+               }
+               /*FALLTHROUGH*/
+           default:
+               if ((flags & 4) == 0)
+                 *r++ = '\\';
+               break;
+           }
+         if ((flags & 2) && (c == CTLESC || c == CTLNUL))
+           *r++ = CTLESC;
+         *r++ = c;
+       }
+    }
+  *r = '\0';
+  if (rlen)
+    *rlen = r - ret;
+  return ret;
+}
+
+/* Take a string STR, possibly containing non-printing characters, and turn it
+   into a $'...' ANSI-C style quoted string.  Returns a new string. */
+char *
+ansic_quote (str, flags, rlen)
+     char *str;
+     int flags, *rlen;
+{
+  char *r, *ret, *s;
+  int l, rsize, t;
+  unsigned char c;
+
+  if (str == 0 || *str == 0)
+    return ((char *)0);
+
+  l = strlen (str);
+  rsize = 4 * l + 4;
+  r = ret = (char *)xmalloc (rsize);
+
+  *r++ = '$';
+  *r++ = '\'';
+
+  for (s = str, l = 0; *s; s++)
+    {
+      c = *s;
+      l = 1;           /* 1 == add backslash; 0 == no backslash */
+      switch (c)
+       {
+       case ESC: c = 'E'; break;
+#ifdef __STDC__
+       case '\a': c = 'a'; break;
+       case '\v': c = 'v'; break;
+#else
+       case '\007': c = 'a'; break;
+       case 0x0b: c = 'v'; break;
+#endif
+
+       case '\b': c = 'b'; break;
+       case '\f': c = 'f'; break;
+       case '\n': c = 'n'; break;
+       case '\r': c = 'r'; break;
+       case '\t': c = 't'; break;
+       case '\\':
+       case '\'':
+         break;
+       default:
+         if (ISPRINT (c) == 0)
+           {
+             *r++ = '\\';
+             *r++ = TOCHAR ((c >> 6) & 07);
+             *r++ = TOCHAR ((c >> 3) & 07);
+             *r++ = TOCHAR (c & 07);
+             continue;
+           }
+         l = 0;
+         break;
+       }
+      if (l)
+       *r++ = '\\';
+      *r++ = c;
+    }
+
+  *r++ = '\'';
+  *r = '\0';
+  if (rlen)
+    *rlen = r - ret;
+  return ret;
+}
+
+/* return 1 if we need to quote with $'...' because of non-printing chars. */
+int
+ansic_shouldquote (string)
+     const char *string;
+{
+  const char *s;
+  unsigned char c;
+
+  if (string == 0)
+    return 0;
+
+  for (s = string; c = *s; s++)
+    if (ISPRINT (c) == 0)
+      return 1;
+
+  return 0;
+}
+
+/* $'...' ANSI-C expand the portion of STRING between START and END and
+   return the result.  The result cannot be longer than the input string. */
+char *
+ansiexpand (string, start, end, lenp)
+     char *string;
+     int start, end, *lenp;
+{
+  char *temp, *t;
+  int len, tlen;
+
+  temp = (char *)xmalloc (end - start + 1);
+  for (tlen = 0, len = start; len < end; )
+    temp[tlen++] = string[len++];
+  temp[tlen] = '\0';
+
+  if (*temp)
+    {
+      t = ansicstr (temp, tlen, 2, (int *)NULL, lenp);
+      free (temp);
+      return (t);
+    }
+  else
+    {
+      if (lenp)
+       *lenp = 0;
+      return (temp);
+    }
+}
index 4607933e549f80b66006d4e36bb78dfbd70d304c..df20010566c5b8ced9b38b1f2b137a336a7b8110 100644 (file)
@@ -507,7 +507,6 @@ make_bare_simple_command ()
   command->value.Simple = temp = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM));
 
   temp->flags = 0;
-itrace("make_bare_simple_command: line_number = %d", line_number);
   temp->line = line_number;
   temp->words = (WORD_LIST *)NULL;
   temp->redirects = (REDIRECT *)NULL;
@@ -533,10 +532,7 @@ make_simple_command (element, command)
     command = make_bare_simple_command ();
 
   if (element.word)
-{
-  itrace("make_simple_command: adding %s", element.word->word);
     command->value.Simple->words = make_word_list (element.word, command->value.Simple->words);
-}
   else if (element.redirect)
     {
       REDIRECT *r = element.redirect;
diff --git a/subst.c b/subst.c
index 7950eed4076091b5fc2e25fde74be91198e1ecd9..44ea7de1d1eace98f78a8b103e72f3e3e43a6c30 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -2599,10 +2599,10 @@ expand_assignment_string_to_string (string, quoted)
 }
 
 char *
-expand_arith_string (string)
+expand_arith_string (string, quoted)
      char *string;
 {
-  return (expand_string_if_necessary (string, Q_DOUBLE_QUOTES, expand_string));
+  return (expand_string_if_necessary (string, quoted, expand_string));
 }
 
 #if defined (COND_COMMAND)
@@ -5278,11 +5278,7 @@ verify_substring_values (value, substr, vtype, e1p, e2p)
   else
     t = (char *)0;
 
-#if 0
-  temp1 = expand_string_if_necessary (substr, Q_DOUBLE_QUOTES, expand_string);
-#else
-  temp1 = expand_arith_string (substr);
-#endif
+  temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES);
   *e1p = evalexp (temp1, &expok);
   free (temp1);
   if (expok == 0)
@@ -5327,11 +5323,7 @@ verify_substring_values (value, substr, vtype, e1p, e2p)
     {
       t++;
       temp2 = savestring (t);
-#if 0
-      temp1 = expand_string_if_necessary (temp2, Q_DOUBLE_QUOTES, expand_string);
-#else
-      temp1 = expand_arith_string (temp2);
-#endif
+      temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES);
       free (temp2);
       t[-1] = ':';
       *e2p = evalexp (temp1, &expok);
@@ -6481,11 +6473,7 @@ param_expand (string, sindex, quoted, expanded_something,
          temp2[t_index] = '\0';
 
          /* Expand variables found inside the expression. */
-#if 0
-         temp1 = expand_string_if_necessary (temp2, Q_DOUBLE_QUOTES, expand_string);
-#else
-         temp1 = expand_arith_string (temp2);
-#endif
+         temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES);
          free (temp2);
 
 arithsub:
@@ -6527,11 +6515,7 @@ comsub:
       zindex = t_index;
 
        /* Do initial variable expansion. */
-#if 0
-      temp1 = expand_string_if_necessary (temp, Q_DOUBLE_QUOTES, expand_string);
-#else
-      temp1 = expand_arith_string (temp);
-#endif
+      temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES);
 
       goto arithsub;
 
diff --git a/subst.h b/subst.h
index b7c6682bfecc91145431c827fd3c28ab5ee2585f..e07055b742052f2591801160fcf67b5118b66a40 100644 (file)
--- a/subst.h
+++ b/subst.h
@@ -152,7 +152,7 @@ extern char *expand_string_unsplit_to_string __P((char *, int));
 extern char *expand_assignment_string_to_string __P((char *, int));
 
 /* Expand an arithmetic expression string */
-extern char *expand_arith_string __P((char *));
+extern char *expand_arith_string __P((char *, int));
 
 /* De-quoted quoted characters in STRING. */
 extern char *dequote_string __P((char *));
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 900e43e3b7252ac5cdcd6b6f4e146314933d6f60..9545aaa720ff8cd6bc5b6b979ed486347ede6896 100644 (file)
@@ -139,6 +139,11 @@ value = new1 new2 new3
 7 8 9
 8 11
 8 11
+6
+nordholz
+8
+8
+8
 
 a b c d e f g
 for case if then else
index 9d7e1afb088aa06d0042b1e5d695257334314999..474eaeddfdcf82f191ae040edaa5989b006def59 100644 (file)
@@ -18,3 +18,13 @@ echo $a $b
 typeset -i a b
 a=(5+3) b=(4+7)
 echo $a $b
+
+let a=(4*3)/2
+echo $a
+
+LNAME=nordholz
+echo ${LNAME}
+echo ${#LNAME}
+
+echo ${#LNAME[$(( 0 ))]}
+echo ${#LNAME[$(( 0+0 ))]}
diff --git a/tests/array4.sub~ b/tests/array4.sub~
new file mode 100644 (file)
index 0000000..f61d7a9
--- /dev/null
@@ -0,0 +1,30 @@
+# compound assignment parsing problems in bash-3.1-release
+func()
+{
+       local -a x=() y=()
+}
+
+a=() b=()
+eval foo=()
+eval foo=() bar=() qux=( "bash" )
+
+foo=( "bash" )
+eval foo=( "bash" )
+eval bar=( "bash" ) bax=( "bash" )
+
+let a=(5 + 3) b=(4 + 7)
+echo $a $b
+
+typeset -i a b
+a=(5+3) b=(4+7)
+echo $a $b
+
+a=(4*3)/2
+echo $a
+
+LNAME=nordholz
+echo ${LNAME}
+echo ${#LNAME}
+
+echo ${#LNAME[$(( 0 ))]}
+echo ${#LNAME[$(( 0+0 ))]}
index 3d7ef8e76d396d77dc0448920719649f5e06e695..f00d39a76361541efc2a00b65dfd2cf905c4c624 100644 (file)
@@ -41,3 +41,5 @@ f
 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20
 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10
 -20 -19 -18 -17 -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0
+a-{bd}-c a-{be}-c
+a-{bdef-g-c a-{bdef-i-c
index 3f57829f060b9558581d7fa2557e2c3fcfe512bb..5a57f2844e9d716258cb50792fc972a1e7887ca5 100644 (file)
@@ -68,3 +68,8 @@ echo 0{1..9} {10..20}
 # do negative numbers work?
 echo {-1..-10}
 echo {-20..0}
+
+# weirdly-formed brace expansions -- fixed in post-bash-3.1
+echo a-{b{d,e}}-c
+
+echo a-{bdef-{g,i}-c
diff --git a/tests/braces.tests~ b/tests/braces.tests~
new file mode 100644 (file)
index 0000000..3f57829
--- /dev/null
@@ -0,0 +1,70 @@
+echo ff{c,b,a}
+echo f{d,e,f}g
+echo {l,n,m}xyz
+echo {abc\,def}
+echo {abc}
+
+echo \{a,b,c,d,e}
+echo {x,y,\{a,b,c}}
+echo {x\,y,\{abc\},trie}
+
+echo /usr/{ucb/{ex,edit},lib/{ex,how_ex}}
+
+echo XXXX\{`echo a b c | tr ' ' ','`\}
+eval echo XXXX\{`echo a b c | tr ' ' ','`\}
+
+echo {}
+echo { }
+echo }
+echo {
+echo abcd{efgh
+
+echo foo {1,2} bar
+echo `zecho foo {1,2} bar`
+echo $(zecho foo {1,2} bar)
+
+var=baz
+varx=vx
+vary=vy
+
+echo foo{bar,${var}.}
+echo foo{bar,${var}}
+
+echo "${var}"{x,y}
+echo $var{x,y}
+echo ${var}{x,y}
+
+unset var varx vary
+
+# new sequence brace operators
+echo {1..10}
+
+# this doesn't work yet
+echo {0..10,braces}
+# but this does
+echo {{0..10},braces}
+echo x{{0..10},braces}y
+
+echo {3..3}
+echo x{3..3}y
+echo {10..1}
+echo {10..1}y
+echo x{10..1}y
+
+echo {a..f}
+echo {f..a}
+
+echo {a..A}
+echo {A..a}
+
+echo {f..f}
+
+# mixes are incorrectly-formed brace expansions
+echo {1..f}
+echo {f..1}
+
+echo 0{1..9} {10..20}
+
+# do negative numbers work?
+echo {-1..-10}
+echo {-20..0}