]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20050630 snapshot
authorChet Ramey <chet.ramey@case.edu>
Sat, 3 Dec 2011 18:48:02 +0000 (13:48 -0500)
committerChet Ramey <chet.ramey@case.edu>
Sat, 3 Dec 2011 18:48:02 +0000 (13:48 -0500)
43 files changed:
CWRU/CWRU.chlog
CWRU/CWRU.chlog~
Makefile.in
Makefile.in~
arrayfunc.c
arrayfunc.c~
bashhist.c
bashhist.c~ [new file with mode: 0644]
bashhist.h
bashhist.h~ [new file with mode: 0644]
bashline.c
builtins/history.def
builtins/history.def~ [new file with mode: 0644]
command.h
command.h~
jobs.c
jobs.c~
lib/malloc/trace.c
lib/readline/complete.c
lib/readline/input.c
lib/readline/input.c~ [new file with mode: 0644]
lib/readline/readline.c
lib/readline/readline.c~
lib/readline/rldefs.h
lib/readline/rldefs.h~ [new file with mode: 0644]
lib/readline/rltty.c
lib/readline/rltty.c.save1 [new file with mode: 0644]
lib/readline/rltty.c~
lib/sh/shquote.c
lib/sh/shquote.c~
make_cmd.c
make_cmd.c~
parse.y
parse.y~
print_cmd.c
print_cmd.c~
redir.c
subst.c
subst.c~
tests/RUN-ONE-TEST
tests/arith-for.right
tests/herestr.right
tests/herestr.right~ [new file with mode: 0644]

index 845f09fad1f9021d94952bfe7e5a70f7418b934d..6bb4fa3ed14c7690e25ce227ff30c48734a909e3 100644 (file)
@@ -11625,3 +11625,105 @@ variables.c
        - assign export_env to environ (extern char **) every time it changes
          (mostly in add_to_export_env define), so maybe getenv will work on
          systems that don't allow it to be replaced
+
+                                  6/29
+                                  ----
+bashline.c
+       - in bash_directory_completion_hook, be careful about not turning `/'
+         into `//' and `//' into `///' for benefit of those systems that treat
+         `//' as some sort of `network root'.  Fix from Eric Blake
+         <ebb9@byu.net>
+
+lib/readline/complete.c
+       - in to_print, do the right thing after stripping the trailing slash
+         from full_pathname: // doesn't turn into /, and /// doesn't become
+         //.  Fix from Eric Blake <ebb9@byu.net>
+
+                                  6/30
+                                  ----
+lib/malloc/trace.c
+       - include <unistd.h> if it's available for a definition of size_t
+
+jobs.c
+       - in wait_for, if a child process is marked as running but waitpid()
+         returns -1/ECHILD (e.g., when the bash process is being traced by
+         strace), make sure to increment c_reaped when marking the child as
+         dead
+       - in without_job_control, make sure to close the pgrp pipe after
+         calling start_pipeline
+
+                                   7/1
+                                   ---
+Makefile.in
+       - only remove pathnames.h when the other files created by running
+         configure are removed (e.g., Makefile).  Fix from William Park
+
+lib/sh/shquote.c
+       - since backslash-newline disappears when within double quotes, don't
+         add a backslash in front of a newline in sh_double_quote.  Problem
+         reported by William Park
+
+jobs.c
+       - in notify_of_job_status, don't print status messages about
+         terminated background processes unless job control is active
+
+bashhist.c
+       - new variable, hist_last_line_pushed, set to 0 in really_add_history
+         (used by `history -s' code)
+
+bashhist.h
+       - new extern declaration for history -s
+
+builtins/history.def
+       - don't remove last history entry in push_history if it was added by
+         a call to push_history -- use hist_last_line_pushed as a sentinel
+         and set it after adding history entry.  This allows multiple
+         calls to history -s to work right:  adding all lines to the history
+         rather than deleting all but the last.  Bug reported by Matthias
+         Schniedermeyer <ms@citd.de>
+       - pay attention to hist_last_line_pushed in expand_and_print_history()
+         so we don't delete an entry pushed by history -s
+
+                                   7/4
+                                   ---
+print_cmd.c
+       - fix print_arith_for_command to not print so many blanks between
+         expressions in ((...))
+
+command.h
+       - new word flag: W_DQUOTE.  Means word should be treated as if double
+         quoted
+
+make_cmd.c
+       - add W_DQUOTE to word flags in make_arith_for_expr
+
+parse.y
+       - add W_DQUOTE to word flags for (( ... )) arithmetic commands
+
+subst.c
+       - don't perform tilde expansion on a word with W_DQUOTE flag set
+       - don't perform process substitution on a word with W_DQUOTE flag set
+
+arrayfunc.c
+       - expand an array index within [...] the same way as an arithmetic
+         expansion between (( ... ))
+
+lib/readline/input.c
+       - use getch() instead of read() on mingw
+
+lib/readline/readline.c
+       - add a few key bindings for the arrow keys on mingw
+
+lib/readline/rldefs.h
+       - if on mingw, define NO_TTY_DRIVER
+
+lib/readline/rltty.c
+       - compile in the stub functions for _rl_{disable,restore}_tty_signals
+         if on mingw
+       - compile in stub function for rl_restart_output on mingw
+       - make sure enough functions and macros are defined to compile if
+         NO_TTY_DRIVER is defined (lightly tested - builds on MacOS X, at
+         least)
+
+
+
index 29ae0607054e270aa713f4b7e183aa5a5518a878..5f65d3881027812d29b1b9f730ebececb4de32fb 100644 (file)
@@ -11586,13 +11586,15 @@ lib/readline/rlprivate.h
                                    ---
 builtins/read.def
        - fixed a bug that occurred when reading a set number of chars and
-         the nth char is a backslash (read one too many)
+         the nth char is a backslash (read one too many).  Bug reported by
+         Chris Morgan <chmorgan@gmail.com>
 
 execute_cmd.c
        - fix execute_builtin so the `unset' builtin also operates on the
          temporary environment in POSIX mode (as well as source and eval),
          so that unsetting variables in the temporary environment doesn't
-         leave them set when unset completes
+         leave them set when unset completes.  Report by Eric Blake
+         <ebb9@byu.net>
 
 array.c
        - fix from William Park for array_rshift when shifting right on an
@@ -11607,3 +11609,115 @@ jobs.c
        - add a run-time check for WCONTINUED being defined in header files
          but rejected with EINVAL by waitpid().  Fix from Maciej Rozycki
          <macro@linux-mips.org>
+
+                                  6/20
+                                  ----
+bashhist.c
+       - make sure calls to sv_histchars are protected by #ifdef BANG_HISTORY
+       - ditto for calls to history_expand_line_internal
+
+                                  6/23
+                                  ----
+doc/bashref.texi
+       - remove extra blank lines in @menu constructs
+
+variables.c
+       - assign export_env to environ (extern char **) every time it changes
+         (mostly in add_to_export_env define), so maybe getenv will work on
+         systems that don't allow it to be replaced
+
+                                  6/29
+                                  ----
+bashline.c
+       - in bash_directory_completion_hook, be careful about not turning `/'
+         into `//' and `//' into `///' for benefit of those systems that treat
+         `//' as some sort of `network root'.  Fix from Eric Blake
+         <ebb9@byu.net>
+
+lib/readline/complete.c
+       - in to_print, do the right thing after stripping the trailing slash
+         from full_pathname: // doesn't turn into /, and /// doesn't become
+         //.  Fix from Eric Blake <ebb9@byu.net>
+
+                                  6/30
+                                  ----
+lib/malloc/trace.c
+       - include <unistd.h> if it's available for a definition of size_t
+
+jobs.c
+       - in wait_for, if a child process is marked as running but waitpid()
+         returns -1/ECHILD (e.g., when the bash process is being traced by
+         strace), make sure to increment c_reaped when marking the child as
+         dead
+       - in without_job_control, make sure to close the pgrp pipe after
+         calling start_pipeline
+
+                                   7/1
+                                   ---
+Makefile.in
+       - only remove pathnames.h when the other files created by running
+         configure are removed (e.g., Makefile).  Fix from William Park
+
+lib/sh/shquote.c
+       - since backslash-newline disappears when within double quotes, don't
+         add a backslash in front of a newline in sh_double_quote.  Problem
+         reported by William Park
+
+jobs.c
+       - in notify_of_job_status, don't print status messages about
+         terminated background processes unless job control is active
+
+bashhist.c
+       - new variable, hist_last_line_pushed, set to 0 in really_add_history
+         (used by `history -s' code)
+
+bashhist.h
+       - new extern declaration for history -s
+
+builtins/history.def
+       - don't remove last history entry in push_history if it was added by
+         a call to push_history -- use hist_last_line_pushed as a sentinel
+         and set it after adding history entry.  This allows multiple
+         calls to history -s to work right:  adding all lines to the history
+         rather than deleting all but the last.  Bug reported by Matthias
+         Schniedermeyer <ms@citd.de>
+       - pay attention to hist_last_line_pushed in expand_and_print_history()
+         so we don't delete an entry pushed by history -s
+
+                                   7/4
+                                   ---
+print_cmd.c
+       - fix print_arith_for_command to not print so many blanks between
+         expressions in ((...))
+
+command.h
+       - new word flag: W_DQUOTE.  Means word should be treated as if double
+         quoted
+
+make_cmd.c
+       - add W_DQUOTE to word flags in make_arith_for_expr
+
+parse.y
+       - add W_DQUOTE to word flags for (( ... )) arithmetic commands
+
+subst.c
+       - don't perform tilde expansion on a word with W_DQUOTE flag set
+       - don't perform process substitution on a word with W_DQUOTE flag set
+
+arrayfunc.c
+       - expand an array index within [...] the same way as an arithmetic
+         expansion between (( ... ))
+
+lib/readline/input.c
+       - use getch() instead of read() on mingw
+
+lib/readline/readline.c
+       - add a few key bindings for the arrow keys on mingw
+
+lib/readline/rltty.c
+       - compile in the stub functions for _rl_{disable,restore}_tty_signals
+         if on mingw
+       - compile in stub function for rl_restart_output on mingw
+
+lib/readline/rldefs.h
+       - if on mingw, define NO_TTY_DRIVER
index f41a138b23c6f303514eff80ae54488c7414813f..7b3ff490e6f446ff7e6e9bbbdc7e77477f0a6c21 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile for bash-3.1, version 2.156
+# Makefile for bash-3.1, version 2.157
 #
 # Copyright (C) 1996-2005 Free Software Foundation, Inc.
 
@@ -730,7 +730,7 @@ LIB_SUBDIRS = ${RL_LIBDIR}  ${HIST_LIBDIR} ${TERM_LIBDIR} ${GLOB_LIBDIR} \
 
 basic-clean:
        $(RM) $(OBJECTS) $(Program) bashbug
-       $(RM) .build .made version.h pathnames.h
+       $(RM) .build .made version.h 
 
 clean: basic-clean
        ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ )
@@ -760,7 +760,7 @@ distclean:  basic-clean maybe-clean
        done
        -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ )
        $(RM) $(CREATED_CONFIGURE) tags TAGS 
-       $(RM) $(CREATED_SUPPORT) Makefile $(CREATED_MAKEFILES)
+       $(RM) $(CREATED_SUPPORT) Makefile $(CREATED_MAKEFILES) pathnames.h
 
 maintainer-clean:      basic-clean
        @echo This command is intended for maintainers to use.
@@ -774,7 +774,7 @@ maintainer-clean:   basic-clean
        done
        -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ )
        $(RM) $(CREATED_CONFIGURE) $(CREATED_MAKEFILES)
-       $(RM) $(CREATED_SUPPORT) Makefile
+       $(RM) $(CREATED_SUPPORT) Makefile pathnames.h
 
 maybe-clean:
        -if test "X$(topdir)" != "X$(BUILD_DIR)" ; then \
index 35b0dc30778a48c876b6666d195af68c6d8c780d..f41a138b23c6f303514eff80ae54488c7414813f 100644 (file)
@@ -117,7 +117,7 @@ THIS_SH = $(BUILD_DIR)/$(Program)
 PROFILE_FLAGS= @PROFILE_FLAGS@
 
 CFLAGS = @CFLAGS@
-CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ @CROSS_COMPILE@
 CPPFLAGS = @CPPFLAGS@
 CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
 LOCAL_CFLAGS = @LOCAL_CFLAGS@ ${DEBUG}
index 127197de8909870c3acc1727b662b7bbb678f6c9..3bdd54f507080a81a0fdb715e801032ef20d22f7 100644 (file)
@@ -592,7 +592,11 @@ array_expand_index (s, len)
   exp = (char *)xmalloc (len);
   strncpy (exp, s, len - 1);
   exp[len - 1] = '\0';
+#if 0
   t = expand_string_to_string (exp, 0);
+#else 
+  t = expand_string_to_string (exp, Q_DOUBLE_QUOTES);
+#endif
   this_command_name = (char *)NULL;
   val = evalexp (t, &expok);
   free (t);
index c1b589f7995e0c40d7fe410b1b13fcd31fe0579e..127197de8909870c3acc1727b662b7bbb678f6c9 100644 (file)
@@ -1,6 +1,6 @@
 /* arrayfunc.c -- High-level array functions used by other parts of the shell. */
 
-/* Copyright (C) 2001-2004 Free Software Foundation, Inc.
+/* Copyright (C) 2001-2005 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
index 73637dc144d5fe07087b69e3f8b6bff9c735a553..1b2df168aeca4d2475aac7dfae4e8b378dc04e2f 100644 (file)
@@ -156,6 +156,10 @@ int history_control;
    to a previous entry as part of command-oriented-history processing. */
 int hist_last_line_added;
 
+/* Set to 1 if builtins/history.def:push_history added the last history
+   entry. */
+int hist_last_line_pushed;
+
 #if defined (READLINE)
 /* If non-zero, and readline is being used, the user is offered the
    chance to re-edit a failed history expansion. */
@@ -700,6 +704,7 @@ really_add_history (line)
      char *line;
 {
   hist_last_line_added = 1;
+  hist_last_line_pushed = 0;
   add_history (line);
   history_lines_this_session++;
 }
diff --git a/bashhist.c~ b/bashhist.c~
new file mode 100644 (file)
index 0000000..73637dc
--- /dev/null
@@ -0,0 +1,815 @@
+/* bashhist.c -- bash interface to the GNU history library. */
+
+/* Copyright (C) 1993-2004 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 (HISTORY)
+
+#if defined (HAVE_UNISTD_H)
+#  ifdef _MINIX
+#    include <sys/types.h>
+#  endif
+#  include <unistd.h>
+#endif
+
+#include "bashtypes.h"
+#include <stdio.h>
+#include <errno.h>
+#include "bashansi.h"
+#include "posixstat.h"
+#include "filecntl.h"
+
+#include "bashintl.h"
+
+#include "shell.h"
+#include "flags.h"
+#include "input.h"
+#include "parser.h"    /* for the struct dstack stuff. */
+#include "pathexp.h"   /* for the struct ignorevar stuff */
+#include "bashhist.h"  /* matching prototypes and declarations */
+#include "builtins/common.h"
+
+#include <readline/history.h>
+#include <glob/glob.h>
+#include <glob/strmatch.h>
+
+#if defined (READLINE)
+#  include "bashline.h"
+extern int rl_done, rl_dispatching;    /* should really include readline.h */
+#endif
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+static int histignore_item_func __P((struct ign *));
+static int check_history_control __P((char *));
+static void hc_erasedups __P((char *));
+static void really_add_history __P((char *));
+
+static struct ignorevar histignore =
+{
+  "HISTIGNORE",
+  (struct ign *)0,
+  0,
+  (char *)0,
+  (sh_iv_item_func_t *)histignore_item_func,
+};
+
+#define HIGN_EXPAND 0x01
+
+/* Declarations of bash history variables. */
+/* Non-zero means to remember lines typed to the shell on the history
+   list.  This is different than the user-controlled behaviour; this
+   becomes zero when we read lines from a file, for example. */
+int remember_on_history = 1;
+
+/* The number of lines that Bash has added to this history session.  The
+   difference between the number of the top element in the history list
+   (offset from history_base) and the number of lines in the history file.
+   Appending this session's history to the history file resets this to 0. */
+int history_lines_this_session;
+
+/* The number of lines that Bash has read from the history file. */
+int history_lines_in_file;
+
+#if defined (BANG_HISTORY)
+/* Non-zero means do no history expansion on this line, regardless
+   of what history_expansion says. */
+int history_expansion_inhibited;
+#endif
+
+/* With the old default, every line was saved in the history individually.
+   I.e., if the user enters:
+       bash$ for i in a b c
+       > do
+       > echo $i
+       > done
+   Each line will be individually saved in the history.
+       bash$ history
+       10  for i in a b c
+       11  do
+       12  echo $i
+       13  done
+       14  history
+   If the variable command_oriented_history is set, multiple lines
+   which form one command will be saved as one history entry.
+       bash$ for i in a b c
+       > do
+       > echo $i
+       > done
+       bash$ history
+       10  for i in a b c
+    do
+    echo $i
+    done
+       11  history
+   The user can then recall the whole command all at once instead
+   of just being able to recall one line at a time.
+
+   This is now enabled by default.
+   */
+int command_oriented_history = 1;
+
+/* Set to 1 if the first line of a possibly-multi-line command was saved
+   in the history list.  Managed by maybe_add_history(), but global so
+   the history-manipluating builtins can see it. */
+int current_command_first_line_saved = 0;
+
+/* Non-zero means to store newlines in the history list when using
+   command_oriented_history rather than trying to use semicolons. */
+int literal_history;
+
+/* Non-zero means to append the history to the history file at shell
+   exit, even if the history has been stifled. */
+int force_append_history;
+
+/* A nit for picking at history saving.  Flags have the following values:
+
+   Value == 0 means save all lines parsed by the shell on the history.
+   Value & HC_IGNSPACE means save all lines that do not start with a space.
+   Value & HC_IGNDUPS means save all lines that do not match the last
+   line saved.
+   Value & HC_ERASEDUPS means to remove all other matching lines from the
+   history list before saving the latest line. */
+int history_control;
+
+/* Set to 1 if the last command was added to the history list successfully
+   as a separate history entry; set to 0 if the line was ignored or added
+   to a previous entry as part of command-oriented-history processing. */
+int hist_last_line_added;
+
+#if defined (READLINE)
+/* If non-zero, and readline is being used, the user is offered the
+   chance to re-edit a failed history expansion. */
+int history_reediting;
+
+/* If non-zero, and readline is being used, don't directly execute a
+   line with history substitution.  Reload it into the editing buffer
+   instead and let the user further edit and confirm with a newline. */
+int hist_verify;
+
+#endif /* READLINE */
+
+/* Non-zero means to not save function definitions in the history list. */
+int dont_save_function_defs;
+
+/* Variables declared in other files used here. */
+extern int current_command_line_count;
+
+extern struct dstack dstack;
+
+static int bash_history_inhibit_expansion __P((char *, int));
+#if defined (READLINE)
+static void re_edit __P((char *));
+#endif
+static int history_expansion_p __P((char *));
+static int shell_comment __P((char *));
+static int should_expand __P((char *));
+static HIST_ENTRY *last_history_entry __P((void));
+static char *expand_histignore_pattern __P((char *));
+static int history_should_ignore __P((char *));
+
+/* Is the history expansion starting at string[i] one that should not
+   be expanded? */
+static int
+bash_history_inhibit_expansion (string, i)
+     char *string;
+     int i;
+{
+  /* The shell uses ! as a pattern negation character in globbing [...]
+     expressions, so let those pass without expansion. */
+  if (i > 0 && (string[i - 1] == '[') && member (']', string + i + 1))
+    return (1);
+  /* The shell uses ! as the indirect expansion character, so let those
+     expansions pass as well. */
+  else if (i > 1 && string[i - 1] == '{' && string[i - 2] == '$' &&
+            member ('}', string + i + 1))
+    return (1);
+#if defined (EXTENDED_GLOB)
+  else if (extended_glob && i > 1 && string[i+1] == '(' && member (')', string + i + 2))
+    return (1);
+#endif
+  else
+    return (0);
+}
+
+void
+bash_initialize_history ()
+{
+  history_quotes_inhibit_expansion = 1;
+  history_search_delimiter_chars = ";&()|<>";
+  history_inhibit_expansion_function = bash_history_inhibit_expansion;
+#if defined (BANG_HISTORY)
+  sv_histchars ("histchars");
+#endif
+}
+
+void
+bash_history_reinit (interact)
+     int interact;
+{
+#if defined (BANG_HISTORY)
+  history_expansion = interact != 0;
+  history_expansion_inhibited = 1;
+#endif
+  remember_on_history = interact != 0;
+  history_inhibit_expansion_function = bash_history_inhibit_expansion;
+}
+
+void
+bash_history_disable ()
+{
+  remember_on_history = 0;
+#if defined (BANG_HISTORY)
+  history_expansion_inhibited = 1;
+#endif
+}
+
+void
+bash_history_enable ()
+{
+  remember_on_history = 1;
+#if defined (BANG_HISTORY)
+  history_expansion_inhibited = 0;
+#endif
+  history_inhibit_expansion_function = bash_history_inhibit_expansion;
+  sv_history_control ("HISTCONTROL");
+  sv_histignore ("HISTIGNORE");
+}
+
+/* Load the history list from the history file. */
+void
+load_history ()
+{
+  char *hf;
+  struct stat buf;
+
+  /* Truncate history file for interactive shells which desire it.
+     Note that the history file is automatically truncated to the
+     size of HISTSIZE if the user does not explicitly set the size
+     differently. */
+  set_if_not ("HISTFILESIZE", get_string_value ("HISTSIZE"));
+  sv_histsize ("HISTFILESIZE");
+
+  /* Read the history in HISTFILE into the history list. */
+  hf = get_string_value ("HISTFILE");
+
+  if (hf && *hf && stat (hf, &buf) == 0)
+    {
+      read_history (hf);
+      using_history ();
+      history_lines_in_file = where_history ();
+    }
+}
+
+#ifdef INCLUDE_UNUSED
+/* Write the existing history out to the history file. */
+void
+save_history ()
+{
+  char *hf;
+  struct stat buf;
+
+  hf = get_string_value ("HISTFILE");
+  if (hf && *hf && stat (hf, &buf) == 0)
+    {
+      /* Append only the lines that occurred this session to
+        the history file. */
+      using_history ();
+
+      if (history_lines_this_session < where_history () || force_append_history)
+       append_history (history_lines_this_session, hf);
+      else
+       write_history (hf);
+
+      sv_histsize ("HISTFILESIZE");
+    }
+}
+#endif
+
+int
+maybe_append_history (filename)
+     char *filename;
+{
+  int fd, result;
+  struct stat buf;
+
+  result = EXECUTION_SUCCESS;
+  if (history_lines_this_session && (history_lines_this_session < where_history ()))
+    {
+      /* If the filename was supplied, then create it if necessary. */
+      if (stat (filename, &buf) == -1 && errno == ENOENT)
+       {
+         fd = open (filename, O_WRONLY|O_CREAT, 0600);
+         if (fd < 0)
+           {
+             builtin_error (_("%s: cannot create: %s"), filename, strerror (errno));
+             return (EXECUTION_FAILURE);
+           }
+         close (fd);
+       }
+      result = append_history (history_lines_this_session, filename);
+      history_lines_in_file += history_lines_this_session;
+      history_lines_this_session = 0;
+    }
+  return (result);
+}
+
+/* If this is an interactive shell, then append the lines executed
+   this session to the history file. */
+int
+maybe_save_shell_history ()
+{
+  int result;
+  char *hf;
+  struct stat buf;
+
+  result = 0;
+  if (history_lines_this_session)
+    {
+      hf = get_string_value ("HISTFILE");
+
+      if (hf && *hf)
+       {
+         /* If the file doesn't exist, then create it. */
+         if (stat (hf, &buf) == -1)
+           {
+             int file;
+             file = open (hf, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+             if (file != -1)
+               close (file);
+           }
+
+         /* Now actually append the lines if the history hasn't been
+            stifled.  If the history has been stifled, rewrite the
+            history file. */
+         using_history ();
+         if (history_lines_this_session <= where_history () || force_append_history)
+           {
+             result = append_history (history_lines_this_session, hf);
+             history_lines_in_file += history_lines_this_session;
+           }
+         else
+           {
+             result = write_history (hf);
+             history_lines_in_file = history_lines_this_session;
+           }
+         history_lines_this_session = 0;
+
+         sv_histsize ("HISTFILESIZE");
+       }
+    }
+  return (result);
+}
+
+#if defined (READLINE)
+/* Tell readline () that we have some text for it to edit. */
+static void
+re_edit (text)
+     char *text;
+{
+  if (bash_input.type == st_stdin)
+    bash_re_edit (text);
+}
+#endif /* READLINE */
+
+/* Return 1 if this line needs history expansion. */
+static int
+history_expansion_p (line)
+     char *line;
+{
+  register char *s;
+
+  for (s = line; *s; s++)
+    if (*s == history_expansion_char || *s == history_subst_char)
+      return 1;
+  return 0;
+}
+
+/* Do pre-processing on LINE.  If PRINT_CHANGES is non-zero, then
+   print the results of expanding the line if there were any changes.
+   If there is an error, return NULL, otherwise the expanded line is
+   returned.  If ADDIT is non-zero the line is added to the history
+   list after history expansion.  ADDIT is just a suggestion;
+   REMEMBER_ON_HISTORY can veto, and does.
+   Right now this does history expansion. */
+char *
+pre_process_line (line, print_changes, addit)
+     char *line;
+     int print_changes, addit;
+{
+  char *history_value;
+  char *return_value;
+  int expanded;
+
+  return_value = line;
+  expanded = 0;
+
+#  if defined (BANG_HISTORY)
+  /* History expand the line.  If this results in no errors, then
+     add that line to the history if ADDIT is non-zero. */
+  if (!history_expansion_inhibited && history_expansion && history_expansion_p (line))
+    {
+      expanded = history_expand (line, &history_value);
+
+      if (expanded)
+       {
+         if (print_changes)
+           {
+             if (expanded < 0)
+               internal_error ("%s", history_value);
+#if defined (READLINE)
+             else if (hist_verify == 0 || expanded == 2)
+#else
+             else
+#endif
+               fprintf (stderr, "%s\n", history_value);
+           }
+
+         /* If there was an error, return NULL. */
+         if (expanded < 0 || expanded == 2)    /* 2 == print only */
+           {
+#    if defined (READLINE)
+             if (expanded == 2 && rl_dispatching == 0 && *history_value)
+#    else            
+             if (expanded == 2 && *history_value)
+#    endif /* !READLINE */
+               maybe_add_history (history_value);
+
+             free (history_value);
+
+#    if defined (READLINE)
+             /* New hack.  We can allow the user to edit the
+                failed history expansion. */
+             if (history_reediting && expanded < 0 && rl_done)
+               re_edit (line);
+#    endif /* READLINE */
+             return ((char *)NULL);
+           }
+
+#    if defined (READLINE)
+         if (hist_verify && expanded == 1)
+           {
+             re_edit (history_value);
+             return ((char *)NULL);
+           }
+#    endif
+       }
+
+      /* Let other expansions know that return_value can be free'ed,
+        and that a line has been added to the history list.  Note
+        that we only add lines that have something in them. */
+      expanded = 1;
+      return_value = history_value;
+    }
+#  endif /* BANG_HISTORY */
+
+  if (addit && remember_on_history && *return_value)
+    maybe_add_history (return_value);
+
+#if 0
+  if (expanded == 0)
+    return_value = savestring (line);
+#endif
+
+  return (return_value);
+}
+
+/* Return 1 if the first non-whitespace character in LINE is a `#', indicating
+ * that the line is a shell comment. */
+static int
+shell_comment (line)
+     char *line;
+{
+  char *p;
+
+  for (p = line; p && *p && whitespace (*p); p++)
+    ;
+  return (p && *p == '#');
+}
+
+#ifdef INCLUDE_UNUSED
+/* Remove shell comments from LINE.  A `#' and anything after it is a comment.
+   This isn't really useful yet, since it doesn't handle quoting. */
+static char *
+filter_comments (line)
+     char *line;
+{
+  char *p;
+
+  for (p = line; p && *p && *p != '#'; p++)
+    ;
+  if (p && *p == '#')
+    *p = '\0';
+  return (line);
+}
+#endif
+
+/* Check LINE against what HISTCONTROL says to do.  Returns 1 if the line
+   should be saved; 0 if it should be discarded. */
+static int
+check_history_control (line)
+     char *line;
+{
+  HIST_ENTRY *temp;
+  int r;
+
+  if (history_control == 0)
+    return 1;
+
+  /* ignorespace or ignoreboth */
+  if ((history_control & HC_IGNSPACE) && *line == ' ')
+    return 0;
+
+  /* ignoredups or ignoreboth */
+  if (history_control & HC_IGNDUPS)
+    {
+      using_history ();
+      temp = previous_history ();
+
+      r = (temp == 0 || STREQ (temp->line, line) == 0);
+
+      using_history ();
+
+      if (r == 0)
+       return r;
+    }
+
+  return 1;
+}
+
+/* Remove all entries matching LINE from the history list.  Triggered when
+   HISTCONTROL includes `erasedups'. */
+static void
+hc_erasedups (line)
+     char *line;
+{
+  HIST_ENTRY *temp;
+  int r;
+
+  using_history ();
+  while (temp = previous_history ())
+    {
+      if (STREQ (temp->line, line))
+       {
+         r = where_history ();
+         remove_history (r);
+       }
+    }
+  using_history ();
+}
+
+/* Add LINE to the history list, handling possibly multi-line compound
+   commands.  We note whether or not we save the first line of each command
+   (which is usually the entire command and history entry), and don't add
+   the second and subsequent lines of a multi-line compound command if we
+   didn't save the first line.  We don't usually save shell comment lines in
+   compound commands in the history, because they could have the effect of
+   commenting out the rest of the command when the entire command is saved as
+   a single history entry (when COMMAND_ORIENTED_HISTORY is enabled).  If
+   LITERAL_HISTORY is set, we're saving lines in the history with embedded
+   newlines, so it's OK to save comment lines.  We also make sure to save
+   multiple-line quoted strings or other constructs. */
+void
+maybe_add_history (line)
+     char *line;
+{
+  hist_last_line_added = 0;
+
+  /* Don't use the value of history_control to affect the second
+     and subsequent lines of a multi-line command (old code did
+     this only when command_oriented_history is enabled). */
+  if (current_command_line_count > 1)
+    {
+      if (current_command_first_line_saved &&
+         (literal_history || dstack.delimiter_depth != 0 || shell_comment (line) == 0))
+       bash_add_history (line);
+      return;
+    }
+
+  /* This is the first line of a (possible multi-line) command.  Note whether
+     or not we should save the first line and remember it. */
+  current_command_first_line_saved = check_add_history (line, 0);
+}
+
+/* Just check LINE against HISTCONTROL and HISTIGNORE and add it to the
+   history if it's OK.  Used by `history -s' as well as maybe_add_history().
+   Returns 1 if the line was saved in the history, 0 otherwise. */
+int
+check_add_history (line, force)
+     char *line;
+     int force;
+{
+  if (check_history_control (line) && history_should_ignore (line) == 0)
+    {
+      /* We're committed to saving the line.  If the user has requested it,
+        remove other matching lines from the history. */
+      if (history_control & HC_ERASEDUPS)
+       hc_erasedups (line);
+        
+      if (force)
+       {
+         really_add_history (line);
+         using_history ();
+       }
+      else
+       bash_add_history (line);
+      return 1;
+    }
+  return 0;
+}
+
+/* Add a line to the history list.
+   The variable COMMAND_ORIENTED_HISTORY controls the style of history
+   remembering;  when non-zero, and LINE is not the first line of a
+   complete parser construct, append LINE to the last history line instead
+   of adding it as a new line. */
+void
+bash_add_history (line)
+     char *line;
+{
+  int add_it, offset, curlen;
+  HIST_ENTRY *current, *old;
+  char *chars_to_add, *new_line;
+
+  add_it = 1;
+  if (command_oriented_history && current_command_line_count > 1)
+    {
+      chars_to_add = literal_history ? "\n" : history_delimiting_chars ();
+
+      using_history ();
+      current = previous_history ();
+
+      if (current)
+       {
+         /* If the previous line ended with an escaped newline (escaped
+            with backslash, but otherwise unquoted), then remove the quoted
+            newline, since that is what happens when the line is parsed. */
+         curlen = strlen (current->line);
+
+         if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\\' &&
+             current->line[curlen - 2] != '\\')
+           {
+             current->line[curlen - 1] = '\0';
+             curlen--;
+             chars_to_add = "";
+           }
+
+         new_line = (char *)xmalloc (1
+                                     + curlen
+                                     + strlen (line)
+                                     + strlen (chars_to_add));
+         sprintf (new_line, "%s%s%s", current->line, chars_to_add, line);
+         offset = where_history ();
+         old = replace_history_entry (offset, new_line, current->data);
+         free (new_line);
+
+         if (old)
+           free_history_entry (old);
+
+         add_it = 0;
+       }
+    }
+
+  if (add_it)
+    really_add_history (line);
+
+  using_history ();
+}
+
+static void
+really_add_history (line)
+     char *line;
+{
+  hist_last_line_added = 1;
+  add_history (line);
+  history_lines_this_session++;
+}
+
+int
+history_number ()
+{
+  using_history ();
+  return (get_string_value ("HISTSIZE") ? history_base + where_history () : 1);
+}
+
+static int
+should_expand (s)
+     char *s;
+{
+  char *p;
+
+  for (p = s; p && *p; p++)
+    {
+      if (*p == '\\')
+       p++;
+      else if (*p == '&')
+       return 1;
+    }
+  return 0;
+}
+
+static int
+histignore_item_func (ign)
+     struct ign *ign;
+{
+  if (should_expand (ign->val))
+    ign->flags |= HIGN_EXPAND;
+  return (0);
+}
+
+void
+setup_history_ignore (varname)
+     char *varname;
+{
+  setup_ignore_patterns (&histignore);
+}
+
+static HIST_ENTRY *
+last_history_entry ()
+{
+  HIST_ENTRY *he;
+
+  using_history ();
+  he = previous_history ();
+  using_history ();
+  return he;
+}
+
+char *
+last_history_line ()
+{
+  HIST_ENTRY *he;
+
+  he = last_history_entry ();
+  if (he == 0)
+    return ((char *)NULL);
+  return he->line;
+}
+
+static char *
+expand_histignore_pattern (pat)
+     char *pat;
+{
+  HIST_ENTRY *phe;
+  char *ret;
+
+  phe = last_history_entry ();
+
+  if (phe == (HIST_ENTRY *)0)
+    return (savestring (pat));
+
+  ret = strcreplace (pat, '&', phe->line, 1);
+
+  return ret;
+}
+
+/* Return 1 if we should not put LINE into the history according to the
+   patterns in HISTIGNORE. */
+static int
+history_should_ignore (line)
+     char *line;
+{
+  register int i, match;
+  char *npat;
+
+  if (histignore.num_ignores == 0)
+    return 0;
+
+  for (i = match = 0; i < histignore.num_ignores; i++)
+    {
+      if (histignore.ignores[i].flags & HIGN_EXPAND)
+       npat = expand_histignore_pattern (histignore.ignores[i].val);
+      else
+       npat = histignore.ignores[i].val;
+
+      match = strmatch (npat, line, FNMATCH_EXTFLAG) != FNM_NOMATCH;
+
+      if (histignore.ignores[i].flags & HIGN_EXPAND)
+       free (npat);
+
+      if (match)
+       break;
+    }
+
+  return match;
+}
+#endif /* HISTORY */
index a4edb50527750c61963d9327d1fb595f91a85a64..0a01d691eabb0bf0ecc4c8e93375e090749fb37c 100644 (file)
@@ -38,6 +38,7 @@ extern int history_control;
 extern int command_oriented_history;
 extern int current_command_first_line_saved;
 extern int hist_last_line_added;
+extern int hist_last_line_pushed;
 
 #  if defined (BANG_HISTORY)
 extern int history_expansion_inhibited;
diff --git a/bashhist.h~ b/bashhist.h~
new file mode 100644 (file)
index 0000000..a4edb50
--- /dev/null
@@ -0,0 +1,64 @@
+/* bashhist.h -- interface to the bash history functions in bashhist.c. */
+
+/* Copyright (C) 1993 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. */
+
+#if !defined (_BASHHIST_H_)
+#define _BASHHIST_H_
+
+#include "stdc.h"
+
+/* Flag values for history_control */
+#define HC_IGNSPACE    0x01
+#define HC_IGNDUPS     0x02
+#define HC_ERASEDUPS   0x04
+
+#define HC_IGNBOTH     (HC_IGNSPACE|HC_IGNDUPS)
+
+extern int remember_on_history;
+extern int history_lines_this_session;
+extern int history_lines_in_file;
+extern int history_expansion;
+extern int history_control;
+extern int command_oriented_history;
+extern int current_command_first_line_saved;
+extern int hist_last_line_added;
+
+#  if defined (BANG_HISTORY)
+extern int history_expansion_inhibited;
+#  endif /* BANG_HISTORY */
+
+extern void bash_initialize_history __P((void));
+extern void bash_history_reinit __P((int));
+extern void bash_history_disable __P((void));
+extern void bash_history_enable __P((void));
+extern void load_history __P((void));
+extern void save_history __P((void));
+extern int maybe_append_history __P((char *));
+extern int maybe_save_shell_history __P((void));
+extern char *pre_process_line __P((char *, int, int));
+extern void maybe_add_history __P((char *));
+extern void bash_add_history __P((char *));
+extern int check_add_history __P((char *, int));
+extern int history_number __P((void));
+
+extern void setup_history_ignore __P((char *));
+
+extern char *last_history_line __P((void));
+
+#endif /* _BASHHIST_H_ */
index ebe2304d9bb426bb6e632424fd59d444949db564..6af64d9f6e21563e37dd18e3a2d3853cacdff839 100644 (file)
@@ -2309,9 +2309,12 @@ bash_directory_completion_hook (dirname)
       if (temp1[len1 - 1] == '/')
        {
          len2 = strlen (temp2);
-         temp2 = (char *)xrealloc (temp2, len2 + 2);
-         temp2[len2] = '/';
-         temp2[len2 + 1] = '\0';
+         if (len2 > 2)         /* don't append `/' to `/' or `//' */
+           {
+             temp2 = (char *)xrealloc (temp2, len2 + 2);
+             temp2[len2] = '/';
+             temp2[len2 + 1] = '\0';
+           }
        }
       free (local_dirname);
       *dirname = temp2;
index 52b1113feb8f2576147499f7b9453dc21815bd0b..40708da1dfb44d62e0a0cdb05969c3c6df850f78 100644 (file)
@@ -346,6 +346,8 @@ push_history (list)
 {
   char *s;
 
+if (current_command_line_count == 0)
+  itrace("push_history: current_command_line_count == 0");
   /* Delete the last history entry if it was a single entry added to the
      history list (generally the `history -s' itself), or if `history -s'
      is being used in a compound command and the compound command was
@@ -353,9 +355,11 @@ push_history (list)
      If you don't want history -s to remove the compound command from the
      history, change #if 0 to #if 1 below. */
 #if 0
-  if (hist_last_line_added && delete_last_history () == 0)
+  if (hist_last_line_pushed == 0 && hist_last_line_added && delete_last_history () == 0)
 #else
-  if ((hist_last_line_added || (current_command_line_count > 0 && current_command_first_line_saved && command_oriented_history))
+  if (hist_last_line_pushed == 0 &&
+       (hist_last_line_added ||
+         (current_command_line_count > 0 && current_command_first_line_saved && command_oriented_history))
       && delete_last_history () == 0)
 #endif
       return;
@@ -368,6 +372,8 @@ push_history (list)
      entry.  Without FORCE=1, if current_command_line_count were > 1, the
      line would be appended to the entry before the just-deleted entry. */
   check_add_history (s, 1);    /* obeys HISTCONTROL, HISTIGNORE */
+
+  hist_last_line_pushed = 1;   /* XXX */
   free (s);
 }
 
@@ -379,7 +385,7 @@ expand_and_print_history (list)
   char *s;
   int r, result;
 
-  if (hist_last_line_added && delete_last_history () == 0)
+  if (hist_last_line_pushed == 0 && hist_last_line_added && delete_last_history () == 0)
     return EXECUTION_FAILURE;
   result = EXECUTION_SUCCESS;
   while (list)
diff --git a/builtins/history.def~ b/builtins/history.def~
new file mode 100644 (file)
index 0000000..33164a3
--- /dev/null
@@ -0,0 +1,411 @@
+This file is history.def, from which is created history.c.
+It implements the builtin "history" in Bash.
+
+Copyright (C) 1987-2003 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.
+
+$PRODUCES history.c
+
+$BUILTIN history
+$FUNCTION history_builtin
+$DEPENDS_ON HISTORY
+$SHORT_DOC history [-c] [-d offset] [n] or history -awrn [filename] or history -ps arg [arg...]
+Display the history list with line numbers.  Lines listed with
+with a `*' have been modified.  Argument of N says to list only
+the last N lines.  The `-c' option causes the history list to be
+cleared by deleting all of the entries.  The `-d' option deletes
+the history entry at offset OFFSET.  The `-w' option writes out the
+current history to the history file;  `-r' means to read the file and
+append the contents to the history list instead.  `-a' means
+to append history lines from this session to the history file.
+Argument `-n' means to read all history lines not already read
+from the history file and append them to the history list.
+
+If FILENAME is given, then that is used as the history file else
+if $HISTFILE has a value, that is used, else ~/.bash_history.
+If the -s option is supplied, the non-option ARGs are appended to
+the history list as a single entry.  The -p option means to perform
+history expansion on each ARG and display the result, without storing
+anything in the history list.
+
+If the $HISTTIMEFORMAT variable is set and not null, its value is used
+as a format string for strftime(3) to print the time stamp associated
+with each displayed history entry.  No time stamps are printed otherwise.
+$END
+
+#include <config.h>
+
+#if defined (HISTORY)
+#include "../bashtypes.h"
+#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
+#  include <sys/file.h>
+#endif
+#include "posixstat.h"
+#include "filecntl.h"
+#include <errno.h>
+#include <stdio.h>
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../bashhist.h"
+#include <readline/history.h>
+#include "bashgetopt.h"
+#include "common.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+extern int current_command_line_count;
+
+static char *histtime __P((HIST_ENTRY *, const char *));
+static void display_history __P((WORD_LIST *));
+static int delete_histent __P((int));
+static int delete_last_history __P((void));
+static void push_history __P((WORD_LIST *));
+static int expand_and_print_history __P((WORD_LIST *));
+
+#define AFLAG  0x01
+#define RFLAG  0x02
+#define WFLAG  0x04
+#define NFLAG  0x08
+#define SFLAG  0x10
+#define PFLAG  0x20
+#define CFLAG  0x40
+#define DFLAG  0x80
+
+int
+history_builtin (list)
+     WORD_LIST *list;
+{
+  int flags, opt, result, old_history_lines, obase;
+  char *filename, *delete_arg;
+  intmax_t delete_offset;
+
+  flags = 0;
+  reset_internal_getopt ();
+  while ((opt = internal_getopt (list, "acd:npsrw")) != -1)
+    {
+      switch (opt)
+       {
+       case 'a':
+         flags |= AFLAG;
+         break;
+       case 'c':
+         flags |= CFLAG;
+         break;
+       case 'n':
+         flags |= NFLAG;
+         break;
+       case 'r':
+         flags |= RFLAG;
+         break;
+       case 'w':
+         flags |= WFLAG;
+         break;
+       case 's':
+         flags |= SFLAG;
+         break;
+       case 'd':
+         flags |= DFLAG;
+         delete_arg = list_optarg;
+         break;
+       case 'p':
+#if defined (BANG_HISTORY)
+         flags |= PFLAG;
+#endif
+         break;
+       default:
+         builtin_usage ();
+         return (EX_USAGE);
+       }
+    }
+  list = loptend;
+
+  opt = flags & (AFLAG|RFLAG|WFLAG|NFLAG);
+  if (opt && opt != AFLAG && opt != RFLAG && opt != WFLAG && opt != NFLAG)
+    {
+      builtin_error (_("cannot use more than one of -anrw"));
+      return (EXECUTION_FAILURE);
+    }
+
+  /* clear the history, but allow other arguments to add to it again. */
+  if (flags & CFLAG)
+    {
+      clear_history ();
+      if (list == 0)
+       return (EXECUTION_SUCCESS);
+    }
+
+  if (flags & SFLAG)
+    {
+      if (list)
+       push_history (list);
+      return (EXECUTION_SUCCESS);
+    }
+#if defined (BANG_HISTORY)
+  else if (flags & PFLAG)
+    {
+      if (list)
+       return (expand_and_print_history (list));
+      return (EXECUTION_SUCCESS);
+    }
+#endif
+  else if (flags & DFLAG)
+    {
+      if ((legal_number (delete_arg, &delete_offset) == 0)
+         || (delete_offset < history_base)
+         || (delete_offset > (history_base + history_length)))
+       {
+         sh_erange (delete_arg, _("history position"));
+         return (EXECUTION_FAILURE);
+       }
+      opt = delete_offset;
+      result = delete_histent (opt - history_base);
+      /* Since remove_history changes history_length, this can happen if
+        we delete the last history entry. */
+      if (where_history () > history_length)
+       history_set_pos (history_length);
+      return (result ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+    }
+  else if ((flags & (AFLAG|RFLAG|NFLAG|WFLAG|CFLAG)) == 0)
+    {
+      display_history (list);
+      return (EXECUTION_SUCCESS);
+    }
+
+  filename = list ? list->word->word : get_string_value ("HISTFILE");
+  result = EXECUTION_SUCCESS;
+
+  if (flags & AFLAG)           /* Append session's history to file. */
+    result = maybe_append_history (filename);
+  else if (flags & WFLAG)      /* Write entire history. */
+    result = write_history (filename);
+  else if (flags & RFLAG)      /* Read entire file. */
+    result = read_history (filename);
+  else if (flags & NFLAG)      /* Read `new' history from file. */
+    {
+      /* Read all of the lines in the file that we haven't already read. */
+      old_history_lines = history_lines_in_file;
+      obase = history_base;
+
+      using_history ();
+      result = read_history_range (filename, history_lines_in_file, -1);
+      using_history ();
+
+      history_lines_in_file = where_history ();
+      /* The question is whether we reset history_lines_this_session to 0,
+        losing any history entries we had before we read the new entries
+        from the history file, or whether we count the new entries we just
+        read from the file as history lines added during this session.
+        Right now, we do the latter.  This will cause these history entries
+        to be written to the history file along with any intermediate entries
+        we add when we do a `history -a', but the alternative is losing
+        them altogether. */
+      history_lines_this_session += history_lines_in_file - old_history_lines +
+                                   history_base - obase;
+    }
+
+  return (result ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
+}
+
+/* Accessors for HIST_ENTRY lists that are called HLIST. */
+#define histline(i) (hlist[(i)]->line)
+#define histdata(i) (hlist[(i)]->data)
+
+static char *
+histtime (hlist, histtimefmt)
+     HIST_ENTRY *hlist;
+     const char *histtimefmt;
+{
+  static char timestr[128];
+  time_t t;
+
+  t = history_get_time (hlist);
+  if (t)
+    strftime (timestr, sizeof (timestr), histtimefmt, localtime (&t));
+  else
+    strcpy (timestr, "??");
+  return timestr;
+}
+
+static void
+display_history (list)
+     WORD_LIST *list;
+{
+  register int i;
+  intmax_t limit;
+  HIST_ENTRY **hlist;
+  char *histtimefmt, *timestr;
+
+  if (list)
+    {
+      limit = get_numeric_arg (list, 0);
+      if (limit < 0)
+       limit = -limit;
+    }
+  else
+    limit = -1;
+
+  hlist = history_list ();
+
+  if (hlist)
+    {
+      for (i = 0;  hlist[i]; i++)
+       ;
+
+      if (0 <= limit && limit < i)
+       i -= limit;
+      else
+       i = 0;
+
+
+      histtimefmt = get_string_value ("HISTTIMEFORMAT");
+
+      while (hlist[i])
+       {
+         QUIT;
+
+         timestr = (histtimefmt && *histtimefmt) ? histtime (hlist[i], histtimefmt) : (char *)NULL;
+         printf ("%5d%c %s%s\n", i + history_base,
+                 histdata(i) ? '*' : ' ',
+                 ((timestr && *timestr) ? timestr : ""),
+                 histline(i));
+         i++;
+       }
+    }
+}
+
+/* Delete and free the history list entry at offset I. */
+static int
+delete_histent (i)
+     int i;
+{
+  HIST_ENTRY *discard;
+
+  discard = remove_history (i);
+  if (discard)
+    free_history_entry (discard);
+
+  return 1;
+}
+
+static int
+delete_last_history ()
+{
+  register int i;
+  HIST_ENTRY **hlist, *histent;
+  int r;
+
+  hlist = history_list ();
+  if (hlist == NULL)
+    return 0;
+
+  for (i = 0; hlist[i]; i++)
+    ;
+  i--;
+
+  /* History_get () takes a parameter that must be offset by history_base. */
+  histent = history_get (history_base + i);    /* Don't free this */
+  if (histent == NULL)
+    return 0;
+
+  r = delete_histent (i);
+
+  if (where_history () > history_length)
+    history_set_pos (history_length);
+
+  return r;
+}
+
+/* Remove the last entry in the history list and add each argument in
+   LIST to the history. */
+static void
+push_history (list)
+     WORD_LIST *list;
+{
+  char *s;
+
+if (current_command_line_count == 0)
+  itrace("push_history: current_command_line_count == 0");
+  /* Delete the last history entry if it was a single entry added to the
+     history list (generally the `history -s' itself), or if `history -s'
+     is being used in a compound command and the compound command was
+     added to the history as a single element (command-oriented history).
+     If you don't want history -s to remove the compound command from the
+     history, change #if 0 to #if 1 below. */
+#if 0
+  if (hist_last_line_pushed == 0 && hist_last_line_added && delete_last_history () == 0)
+#else
+  if (hist_last_line_pushed == 0 &&
+       (hist_last_line_added ||
+         (current_command_line_count > 0 && current_command_first_line_saved && command_oriented_history))
+      && delete_last_history () == 0)
+#endif
+      return;
+
+  s = string_list (list);
+  /* Call check_add_history with FORCE set to 1 to skip the check against
+     current_command_line_count.  If history -s is used in a compound
+     command, the above code will delete the compound command's history
+     entry and this call will add the line to the history as a separate
+     entry.  Without FORCE=1, if current_command_line_count were > 1, the
+     line would be appended to the entry before the just-deleted entry. */
+  check_add_history (s, 1);    /* obeys HISTCONTROL, HISTIGNORE */
+
+  hist_last_line_pushed = 1;   /* XXX */
+  free (s);
+}
+
+#if defined (BANG_HISTORY)
+static int
+expand_and_print_history (list)
+     WORD_LIST *list;
+{
+  char *s;
+  int r, result;
+
+  if (hist_last_line_added && delete_last_history () == 0)
+    return EXECUTION_FAILURE;
+  result = EXECUTION_SUCCESS;
+  while (list)
+    {
+      r = history_expand (list->word->word, &s);
+      if (r < 0)
+       {
+         builtin_error (_("%s: history expansion failed"), list->word->word);
+         result = EXECUTION_FAILURE;
+       }
+      else
+       {
+         fputs (s, stdout);
+         putchar ('\n');
+       }
+      FREE (s);
+      list = list->next;
+    }
+  fflush (stdout);
+  return result;
+}
+#endif /* BANG_HISTORY */
+#endif /* HISTORY */
index f9fe7ce32e141d8e39ba1a9f42e5737ca9741f56..285940a67e8e5b8ed2dd897f6f0a61417bbdfa90 100644 (file)
--- a/command.h
+++ b/command.h
@@ -86,6 +86,7 @@ enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select,
 #define W_ASSNBLTIN    0x10000 /* word is a builtin command that takes assignments */
 #define W_ASSIGNARG    0x20000 /* word is assignment argument to command */
 #define W_HASQUOTEDNULL        0x40000 /* word contains a quoted null character */
+#define W_DQUOTE       0x80000 /* word should be treated as if double-quoted */
 
 /* Possible values for subshell_environment */
 #define SUBSHELL_ASYNC 0x01    /* subshell caused by `command &' */
index b3fd91e7eefbe74eabac1d956f5d300efaafb1d3..f9fe7ce32e141d8e39ba1a9f42e5737ca9741f56 100644 (file)
@@ -1,7 +1,7 @@
 /* command.h -- The structures used internally to represent commands, and
    the extern declarations of the functions used to create them. */
 
-/* Copyright (C) 1993 Free Software Foundation, Inc.
+/* Copyright (C) 1993-2005 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
diff --git a/jobs.c b/jobs.c
index 05d93950be86994d77e8aa27e4e5f1f2ea3d4852..373cf773d5cf104411ce53bef523503644eb72bb 100644 (file)
--- a/jobs.c
+++ b/jobs.c
@@ -699,7 +699,9 @@ bgp_delete (pid)
   if (p == 0)
     return 0;          /* not found */
 
-itrace("bgp_delete: deleting %d", pid);
+#if defined (DEBUG)
+  itrace("bgp_delete: deleting %d", pid);
+#endif
 
   /* Housekeeping in the border cases. */
   if (p == bgpids.list)
@@ -814,13 +816,15 @@ cleanup_dead_jobs ()
 
   /* XXX could use js.j_firstj here */
   for (i = 0; i < js.j_jobslots; i++)
-{
-if (i < js.j_firstj && jobs[i])
-  itrace("cleanup_dead_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+    {
+#if defined (DEBUG)
+      if (i < js.j_firstj && jobs[i])
+       itrace("cleanup_dead_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#endif
 
-    if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i))
-      delete_job (i, 0);
-}
+      if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i))
+       delete_job (i, 0);
+    }
   UNQUEUE_SIGCHLD(os);
 }
 
@@ -931,9 +935,14 @@ delete_job (job_index, warn_stopped)
   if (temp->state == JDEAD)
     {
       js.c_reaped -= ndel;
-if (js.c_reaped < 0)
-  itrace("delete_job (%d): js.c_reaped (%d) < 0 ndel = %d", job_index, js.c_reaped, ndel);
       js.j_ndead--;
+      if (js.c_reaped < 0)
+       {
+#ifdef DEBUG
+         itrace("delete_job (%d pgrp %d): js.c_reaped (%d) < 0 ndel = %d js.j_ndead = %d", job_index, temp->pgrp, js.c_reaped, ndel, js.j_ndead);
+#endif
+         js.c_reaped = 0;
+       }
     }
 
   if (temp->deferred)
@@ -1088,8 +1097,10 @@ map_over_jobs (func, arg1, arg2)
   /* XXX could use js.j_firstj here */
   for (i = result = 0; i < js.j_jobslots; i++)
     {
-if (i < js.j_firstj && jobs[i])
-  itrace("map_over_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#if defined (DEBUG)
+      if (i < js.j_firstj && jobs[i])
+       itrace("map_over_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#endif
       if (jobs[i])
        {
          result = (*func)(jobs[i], arg1, arg2, i);
@@ -1224,8 +1235,10 @@ find_job (pid, alive_only, procp)
   /* XXX could use js.j_firstj here */
   for (i = 0; i < js.j_jobslots; i++)
     {
-if (i < js.j_firstj && jobs[i])
-  itrace("find_job: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#if defined (DEBUG)
+      if (i < js.j_firstj && jobs[i])
+       itrace("find_job: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#endif
       if (jobs[i])
        {
          p = jobs[i]->pipe;
@@ -1989,12 +2002,14 @@ wait_for_background_pids ()
       /* find first running job; if none running in foreground, break */
       /* XXX could use js.j_firstj here */
       for (i = 0; i < js.j_jobslots; i++)
-{
-if (i < js.j_firstj && jobs[i])
-  itrace("wait_for_background_pids: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
-       if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0)
-         break;
-}
+       {
+#if defined (DEBUG)
+         if (i < js.j_firstj && jobs[i])
+           itrace("wait_for_background_pids: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#endif
+         if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0)
+           break;
+       }
       if (i == js.j_jobslots)
        {
          UNBLOCK_CHILD (oset);
@@ -2255,6 +2270,7 @@ wait_for (pid)
              if (job != NO_JOB)
                {
                  jobs[job]->state = JDEAD;
+                 js.c_reaped++;
                  js.j_ndead++;
                }
            }
@@ -3209,8 +3225,9 @@ notify_of_job_status ()
 
          /* POSIX.2 says we have to hang onto the statuses of at most the
             last CHILD_MAX background processes if the shell is running a
-            script.  If the shell is not interactive, don't print anything
-            unless the job was killed by a signal. */
+            script.  If the shell is running a script, either from a file
+            or standard input, don't print anything unless the job was
+            killed by a signal. */
          if (startup_state == 0 && WIFSIGNALED (s) == 0 &&
                ((DEADJOB (job) && IS_FOREGROUND (job) == 0) || STOPPED (job)))
            continue;
@@ -3273,7 +3290,7 @@ notify_of_job_status ()
                      fprintf (stderr, "\n");
                    }
                }
-             else
+             else if (job_control)     /* XXX job control test added */
                {
                  if (dir == 0)
                    dir = current_working_directory ();
@@ -3654,12 +3671,14 @@ delete_all_jobs (running_only)
 
       /* XXX could use js.j_firstj here */
       for (i = 0; i < js.j_jobslots; i++)
-{
-if (i < js.j_firstj && jobs[i])
-  itrace("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
-       if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i))))
-         delete_job (i, 1);
-}
+       {
+#if defined (DEBUG)
+         if (i < js.j_firstj && jobs[i])
+           itrace("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#endif
+         if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i))))
+           delete_job (i, 1);
+       }
       if (running_only == 0)
        {
          free ((char *)jobs);
@@ -3706,12 +3725,14 @@ count_all_jobs ()
   BLOCK_CHILD (set, oset);
   /* XXX could use js.j_firstj here */
   for (i = n = 0; i < js.j_jobslots; i++)
-{
-if (i < js.j_firstj && jobs[i])
-  itrace("count_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
-    if (jobs[i] && DEADJOB(i) == 0)
-      n++;
-}
+    {
+#if defined (DEBUG)
+      if (i < js.j_firstj && jobs[i])
+       itrace("count_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#endif
+      if (jobs[i] && DEADJOB(i) == 0)
+       n++;
+    }
   UNBLOCK_CHILD (oset);
   return n;
 }
@@ -3778,8 +3799,10 @@ mark_dead_jobs_as_notified (force)
   /* XXX could use js.j_firstj here */
   for (i = ndead = ndeadproc = 0; i < js.j_jobslots; i++)
     {
-if (i < js.j_firstj && jobs[i])
-  itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#if defined (DEBUG)
+      if (i < js.j_firstj && jobs[i])
+       itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#endif
       if (jobs[i] && DEADJOB (i))
        {
          ndead++;
@@ -3827,8 +3850,10 @@ itrace("mark_dead_jobs_as_notified: child_max = %d ndead = %d ndeadproc = %d", j
     {
       if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i, 0) != last_asynchronous_pid)))
        {
-if (i < js.j_firstj && jobs[i])
-  itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#if defined (DEBUG)
+         if (i < js.j_firstj && jobs[i])
+           itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#endif
          /* If marking this job as notified would drop us down below
             child_max, don't mark it so we can keep at least child_max
             statuses.  XXX -- need to check what Posix actually says
@@ -3876,6 +3901,9 @@ without_job_control ()
 {
   stop_making_children ();
   start_pipeline ();
+#if defined (PGRP_PIPE)
+  pipe_close (pgrp_pipe);
+#endif
   delete_all_jobs (0);
   set_job_control (0);
 }
diff --git a/jobs.c~ b/jobs.c~
index f8a5c8193a9ff089d5ae45d19fe5ab2a124aa40d..b9d03b186b24d0c7a16bebb702089e13be4c720f 100644 (file)
--- a/jobs.c~
+++ b/jobs.c~
@@ -699,7 +699,9 @@ bgp_delete (pid)
   if (p == 0)
     return 0;          /* not found */
 
-itrace("bgp_delete: deleting %d", pid);
+#if defined (DEBUG)
+  itrace("bgp_delete: deleting %d", pid);
+#endif
 
   /* Housekeeping in the border cases. */
   if (p == bgpids.list)
@@ -814,13 +816,15 @@ cleanup_dead_jobs ()
 
   /* XXX could use js.j_firstj here */
   for (i = 0; i < js.j_jobslots; i++)
-{
-if (i < js.j_firstj && jobs[i])
-  itrace("cleanup_dead_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+    {
+#if defined (DEBUG)
+      if (i < js.j_firstj && jobs[i])
+       itrace("cleanup_dead_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#endif
 
-    if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i))
-      delete_job (i, 0);
-}
+      if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i))
+       delete_job (i, 0);
+    }
   UNQUEUE_SIGCHLD(os);
 }
 
@@ -931,9 +935,14 @@ delete_job (job_index, warn_stopped)
   if (temp->state == JDEAD)
     {
       js.c_reaped -= ndel;
-if (js.c_reaped < 0)
-  itrace("delete_job (%d): js.c_reaped (%d) < 0 ndel = %d", job_index, js.c_reaped, ndel);
       js.j_ndead--;
+      if (js.c_reaped < 0)
+       {
+#ifdef DEBUG
+         itrace("delete_job (%d pgrp %d): js.c_reaped (%d) < 0 ndel = %d js.j_ndead = %d", job_index, temp->pgrp, js.c_reaped, ndel, js.j_ndead);
+#endif
+         js.c_reaped = 0;
+       }
     }
 
   if (temp->deferred)
@@ -1088,8 +1097,10 @@ map_over_jobs (func, arg1, arg2)
   /* XXX could use js.j_firstj here */
   for (i = result = 0; i < js.j_jobslots; i++)
     {
-if (i < js.j_firstj && jobs[i])
-  itrace("map_over_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#if defined (DEBUG)
+      if (i < js.j_firstj && jobs[i])
+       itrace("map_over_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#endif
       if (jobs[i])
        {
          result = (*func)(jobs[i], arg1, arg2, i);
@@ -1224,8 +1235,10 @@ find_job (pid, alive_only, procp)
   /* XXX could use js.j_firstj here */
   for (i = 0; i < js.j_jobslots; i++)
     {
-if (i < js.j_firstj && jobs[i])
-  itrace("find_job: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#if defined (DEBUG)
+      if (i < js.j_firstj && jobs[i])
+       itrace("find_job: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#endif
       if (jobs[i])
        {
          p = jobs[i]->pipe;
@@ -1989,12 +2002,14 @@ wait_for_background_pids ()
       /* find first running job; if none running in foreground, break */
       /* XXX could use js.j_firstj here */
       for (i = 0; i < js.j_jobslots; i++)
-{
-if (i < js.j_firstj && jobs[i])
-  itrace("wait_for_background_pids: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
-       if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0)
-         break;
-}
+       {
+#if defined (DEBUG)
+         if (i < js.j_firstj && jobs[i])
+           itrace("wait_for_background_pids: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#endif
+         if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0)
+           break;
+       }
       if (i == js.j_jobslots)
        {
          UNBLOCK_CHILD (oset);
@@ -2255,6 +2270,7 @@ wait_for (pid)
              if (job != NO_JOB)
                {
                  jobs[job]->state = JDEAD;
+                 js.c_reaped++;
                  js.j_ndead++;
                }
            }
@@ -2818,6 +2834,7 @@ waitchld (wpid, block)
   PROCESS *child;
   pid_t pid;
   int call_set_current, last_stopped_job, job, children_exited, waitpid_flags;
+  static int wcontinued = WCONTINUED;  /* run-time fix for glibc problem */
 
   call_set_current = children_exited = 0;
   last_stopped_job = NO_JOB;
@@ -2827,12 +2844,19 @@ waitchld (wpid, block)
       /* We don't want to be notified about jobs stopping if job control
         is not active.  XXX - was interactive_shell instead of job_control */
       waitpid_flags = (job_control && subshell_environment == 0)
-                       ? (WUNTRACED|WCONTINUED)
+                       ? (WUNTRACED|wcontinued)
                        : 0;
       if (sigchld || block == 0)
        waitpid_flags |= WNOHANG;
       pid = WAITPID (-1, &status, waitpid_flags);
 
+      /* WCONTINUED may be rejected by waitpid as invalid even when defined */
+      if (wcontinued && pid < 0 && errno == EINVAL)
+       {
+         wcontinued = 0;
+         continue;     /* jump back to the test and retry without WCONTINUED */
+       }
+
       /* The check for WNOHANG is to make sure we decrement sigchld only
         if it was non-zero before we called waitpid. */
       if (sigchld > 0 && (waitpid_flags & WNOHANG))
@@ -3203,7 +3227,7 @@ notify_of_job_status ()
             last CHILD_MAX background processes if the shell is running a
             script.  If the shell is not interactive, don't print anything
             unless the job was killed by a signal. */
-         if (startup_state == 0 && WIFSIGNALED (s) == 0 &&
+         if (startup_state == 0 && WIFSIGNALED (s) == 0 && job_control == 0 &&
                ((DEADJOB (job) && IS_FOREGROUND (job) == 0) || STOPPED (job)))
            continue;
          
@@ -3265,7 +3289,7 @@ notify_of_job_status ()
                      fprintf (stderr, "\n");
                    }
                }
-             else
+             else if (job_control)     /* XXX job control test added */
                {
                  if (dir == 0)
                    dir = current_working_directory ();
@@ -3646,12 +3670,14 @@ delete_all_jobs (running_only)
 
       /* XXX could use js.j_firstj here */
       for (i = 0; i < js.j_jobslots; i++)
-{
-if (i < js.j_firstj && jobs[i])
-  itrace("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
-       if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i))))
-         delete_job (i, 1);
-}
+       {
+#if defined (DEBUG)
+         if (i < js.j_firstj && jobs[i])
+           itrace("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#endif
+         if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i))))
+           delete_job (i, 1);
+       }
       if (running_only == 0)
        {
          free ((char *)jobs);
@@ -3698,12 +3724,14 @@ count_all_jobs ()
   BLOCK_CHILD (set, oset);
   /* XXX could use js.j_firstj here */
   for (i = n = 0; i < js.j_jobslots; i++)
-{
-if (i < js.j_firstj && jobs[i])
-  itrace("count_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
-    if (jobs[i] && DEADJOB(i) == 0)
-      n++;
-}
+    {
+#if defined (DEBUG)
+      if (i < js.j_firstj && jobs[i])
+       itrace("count_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#endif
+      if (jobs[i] && DEADJOB(i) == 0)
+       n++;
+    }
   UNBLOCK_CHILD (oset);
   return n;
 }
@@ -3770,8 +3798,10 @@ mark_dead_jobs_as_notified (force)
   /* XXX could use js.j_firstj here */
   for (i = ndead = ndeadproc = 0; i < js.j_jobslots; i++)
     {
-if (i < js.j_firstj && jobs[i])
-  itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#if defined (DEBUG)
+      if (i < js.j_firstj && jobs[i])
+       itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#endif
       if (jobs[i] && DEADJOB (i))
        {
          ndead++;
@@ -3819,8 +3849,10 @@ itrace("mark_dead_jobs_as_notified: child_max = %d ndead = %d ndeadproc = %d", j
     {
       if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i, 0) != last_asynchronous_pid)))
        {
-if (i < js.j_firstj && jobs[i])
-  itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#if defined (DEBUG)
+         if (i < js.j_firstj && jobs[i])
+           itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+#endif
          /* If marking this job as notified would drop us down below
             child_max, don't mark it so we can keep at least child_max
             statuses.  XXX -- need to check what Posix actually says
@@ -3868,6 +3900,9 @@ without_job_control ()
 {
   stop_making_children ();
   start_pipeline ();
+#if defined (PGRP_PIPE)
+  pipe_close (pgrp_pipe);
+#endif
   delete_all_jobs (0);
   set_job_control (0);
 }
index c775ae083281575ac44a22d88c6bfcaeb9d698e0..79f4668652b636c3d5cc5ff4cada0e505d5b895b 100644 (file)
@@ -22,6 +22,9 @@
 #endif
 
 #include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
 
 #include "imalloc.h"
 
index 2f61c264709f0f668c65624d6d128baa757ae687..eb7c0ed62511b6299b40c92a9fd1cfce4572c6a7 100644 (file)
@@ -694,7 +694,7 @@ print_filename (to_print, full_pathname)
      char *to_print, *full_pathname;
 {
   int printed_len, extension_char, slen, tlen;
-  char *s, c, *new_full_pathname;
+  char *s, c, *new_full_pathname, *dn;
 
   extension_char = 0;
   printed_len = fnprint (to_print);
@@ -719,7 +719,17 @@ print_filename (to_print, full_pathname)
             files in the root directory.  If we pass a null string to the
             bash directory completion hook, for example, it will expand it
             to the current directory.  We just want the `/'. */
-         s = tilde_expand (full_pathname && *full_pathname ? full_pathname : "/");
+         if (full_pathname == 0 || *full_pathname == 0)
+           dn = "/";
+         else if (full_pathname[0] != '/')
+           dn = full_pathname;
+         else if (full_pathname[1] == 0)
+           dn = "//";          /* restore trailing slash to `//' */
+         else if (full_pathname[1] == '/' && full_pathname[2] == 0)
+           dn = "/";           /* don't turn /// into // */
+         else
+           dn = full_pathname;
+         s = tilde_expand (dn);
          if (rl_directory_completion_hook)
            (*rl_directory_completion_hook) (&s);
 
@@ -727,6 +737,10 @@ print_filename (to_print, full_pathname)
          tlen = strlen (to_print);
          new_full_pathname = (char *)xmalloc (slen + tlen + 2);
          strcpy (new_full_pathname, s);
+         if (s[slen - 1] == '/')
+           slen--;
+         else
+           new_full_pathname[slen] = '/';
          new_full_pathname[slen] = '/';
          strcpy (new_full_pathname + slen + 1, to_print);
 
index 8eb5080bf2866a0583dbc5b2705bfda8715e53a5..0ec507ec27c5c9aaef808a361d521eec2d7a8031 100644 (file)
@@ -444,6 +444,10 @@ rl_getc (stream)
 
   while (1)
     {
+#if defined (__MINGW32__)
+      if (isatty (fileno (stream)))
+       return (getch ());
+#endif
       result = read (fileno (stream), &c, sizeof (unsigned char));
 
       if (result == sizeof (unsigned char))
diff --git a/lib/readline/input.c~ b/lib/readline/input.c~
new file mode 100644 (file)
index 0000000..8eb5080
--- /dev/null
@@ -0,0 +1,566 @@
+/* input.c -- character input functions for readline. */
+
+/* Copyright (C) 1994-2005 Free Software Foundation, Inc.
+
+   This file is part of the GNU Readline Library, a library for
+   reading lines of text with interactive input and history editing.
+
+   The GNU Readline 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 GNU Readline 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. */
+#define READLINE_LIBRARY
+
+#if defined (__TANDEM)
+#  include <floss.h>
+#endif
+
+#if defined (HAVE_CONFIG_H)
+#  include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+#if defined (HAVE_SYS_FILE_H)
+#  include <sys/file.h>
+#endif /* HAVE_SYS_FILE_H */
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+#  include <stdlib.h>
+#else
+#  include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#if defined (HAVE_SELECT)
+#  if !defined (HAVE_SYS_SELECT_H) || !defined (M_UNIX)
+#    include <sys/time.h>
+#  endif
+#endif /* HAVE_SELECT */
+#if defined (HAVE_SYS_SELECT_H)
+#  include <sys/select.h>
+#endif
+
+#if defined (FIONREAD_IN_SYS_IOCTL)
+#  include <sys/ioctl.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+#include "rlmbutil.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+
+#include "rlprivate.h"
+#include "rlshell.h"
+#include "xmalloc.h"
+
+/* What kind of non-blocking I/O do we have? */
+#if !defined (O_NDELAY) && defined (O_NONBLOCK)
+#  define O_NDELAY O_NONBLOCK  /* Posix style */
+#endif
+
+/* Non-null means it is a pointer to a function to run while waiting for
+   character input. */
+rl_hook_func_t *rl_event_hook = (rl_hook_func_t *)NULL;
+
+rl_getc_func_t *rl_getc_function = rl_getc;
+
+static int _keyboard_input_timeout = 100000;           /* 0.1 seconds; it's in usec */
+
+static int ibuffer_space PARAMS((void));
+static int rl_get_char PARAMS((int *));
+static int rl_gather_tyi PARAMS((void));
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Character Input Buffering                   */
+/*                                                                 */
+/* **************************************************************** */
+
+static int pop_index, push_index;
+static unsigned char ibuffer[512];
+static int ibuffer_len = sizeof (ibuffer) - 1;
+
+#define any_typein (push_index != pop_index)
+
+int
+_rl_any_typein ()
+{
+  return any_typein;
+}
+
+/* Return the amount of space available in the buffer for stuffing
+   characters. */
+static int
+ibuffer_space ()
+{
+  if (pop_index > push_index)
+    return (pop_index - push_index - 1);
+  else
+    return (ibuffer_len - (push_index - pop_index));
+}
+
+/* Get a key from the buffer of characters to be read.
+   Return the key in KEY.
+   Result is KEY if there was a key, or 0 if there wasn't. */
+static int
+rl_get_char (key)
+     int *key;
+{
+  if (push_index == pop_index)
+    return (0);
+
+  *key = ibuffer[pop_index++];
+
+  if (pop_index >= ibuffer_len)
+    pop_index = 0;
+
+  return (1);
+}
+
+/* Stuff KEY into the *front* of the input buffer.
+   Returns non-zero if successful, zero if there is
+   no space left in the buffer. */
+int
+_rl_unget_char (key)
+     int key;
+{
+  if (ibuffer_space ())
+    {
+      pop_index--;
+      if (pop_index < 0)
+       pop_index = ibuffer_len - 1;
+      ibuffer[pop_index] = key;
+      return (1);
+    }
+  return (0);
+}
+
+int
+_rl_pushed_input_available ()
+{
+  return (push_index != pop_index);
+}
+
+/* If a character is available to be read, then read it and stuff it into
+   IBUFFER.  Otherwise, just return.  Returns number of characters read
+   (0 if none available) and -1 on error (EIO). */
+static int
+rl_gather_tyi ()
+{
+  int tty;
+  register int tem, result;
+  int chars_avail, k;
+  char input;
+#if defined(HAVE_SELECT)
+  fd_set readfds, exceptfds;
+  struct timeval timeout;
+#endif
+
+  tty = fileno (rl_instream);
+
+#if defined (HAVE_SELECT)
+  FD_ZERO (&readfds);
+  FD_ZERO (&exceptfds);
+  FD_SET (tty, &readfds);
+  FD_SET (tty, &exceptfds);
+  timeout.tv_sec = 0;
+  timeout.tv_usec = _keyboard_input_timeout;
+  result = select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout);
+  if (result <= 0)
+    return 0;  /* Nothing to read. */
+#endif
+
+  result = -1;
+#if defined (FIONREAD)
+  errno = 0;
+  result = ioctl (tty, FIONREAD, &chars_avail);
+  if (result == -1 && errno == EIO)
+    return -1;
+#endif
+
+#if defined (O_NDELAY)
+  if (result == -1)
+    {
+      tem = fcntl (tty, F_GETFL, 0);
+
+      fcntl (tty, F_SETFL, (tem | O_NDELAY));
+      chars_avail = read (tty, &input, 1);
+
+      fcntl (tty, F_SETFL, tem);
+      if (chars_avail == -1 && errno == EAGAIN)
+       return 0;
+      if (chars_avail == 0)    /* EOF */
+       {
+         rl_stuff_char (EOF);
+         return (0);
+       }
+    }
+#endif /* O_NDELAY */
+
+  /* If there's nothing available, don't waste time trying to read
+     something. */
+  if (chars_avail <= 0)
+    return 0;
+
+  tem = ibuffer_space ();
+
+  if (chars_avail > tem)
+    chars_avail = tem;
+
+  /* One cannot read all of the available input.  I can only read a single
+     character at a time, or else programs which require input can be
+     thwarted.  If the buffer is larger than one character, I lose.
+     Damn! */
+  if (tem < ibuffer_len)
+    chars_avail = 0;
+
+  if (result != -1)
+    {
+      while (chars_avail--)
+       {
+         k = (*rl_getc_function) (rl_instream);
+         rl_stuff_char (k);
+         if (k == NEWLINE || k == RETURN)
+           break;
+       }
+    }
+  else
+    {
+      if (chars_avail)
+       rl_stuff_char (input);
+    }
+
+  return 1;
+}
+
+int
+rl_set_keyboard_input_timeout (u)
+     int u;
+{
+  int o;
+
+  o = _keyboard_input_timeout;
+  if (u > 0)
+    _keyboard_input_timeout = u;
+  return (o);
+}
+
+/* Is there input available to be read on the readline input file
+   descriptor?  Only works if the system has select(2) or FIONREAD.
+   Uses the value of _keyboard_input_timeout as the timeout; if another
+   readline function wants to specify a timeout and not leave it up to
+   the user, it should use _rl_input_queued(timeout_value_in_microseconds)
+   instead. */
+int
+_rl_input_available ()
+{
+#if defined(HAVE_SELECT)
+  fd_set readfds, exceptfds;
+  struct timeval timeout;
+#endif
+#if !defined (HAVE_SELECT) && defined(FIONREAD)
+  int chars_avail;
+#endif
+  int tty;
+
+  tty = fileno (rl_instream);
+
+#if defined (HAVE_SELECT)
+  FD_ZERO (&readfds);
+  FD_ZERO (&exceptfds);
+  FD_SET (tty, &readfds);
+  FD_SET (tty, &exceptfds);
+  timeout.tv_sec = 0;
+  timeout.tv_usec = _keyboard_input_timeout;
+  return (select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout) > 0);
+#else
+
+#if defined (FIONREAD)
+  if (ioctl (tty, FIONREAD, &chars_avail) == 0)
+    return (chars_avail);
+#endif
+
+#endif
+
+  return 0;
+}
+
+int
+_rl_input_queued (t)
+     int t;
+{
+  int old_timeout, r;
+
+  old_timeout = rl_set_keyboard_input_timeout (t);
+  r = _rl_input_available ();
+  rl_set_keyboard_input_timeout (old_timeout);
+  return r;
+}
+
+void
+_rl_insert_typein (c)
+     int c;     
+{      
+  int key, t, i;
+  char *string;
+
+  i = key = 0;
+  string = (char *)xmalloc (ibuffer_len + 1);
+  string[i++] = (char) c;
+
+  while ((t = rl_get_char (&key)) &&
+        _rl_keymap[key].type == ISFUNC &&
+        _rl_keymap[key].function == rl_insert)
+    string[i++] = key;
+
+  if (t)
+    _rl_unget_char (key);
+
+  string[i] = '\0';
+  rl_insert_text (string);
+  free (string);
+}
+
+/* Add KEY to the buffer of characters to be read.  Returns 1 if the
+   character was stuffed correctly; 0 otherwise. */
+int
+rl_stuff_char (key)
+     int key;
+{
+  if (ibuffer_space () == 0)
+    return 0;
+
+  if (key == EOF)
+    {
+      key = NEWLINE;
+      rl_pending_input = EOF;
+      RL_SETSTATE (RL_STATE_INPUTPENDING);
+    }
+  ibuffer[push_index++] = key;
+  if (push_index >= ibuffer_len)
+    push_index = 0;
+
+  return 1;
+}
+
+/* Make C be the next command to be executed. */
+int
+rl_execute_next (c)
+     int c;
+{
+  rl_pending_input = c;
+  RL_SETSTATE (RL_STATE_INPUTPENDING);
+  return 0;
+}
+
+/* Clear any pending input pushed with rl_execute_next() */
+int
+rl_clear_pending_input ()
+{
+  rl_pending_input = 0;
+  RL_UNSETSTATE (RL_STATE_INPUTPENDING);
+  return 0;
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                          Character Input                        */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Read a key, including pending input. */
+int
+rl_read_key ()
+{
+  int c;
+
+  rl_key_sequence_length++;
+
+  if (rl_pending_input)
+    {
+      c = rl_pending_input;
+      rl_clear_pending_input ();
+    }
+  else
+    {
+      /* If input is coming from a macro, then use that. */
+      if (c = _rl_next_macro_key ())
+       return (c);
+
+      /* If the user has an event function, then call it periodically. */
+      if (rl_event_hook)
+       {
+         while (rl_event_hook && rl_get_char (&c) == 0)
+           {
+             (*rl_event_hook) ();
+             if (rl_done)              /* XXX - experimental */
+               return ('\n');
+             if (rl_gather_tyi () < 0) /* XXX - EIO */
+               {
+                 rl_done = 1;
+                 return ('\n');
+               }
+           }
+       }
+      else
+       {
+         if (rl_get_char (&c) == 0)
+           c = (*rl_getc_function) (rl_instream);
+       }
+    }
+
+  return (c);
+}
+
+int
+rl_getc (stream)
+     FILE *stream;
+{
+  int result;
+  unsigned char c;
+
+  while (1)
+    {
+      result = read (fileno (stream), &c, sizeof (unsigned char));
+
+      if (result == sizeof (unsigned char))
+       return (c);
+
+      /* If zero characters are returned, then the file that we are
+        reading from is empty!  Return EOF in that case. */
+      if (result == 0)
+       return (EOF);
+
+#if defined (__BEOS__)
+      if (errno == EINTR)
+       continue;
+#endif
+
+#if defined (EWOULDBLOCK)
+#  define X_EWOULDBLOCK EWOULDBLOCK
+#else
+#  define X_EWOULDBLOCK -99
+#endif
+
+#if defined (EAGAIN)
+#  define X_EAGAIN EAGAIN
+#else
+#  define X_EAGAIN -99
+#endif
+
+      if (errno == X_EWOULDBLOCK || errno == X_EAGAIN)
+       {
+         if (sh_unset_nodelay_mode (fileno (stream)) < 0)
+           return (EOF);
+         continue;
+       }
+
+#undef X_EWOULDBLOCK
+#undef X_EAGAIN
+
+      /* If the error that we received was SIGINT, then try again,
+        this is simply an interrupted system call to read ().
+        Otherwise, some error ocurred, also signifying EOF. */
+      if (errno != EINTR)
+       return (EOF);
+    }
+}
+
+#if defined (HANDLE_MULTIBYTE)
+/* read multibyte char */
+int
+_rl_read_mbchar (mbchar, size)
+     char *mbchar;
+     int size;
+{
+  int mb_len = 0;
+  size_t mbchar_bytes_length;
+  wchar_t wc;
+  mbstate_t ps, ps_back;
+
+  memset(&ps, 0, sizeof (mbstate_t));
+  memset(&ps_back, 0, sizeof (mbstate_t));
+  
+  while (mb_len < size)
+    {
+      RL_SETSTATE(RL_STATE_MOREINPUT);
+      mbchar[mb_len++] = rl_read_key ();
+      RL_UNSETSTATE(RL_STATE_MOREINPUT);
+
+      mbchar_bytes_length = mbrtowc (&wc, mbchar, mb_len, &ps);
+      if (mbchar_bytes_length == (size_t)(-1))
+       break;          /* invalid byte sequence for the current locale */
+      else if (mbchar_bytes_length == (size_t)(-2))
+       {
+         /* shorted bytes */
+         ps = ps_back;
+         continue;
+       } 
+      else if (mbchar_bytes_length == 0)
+       {
+         mbchar[0] = '\0';     /* null wide character */
+         mb_len = 1;
+         break;
+       }
+      else if (mbchar_bytes_length > (size_t)(0))
+       break;
+    }
+
+  return mb_len;
+}
+
+/* Read a multibyte-character string whose first character is FIRST into
+   the buffer MB of length MBLEN.  Returns the last character read, which
+   may be FIRST.  Used by the search functions, among others.  Very similar
+   to _rl_read_mbchar. */
+int
+_rl_read_mbstring (first, mb, mblen)
+     int first;
+     char *mb;
+     int mblen;
+{
+  int i, c;
+  mbstate_t ps;
+
+  c = first;
+  memset (mb, 0, mblen);
+  for (i = 0; i < mblen; i++)
+    {
+      mb[i] = (char)c;
+      memset (&ps, 0, sizeof (mbstate_t));
+      if (_rl_get_char_len (mb, &ps) == -2)
+       {
+         /* Read more for multibyte character */
+         RL_SETSTATE (RL_STATE_MOREINPUT);
+         c = rl_read_key ();
+         RL_UNSETSTATE (RL_STATE_MOREINPUT);
+       }
+      else
+       break;
+    }
+  return c;
+}
+#endif /* HANDLE_MULTIBYTE */
index aafad068ec704c5d5fde2271207046777f6812dc..5e9767ab47f9fbbf7e25a56d82c757f6aeacc304 100644 (file)
@@ -1095,6 +1095,13 @@ bind_arrow_keys_internal (map)
   rl_bind_keyseq_if_unbound ("\033OH", rl_beg_of_line);
   rl_bind_keyseq_if_unbound ("\033OF", rl_end_of_line);
 
+#if defined (__MINGW32__)
+  rl_bind_keyseq_if_unbound ("\340H", rl_get_previous_history);
+  rl_bind_keyseq_if_unbound ("\340P", rl_get_next_history);
+  rl_bind_keyseq_if_unbound ("\340M", rl_forward_char);
+  rl_bind_keyseq_if_unbound ("\340K", rl_backward_char);
+#endif
+
   _rl_keymap = xkeymap;
 }
 
index c3a352a0ecbee1637a42617b2051b3c99c058fa3..aafad068ec704c5d5fde2271207046777f6812dc 100644 (file)
 #include "xmalloc.h"
 
 #ifndef RL_LIBRARY_VERSION
-#  define RL_LIBRARY_VERSION "5.0"
+#  define RL_LIBRARY_VERSION "5.1"
 #endif
 
 #ifndef RL_READLINE_VERSION
-#  define RL_READLINE_VERSION  0x0500
+#  define RL_READLINE_VERSION  0x0501
 #endif
 
 extern void _rl_free_history_entry PARAMS((HIST_ENTRY *));
@@ -87,6 +87,9 @@ static void bind_arrow_keys PARAMS((void));
 static void readline_default_bindings PARAMS((void));
 static void reset_default_bindings PARAMS((void));
 
+static int _rl_subseq_result PARAMS((int, Keymap, int, int));
+static int _rl_subseq_getchar PARAMS((int));
+
 /* **************************************************************** */
 /*                                                                 */
 /*                     Line editing input utility                  */
@@ -104,6 +107,7 @@ int rl_gnu_readline_p = 1;
    By default, it is the standard emacs keymap. */
 Keymap _rl_keymap = emacs_standard_keymap;
 
+
 /* The current style of editing. */
 int rl_editing_mode = emacs_mode;
 
@@ -219,6 +223,9 @@ char *_rl_comment_begin;
 /* Keymap holding the function currently being executed. */
 Keymap rl_executing_keymap;
 
+/* Keymap we're currently using to dispatch. */
+Keymap _rl_dispatching_keymap;
+
 /* Non-zero means to erase entire line, including prompt, on empty input lines. */
 int rl_erase_empty_line = 0;
 
@@ -230,6 +237,9 @@ int rl_num_chars_to_read;
 char *rl_line_buffer = (char *)NULL;
 int rl_line_buffer_len = 0;
 
+/* Key sequence `contexts' */
+_rl_keyseq_cxt *_rl_kscxt = 0;
+
 /* Forward declarations used by the display, termcap, and history code. */
 
 /* **************************************************************** */
@@ -295,14 +305,16 @@ readline (prompt)
   rl_set_prompt (prompt);
 
   rl_initialize ();
-  (*rl_prep_term_function) (_rl_meta_flag);
+  if (rl_prep_term_function)
+    (*rl_prep_term_function) (_rl_meta_flag);
 
 #if defined (HANDLE_SIGNALS)
   rl_set_signals ();
 #endif
 
   value = readline_internal ();
-  (*rl_deprep_term_function) ();
+  if (rl_deprep_term_function)
+    (*rl_deprep_term_function) ();
 
 #if defined (HANDLE_SIGNALS)
   rl_clear_signals ();
@@ -392,6 +404,36 @@ readline_internal_teardown (eof)
   return (eof ? (char *)NULL : savestring (the_line));
 }
 
+void
+_rl_internal_char_cleanup ()
+{
+#if defined (VI_MODE)
+  /* In vi mode, when you exit insert mode, the cursor moves back
+     over the previous character.  We explicitly check for that here. */
+  if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap)
+    rl_vi_check ();
+#endif /* VI_MODE */
+
+  if (rl_num_chars_to_read && rl_end >= rl_num_chars_to_read)
+    {
+      (*rl_redisplay_function) ();
+      _rl_want_redisplay = 0;
+      rl_newline (1, '\n');
+    }
+
+  if (rl_done == 0)
+    {
+      (*rl_redisplay_function) ();
+      _rl_want_redisplay = 0;
+    }
+
+  /* If the application writer has told us to erase the entire line if
+     the only character typed was something bound to rl_newline, do so. */
+  if (rl_erase_empty_line && rl_done && rl_last_func == rl_newline &&
+      rl_point == 0 && rl_end == 0)
+    _rl_erase_entire_line ();
+}
+
 STATIC_CALLBACK int
 #if defined (READLINE_CALLBACKS)
 readline_internal_char ()
@@ -414,12 +456,21 @@ readline_internal_charloop ()
       code = setjmp (readline_top_level);
 
       if (code)
-       (*rl_redisplay_function) ();
+       {
+         (*rl_redisplay_function) ();
+         _rl_want_redisplay = 0;
+         /* If we get here, we're not being called from something dispatched
+            from _rl_callback_read_char(), which sets up its own value of
+            readline_top_level (saving and restoring the old, of course), so
+            we can just return here. */
+         if (RL_ISSTATE (RL_STATE_CALLBACK))
+           return (0);
+       }
 
       if (rl_pending_input == 0)
        {
          /* Then initialize the argument and number of keys read. */
-         _rl_init_argument ();
+         _rl_reset_argument ();
          rl_key_sequence_length = 0;
        }
 
@@ -453,27 +504,7 @@ readline_internal_charloop ()
       if (rl_pending_input == 0 && lk == _rl_last_command_was_kill)
        _rl_last_command_was_kill = 0;
 
-#if defined (VI_MODE)
-      /* In vi mode, when you exit insert mode, the cursor moves back
-        over the previous character.  We explicitly check for that here. */
-      if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap)
-       rl_vi_check ();
-#endif /* VI_MODE */
-
-      if (rl_num_chars_to_read && rl_end >= rl_num_chars_to_read)
-        {
-          (*rl_redisplay_function) ();
-          rl_newline (1, '\n');
-        }
-
-      if (rl_done == 0)
-       (*rl_redisplay_function) ();
-
-      /* If the application writer has told us to erase the entire line if
-         the only character typed was something bound to rl_newline, do so. */
-      if (rl_erase_empty_line && rl_done && rl_last_func == rl_newline &&
-         rl_point == 0 && rl_end == 0)
-       _rl_erase_entire_line ();
+      _rl_internal_char_cleanup ();
 
 #if defined (READLINE_CALLBACKS)
       return 0;
@@ -523,6 +554,107 @@ _rl_set_the_line ()
   the_line = rl_line_buffer;
 }
 
+#if defined (READLINE_CALLBACKS)
+_rl_keyseq_cxt *
+_rl_keyseq_cxt_alloc ()
+{
+  _rl_keyseq_cxt *cxt;
+
+  cxt = (_rl_keyseq_cxt *)xmalloc (sizeof (_rl_keyseq_cxt));
+
+  cxt->flags = cxt->subseq_arg = cxt->subseq_retval = 0;
+
+  cxt->okey = 0;
+  cxt->ocxt = _rl_kscxt;
+  cxt->childval = 42;          /* sentinel value */
+
+  return cxt;
+}
+
+void
+_rl_keyseq_cxt_dispose (cxt)
+    _rl_keyseq_cxt *cxt;
+{
+  free (cxt);
+}
+
+void
+_rl_keyseq_chain_dispose ()
+{
+  _rl_keyseq_cxt *cxt;
+
+  while (_rl_kscxt)
+    {
+      cxt = _rl_kscxt;
+      _rl_kscxt = _rl_kscxt->ocxt;
+      _rl_keyseq_cxt_dispose (cxt);
+    }
+}
+#endif
+
+static int
+_rl_subseq_getchar (key)
+     int key;
+{
+  int k;
+
+  if (key == ESC)
+    RL_SETSTATE(RL_STATE_METANEXT);
+  RL_SETSTATE(RL_STATE_MOREINPUT);
+  k = rl_read_key ();
+  RL_UNSETSTATE(RL_STATE_MOREINPUT);
+  if (key == ESC)
+    RL_UNSETSTATE(RL_STATE_METANEXT);
+
+  return k;
+}
+
+#if defined (READLINE_CALLBACKS)
+int
+_rl_dispatch_callback (cxt)
+     _rl_keyseq_cxt *cxt;
+{
+  int nkey, r;
+
+  /* For now */
+#if 1
+  /* The first time this context is used, we want to read input and dispatch
+     on it.  When traversing the chain of contexts back `up', we want to use
+     the value from the next context down.  We're simulating recursion using
+     a chain of contexts. */
+  if ((cxt->flags & KSEQ_DISPATCHED) == 0)
+    {
+      nkey = _rl_subseq_getchar (cxt->okey);
+      r = _rl_dispatch_subseq (nkey, cxt->dmap, cxt->subseq_arg);
+      cxt->flags |= KSEQ_DISPATCHED;
+    }
+  else
+    r = cxt->childval;
+#else
+  r = _rl_dispatch_subseq (nkey, cxt->dmap, cxt->subseq_arg);
+#endif
+
+  /* For now */
+  r = _rl_subseq_result (r, cxt->oldmap, cxt->okey, (cxt->flags & KSEQ_SUBSEQ));
+
+  if (r == 0)                  /* success! */
+    {
+      _rl_keyseq_chain_dispose ();
+      RL_UNSETSTATE (RL_STATE_MULTIKEY);
+      return r;
+    }
+
+  if (r != -3)                 /* magic value that says we added to the chain */
+    _rl_kscxt = cxt->ocxt;
+  if (_rl_kscxt)
+    _rl_kscxt->childval = r;
+  if (r != -3)
+    _rl_keyseq_cxt_dispose (cxt);
+
+  return r;
+}
+#endif /* READLINE_CALLBACKS */
+  
 /* Do the command associated with KEY in MAP.
    If the associated command is really a keymap, then read
    another key, and dispatch into that map. */
@@ -531,6 +663,7 @@ _rl_dispatch (key, map)
      register int key;
      Keymap map;
 {
+  _rl_dispatching_keymap = map;
   return _rl_dispatch_subseq (key, map, 0);
 }
 
@@ -543,6 +676,9 @@ _rl_dispatch_subseq (key, map, got_subseq)
   int r, newkey;
   char *macro;
   rl_command_func_t *func;
+#if defined (READLINE_CALLBACKS)
+  _rl_keyseq_cxt *cxt;
+#endif
 
   if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii)
     {
@@ -576,10 +712,6 @@ _rl_dispatch_subseq (key, map, got_subseq)
 
          rl_executing_keymap = map;
 
-#if 0
-         _rl_suppress_redisplay = (map[key].function == rl_insert) && _rl_input_available ();
-#endif
-
          rl_dispatching = 1;
          RL_SETSTATE(RL_STATE_DISPATCHING);
          r = (*map[key].function)(rl_numeric_arg * rl_arg_sign, key);
@@ -611,6 +743,10 @@ _rl_dispatch_subseq (key, map, got_subseq)
        }
       else
        {
+#if defined (READLINE_CALLBACKS)
+         RL_UNSETSTATE (RL_STATE_MULTIKEY);
+         _rl_keyseq_chain_dispose ();
+#endif
          _rl_abort_internal ();
          return -1;
        }
@@ -632,66 +768,43 @@ _rl_dispatch_subseq (key, map, got_subseq)
 #endif
 
          rl_key_sequence_length++;
+         _rl_dispatching_keymap = FUNCTION_TO_KEYMAP (map, key);
 
-         if (key == ESC)
-           RL_SETSTATE(RL_STATE_METANEXT);
-         RL_SETSTATE(RL_STATE_MOREINPUT);
-         newkey = rl_read_key ();
-         RL_UNSETSTATE(RL_STATE_MOREINPUT);
-         if (key == ESC)
-           RL_UNSETSTATE(RL_STATE_METANEXT);
+         /* Allocate new context here.  Use linked contexts (linked through
+            cxt->ocxt) to simulate recursion */
+#if defined (READLINE_CALLBACKS)
+         if (RL_ISSTATE (RL_STATE_CALLBACK))
+           {
+             /* Return 0 only the first time, to indicate success to
+                _rl_callback_read_char.  The rest of the time, we're called
+                from _rl_dispatch_callback, so we return 3 to indicate
+                special handling is necessary. */
+             r = RL_ISSTATE (RL_STATE_MULTIKEY) ? -3 : 0;
+             cxt = _rl_keyseq_cxt_alloc ();
+
+             if (got_subseq)
+               cxt->flags |= KSEQ_SUBSEQ;
+             cxt->okey = key;
+             cxt->oldmap = map;
+             cxt->dmap = _rl_dispatching_keymap;
+             cxt->subseq_arg = got_subseq || cxt->dmap[ANYOTHERKEY].function;
+
+             RL_SETSTATE (RL_STATE_MULTIKEY);
+             _rl_kscxt = cxt;
+
+             return r;         /* don't indicate immediate success */
+           }
+#endif
 
+         newkey = _rl_subseq_getchar (key);
          if (newkey < 0)
            {
              _rl_abort_internal ();
              return -1;
            }
 
-         r = _rl_dispatch_subseq (newkey, FUNCTION_TO_KEYMAP (map, key), got_subseq || map[ANYOTHERKEY].function);
-
-         if (r == -2)
-           /* We didn't match anything, and the keymap we're indexed into
-              shadowed a function previously bound to that prefix.  Call
-              the function.  The recursive call to _rl_dispatch_subseq has
-              already taken care of pushing any necessary input back onto
-              the input queue with _rl_unget_char. */
-           {
-             Keymap m = FUNCTION_TO_KEYMAP (map, key);
-             int type = m[ANYOTHERKEY].type;
-             func = m[ANYOTHERKEY].function;
-             if (type == ISFUNC && func == rl_do_lowercase_version)
-               r = _rl_dispatch (_rl_to_lower (key), map);
-             else if (type == ISFUNC && func == rl_insert)
-               {
-                 /* If the function that was shadowed was self-insert, we
-                    somehow need a keymap with map[key].func == self-insert.
-                    Let's use this one. */
-                 int nt = m[key].type;
-                 rl_command_func_t *nf = m[key].function;
-
-                 m[key].type = type;
-                 m[key].function = func;
-                 r = _rl_dispatch (key, m);
-                 m[key].type = nt;
-                 m[key].function = nf;
-               }
-             else
-               r = _rl_dispatch (ANYOTHERKEY, m);
-           }
-         else if (r && map[ANYOTHERKEY].function)
-           {
-             /* We didn't match (r is probably -1), so return something to
-                tell the caller that it should try ANYOTHERKEY for an
-                overridden function. */
-             _rl_unget_char (key);
-             return -2;
-           }
-         else if (r && got_subseq)
-           {
-             /* OK, back up the chain. */
-             _rl_unget_char (key);
-             return -1;
-           }
+         r = _rl_dispatch_subseq (newkey, _rl_dispatching_keymap, got_subseq || map[ANYOTHERKEY].function);
+         return _rl_subseq_result (r, map, key, got_subseq);
        }
       else
        {
@@ -715,9 +828,69 @@ _rl_dispatch_subseq (key, map, got_subseq)
       _rl_vi_textmod_command (key))
     _rl_vi_set_last (key, rl_numeric_arg, rl_arg_sign);
 #endif
+
   return (r);
 }
 
+static int
+_rl_subseq_result (r, map, key, got_subseq)
+     int r;
+     Keymap map;
+     int key, got_subseq;
+{
+  Keymap m;
+  int type, nt;
+  rl_command_func_t *func, *nf;
+  
+  if (r == -2)
+    /* We didn't match anything, and the keymap we're indexed into
+       shadowed a function previously bound to that prefix.  Call
+       the function.  The recursive call to _rl_dispatch_subseq has
+       already taken care of pushing any necessary input back onto
+       the input queue with _rl_unget_char. */
+    {
+      m = _rl_dispatching_keymap;
+      type = m[ANYOTHERKEY].type;
+      func = m[ANYOTHERKEY].function;
+      if (type == ISFUNC && func == rl_do_lowercase_version)
+       r = _rl_dispatch (_rl_to_lower (key), map);
+      else if (type == ISFUNC && func == rl_insert)
+       {
+         /* If the function that was shadowed was self-insert, we
+            somehow need a keymap with map[key].func == self-insert.
+            Let's use this one. */
+         nt = m[key].type;
+         nf = m[key].function;
+
+         m[key].type = type;
+         m[key].function = func;
+         r = _rl_dispatch (key, m);
+         m[key].type = nt;
+         m[key].function = nf;
+       }
+      else
+       r = _rl_dispatch (ANYOTHERKEY, m);
+    }
+  else if (r && map[ANYOTHERKEY].function)
+    {
+      /* We didn't match (r is probably -1), so return something to
+        tell the caller that it should try ANYOTHERKEY for an
+        overridden function. */
+      _rl_unget_char (key);
+      _rl_dispatching_keymap = map;
+      return -2;
+    }
+  else if (r && got_subseq)
+    {
+      /* OK, back up the chain. */
+      _rl_unget_char (key);
+      _rl_dispatching_keymap = map;
+      return -1;
+    }
+
+  return r;
+}
+
 /* **************************************************************** */
 /*                                                                 */
 /*                     Initializations                             */
index 0d600407b5f0326201bf5b0cbb395fc8b1bf92e8..0f6c87446ddd141f31cace5471dbdb063e8315bd 100644 (file)
@@ -2,7 +2,7 @@
    for readline.  This should be included after any files that define
    system-specific constants like _POSIX_VERSION or USG. */
 
-/* Copyright (C) 1987,1989 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
 
    This file contains the Readline Library (the Library), a set of
    routines for providing Emacs style line input to programs that ask
 #  if defined (HAVE_TERMIO_H)
 #    define TERMIO_TTY_DRIVER
 #  else
-#    define NEW_TTY_DRIVER
+#    if !defined (__MINGW32__)
+#      define NEW_TTY_DRIVER
+#    else
+#      define NO_TTY_DRIVER
+#    endif
 #  endif
 #endif
 
diff --git a/lib/readline/rldefs.h~ b/lib/readline/rldefs.h~
new file mode 100644 (file)
index 0000000..085d82d
--- /dev/null
@@ -0,0 +1,160 @@
+/* rldefs.h -- an attempt to isolate some of the system-specific defines
+   for readline.  This should be included after any files that define
+   system-specific constants like _POSIX_VERSION or USG. */
+
+/* Copyright (C) 1987,1989 Free Software Foundation, Inc.
+
+   This file contains the Readline Library (the Library), a set of
+   routines for providing Emacs style line input to programs that ask
+   for it.
+
+   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. */
+
+#if !defined (_RLDEFS_H_)
+#define _RLDEFS_H_
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "rlstdc.h"
+
+#if defined (_POSIX_VERSION) && !defined (TERMIOS_MISSING)
+#  define TERMIOS_TTY_DRIVER
+#else
+#  if defined (HAVE_TERMIO_H)
+#    define TERMIO_TTY_DRIVER
+#  else
+#    if !defined (__MINGW32__)
+#      define NEW_TTY_DRIVER
+#    else
+#      define NO_TTY_DRIVER
+#    endif
+#  endif
+#endif
+
+/* Posix macro to check file in statbuf for directory-ness.
+   This requires that <sys/stat.h> be included before this test. */
+#if defined (S_IFDIR) && !defined (S_ISDIR)
+#  define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
+#endif
+
+/* Decide which flavor of the header file describing the C library
+   string functions to include and include it. */
+
+#if defined (HAVE_STRING_H)
+#  include <string.h>
+#else /* !HAVE_STRING_H */
+#  include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#if !defined (strchr) && !defined (__STDC__)
+extern char *strchr (), *strrchr ();
+#endif /* !strchr && !__STDC__ */
+
+#if defined (PREFER_STDARG)
+#  include <stdarg.h>
+#else
+#  if defined (PREFER_VARARGS)
+#    include <varargs.h>
+#  endif
+#endif
+
+#if defined (HAVE_STRCASECMP)
+#define _rl_stricmp strcasecmp
+#define _rl_strnicmp strncasecmp
+#else
+extern int _rl_stricmp PARAMS((char *, char *));
+extern int _rl_strnicmp PARAMS((char *, char *, int));
+#endif
+
+#if defined (HAVE_STRPBRK) && !defined (HAVE_MULTIBYTE)
+#  define _rl_strpbrk(a,b)     strpbrk((a),(b))
+#else
+extern char *_rl_strpbrk PARAMS((const char *, const char *));
+#endif
+
+#if !defined (emacs_mode)
+#  define no_mode -1
+#  define vi_mode 0
+#  define emacs_mode 1
+#endif
+
+#if !defined (RL_IM_INSERT)
+#  define RL_IM_INSERT         1
+#  define RL_IM_OVERWRITE      0
+#
+#  define RL_IM_DEFAULT                RL_IM_INSERT
+#endif
+
+/* If you cast map[key].function to type (Keymap) on a Cray,
+   the compiler takes the value of map[key].function and
+   divides it by 4 to convert between pointer types (pointers
+   to functions and pointers to structs are different sizes).
+   This is not what is wanted. */
+#if defined (CRAY)
+#  define FUNCTION_TO_KEYMAP(map, key) (Keymap)((int)map[key].function)
+#  define KEYMAP_TO_FUNCTION(data)     (rl_command_func_t *)((int)(data))
+#else
+#  define FUNCTION_TO_KEYMAP(map, key) (Keymap)(map[key].function)
+#  define KEYMAP_TO_FUNCTION(data)     (rl_command_func_t *)(data)
+#endif
+
+#ifndef savestring
+#define savestring(x) strcpy ((char *)xmalloc (1 + strlen (x)), (x))
+#endif
+
+/* Possible values for _rl_bell_preference. */
+#define NO_BELL 0
+#define AUDIBLE_BELL 1
+#define VISIBLE_BELL 2
+
+/* Definitions used when searching the line for characters. */
+/* NOTE: it is necessary that opposite directions are inverses */
+#define        FTO      1              /* forward to */
+#define BTO    -1              /* backward to */
+#define FFIND   2              /* forward find */
+#define BFIND  -2              /* backward find */
+
+/* Possible values for the found_quote flags word used by the completion
+   functions.  It says what kind of (shell-like) quoting we found anywhere
+   in the line. */
+#define RL_QF_SINGLE_QUOTE     0x01
+#define RL_QF_DOUBLE_QUOTE     0x02
+#define RL_QF_BACKSLASH                0x04
+#define RL_QF_OTHER_QUOTE      0x08
+
+/* Default readline line buffer length. */
+#define DEFAULT_BUFFER_SIZE 256
+
+#if !defined (STREQ)
+#define STREQ(a, b)    (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0))
+#define STREQN(a, b, n)        (((n) == 0) ? (1) \
+                                   : ((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0))
+#endif
+
+#if !defined (FREE)
+#  define FREE(x)      if (x) free (x)
+#endif
+
+#if !defined (SWAP)
+#  define SWAP(s, e)  do { int t; t = s; s = e; e = t; } while (0)
+#endif
+
+/* CONFIGURATION SECTION */
+#include "rlconf.h"
+
+#endif /* !_RLDEFS_H_ */
index 8b89a8a5b14a05e728b6569bc87204f00e111547..e618594f5caa41e91ee9a58fd4477126e7ae5aa4 100644 (file)
@@ -1,7 +1,7 @@
 /* rltty.c -- functions to prepare and restore the terminal for readline's
    use. */
 
-/* Copyright (C) 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1992-2005 Free Software Foundation, Inc.
 
    This file is part of the GNU Readline Library, a library for
    reading lines of text with interactive input and history editing.
@@ -152,7 +152,9 @@ set_winsize (tty)
 #endif /* TIOCGWINSZ */
 }
 
-#if defined (NEW_TTY_DRIVER)
+#if defined (NO_TTY_DRIVER)
+/* Nothing */
+#elif defined (NEW_TTY_DRIVER)
 
 /* Values for the `flags' field of a struct bsdtty.  This tells which
    elements of the struct bsdtty have been fetched from the system and
@@ -633,9 +635,23 @@ prepare_terminal_settings (meta_flag, oldtio, tiop)
 
 #endif /* TERMIOS_TTY_DRIVER && _POSIX_VDISABLE */
 }
-#endif  /* NEW_TTY_DRIVER */
+#endif  /* !NEW_TTY_DRIVER */
 
 /* Put the terminal in CBREAK mode so that we can detect key presses. */
+#if defined (NO_TTY_DRIVER)
+void
+rl_prep_terminal (meta_flag)
+     int meta_flag;
+{
+  readline_echoing_p = 1;
+}
+
+void
+rl_deprep_terminal ()
+{
+}
+
+#else /* ! NO_TTY_DRIVER */
 void
 rl_prep_terminal (meta_flag)
      int meta_flag;
@@ -721,6 +737,7 @@ rl_deprep_terminal ()
 
   release_sigint ();
 }
+#endif /* !NO_TTY_DRIVER */
 \f
 /* **************************************************************** */
 /*                                                                 */
@@ -732,6 +749,10 @@ int
 rl_restart_output (count, key)
      int count, key;
 {
+#if defined (__MINGW32__)
+  return 0;
+#else /* !__MING32__ */
+
   int fildes = fileno (rl_outstream);
 #if defined (TIOCSTART)
 #if defined (apollo)
@@ -759,12 +780,17 @@ rl_restart_output (count, key)
 #endif /* !TIOCSTART */
 
   return 0;
+#endif /* !__MINGW32__ */
 }
 
 int
 rl_stop_output (count, key)
      int count, key;
 {
+#if defined (__MINGW32__)
+  return 0;
+#else
+
   int fildes = fileno (rl_instream);
 
 #if defined (TIOCSTOP)
@@ -787,6 +813,7 @@ rl_stop_output (count, key)
 #endif /* !TIOCSTOP */
 
   return 0;
+#endif /* !__MINGW32__ */
 }
 
 /* **************************************************************** */
@@ -795,9 +822,16 @@ rl_stop_output (count, key)
 /*                                                                 */
 /* **************************************************************** */
 
+#if !defined (NO_TTY_DRIVER)
 #define SET_SPECIAL(sc, func)  set_special_char(kmap, &ttybuff, sc, func)
+#endif
+
+#if defined (NO_TTY_DRIVER)
 
-#if defined (NEW_TTY_DRIVER)
+#define SET_SPECIAL(sc, func)
+#define RESET_SPECIAL(c)
+
+#elif defined (NEW_TTY_DRIVER)
 static void
 set_special_char (kmap, tiop, sc, func)
      Keymap kmap;
@@ -878,6 +912,7 @@ void
 rltty_set_default_bindings (kmap)
      Keymap kmap;
 {
+#if !defined (NO_TTY_DRIVER)
   TIOTYPE ttybuff;
   int tty;
   static int called = 0;
@@ -886,6 +921,7 @@ rltty_set_default_bindings (kmap)
 
   if (get_tty_settings (tty, &ttybuff) == 0)
     _rl_bind_tty_special_chars (kmap, ttybuff);
+#endif
 }
 
 /* New public way to set the system default editing chars to their readline
@@ -923,7 +959,7 @@ rl_tty_unset_default_bindings (kmap)
 
 #if defined (HANDLE_SIGNALS)
 
-#if defined (NEW_TTY_DRIVER)
+#if defined (NEW_TTY_DRIVER) || defined (NO_TTY_DRIVER)
 int
 _rl_disable_tty_signals ()
 {
diff --git a/lib/readline/rltty.c.save1 b/lib/readline/rltty.c.save1
new file mode 100644 (file)
index 0000000..9394cfc
--- /dev/null
@@ -0,0 +1,989 @@
+/* rltty.c -- functions to prepare and restore the terminal for readline's
+   use. */
+
+/* Copyright (C) 1992 Free Software Foundation, Inc.
+
+   This file is part of the GNU Readline Library, a library for
+   reading lines of text with interactive input and history editing.
+
+   The GNU Readline 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 GNU Readline 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. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+#  include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include "rldefs.h"
+
+#if defined (GWINSZ_IN_SYS_IOCTL)
+#  include <sys/ioctl.h>
+#endif /* GWINSZ_IN_SYS_IOCTL */
+
+#include "rltty.h"
+#include "readline.h"
+#include "rlprivate.h"
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+rl_vintfunc_t *rl_prep_term_function = rl_prep_terminal;
+rl_voidfunc_t *rl_deprep_term_function = rl_deprep_terminal;
+
+static void block_sigint PARAMS((void));
+static void release_sigint PARAMS((void));
+
+static void set_winsize PARAMS((int));
+
+/* **************************************************************** */
+/*                                                                 */
+/*                        Signal Management                        */
+/*                                                                 */
+/* **************************************************************** */
+
+#if defined (HAVE_POSIX_SIGNALS)
+static sigset_t sigint_set, sigint_oset;
+#else /* !HAVE_POSIX_SIGNALS */
+#  if defined (HAVE_BSD_SIGNALS)
+static int sigint_oldmask;
+#  endif /* HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+static int sigint_blocked;
+
+/* Cause SIGINT to not be delivered until the corresponding call to
+   release_sigint(). */
+static void
+block_sigint ()
+{
+  if (sigint_blocked)
+    return;
+
+#if defined (HAVE_POSIX_SIGNALS)
+  sigemptyset (&sigint_set);
+  sigemptyset (&sigint_oset);
+  sigaddset (&sigint_set, SIGINT);
+  sigprocmask (SIG_BLOCK, &sigint_set, &sigint_oset);
+#else /* !HAVE_POSIX_SIGNALS */
+#  if defined (HAVE_BSD_SIGNALS)
+  sigint_oldmask = sigblock (sigmask (SIGINT));
+#  else /* !HAVE_BSD_SIGNALS */
+#    if defined (HAVE_USG_SIGHOLD)
+  sighold (SIGINT);
+#    endif /* HAVE_USG_SIGHOLD */
+#  endif /* !HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+  sigint_blocked = 1;
+}
+
+/* Allow SIGINT to be delivered. */
+static void
+release_sigint ()
+{
+  if (sigint_blocked == 0)
+    return;
+
+#if defined (HAVE_POSIX_SIGNALS)
+  sigprocmask (SIG_SETMASK, &sigint_oset, (sigset_t *)NULL);
+#else
+#  if defined (HAVE_BSD_SIGNALS)
+  sigsetmask (sigint_oldmask);
+#  else /* !HAVE_BSD_SIGNALS */
+#    if defined (HAVE_USG_SIGHOLD)
+  sigrelse (SIGINT);
+#    endif /* HAVE_USG_SIGHOLD */
+#  endif /* !HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+  sigint_blocked = 0;
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                   Saving and Restoring the TTY                  */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Non-zero means that the terminal is in a prepped state. */
+static int terminal_prepped;
+
+static _RL_TTY_CHARS _rl_tty_chars, _rl_last_tty_chars;
+
+/* If non-zero, means that this process has called tcflow(fd, TCOOFF)
+   and output is suspended. */
+#if defined (__ksr1__)
+static int ksrflow;
+#endif
+
+/* Dummy call to force a backgrounded readline to stop before it tries
+   to get the tty settings. */
+static void
+set_winsize (tty)
+     int tty;
+{
+#if defined (TIOCGWINSZ)
+  struct winsize w;
+
+  if (ioctl (tty, TIOCGWINSZ, &w) == 0)
+      (void) ioctl (tty, TIOCSWINSZ, &w);
+#endif /* TIOCGWINSZ */
+}
+
+#if defined (NEW_TTY_DRIVER)
+
+/* Values for the `flags' field of a struct bsdtty.  This tells which
+   elements of the struct bsdtty have been fetched from the system and
+   are valid. */
+#define SGTTY_SET      0x01
+#define LFLAG_SET      0x02
+#define TCHARS_SET     0x04
+#define LTCHARS_SET    0x08
+
+struct bsdtty {
+  struct sgttyb sgttyb;        /* Basic BSD tty driver information. */
+  int lflag;           /* Local mode flags, like LPASS8. */
+#if defined (TIOCGETC)
+  struct tchars tchars;        /* Terminal special characters, including ^S and ^Q. */
+#endif
+#if defined (TIOCGLTC)
+  struct ltchars ltchars; /* 4.2 BSD editing characters */
+#endif
+  int flags;           /* Bitmap saying which parts of the struct are valid. */
+};
+
+#define TIOTYPE struct bsdtty
+
+static TIOTYPE otio;
+
+static void save_tty_chars PARAMS((TIOTYPE *));
+static int _get_tty_settings PARAMS((int, TIOTYPE *));
+static int get_tty_settings PARAMS((int, TIOTYPE *));
+static int _set_tty_settings PARAMS((int, TIOTYPE *));
+static int set_tty_settings PARAMS((int, TIOTYPE *));
+
+static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *));
+
+static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t));
+
+static void
+save_tty_chars (tiop)
+     TIOTYPE *tiop;
+{
+  _rl_last_tty_chars = _rl_tty_chars;
+
+  if (tiop->flags & SGTTY_SET)
+    {
+      _rl_tty_chars.t_erase = tiop->sgttyb.sg_erase;
+      _rl_tty_chars.t_kill = tiop->sgttyb.sg_kill;
+    }
+
+  if (tiop->flags & TCHARS_SET)
+    {
+      _rl_tty_chars.t_intr = tiop->tchars.t_intrc;
+      _rl_tty_chars.t_quit = tiop->tchars.t_quitc;
+      _rl_tty_chars.t_start = tiop->tchars.t_startc;
+      _rl_tty_chars.t_stop = tiop->tchars.t_stopc;
+      _rl_tty_chars.t_eof = tiop->tchars.t_eofc;
+      _rl_tty_chars.t_eol = '\n';
+      _rl_tty_chars.t_eol2 = tiop->tchars.t_brkc;
+    }
+
+  if (tiop->flags & LTCHARS_SET)
+    {
+      _rl_tty_chars.t_susp = tiop->ltchars.t_suspc;
+      _rl_tty_chars.t_dsusp = tiop->ltchars.t_dsuspc;
+      _rl_tty_chars.t_reprint = tiop->ltchars.t_rprntc;
+      _rl_tty_chars.t_flush = tiop->ltchars.t_flushc;
+      _rl_tty_chars.t_werase = tiop->ltchars.t_werasc;
+      _rl_tty_chars.t_lnext = tiop->ltchars.t_lnextc;
+    }
+
+  _rl_tty_chars.t_status = -1;
+}
+
+static int
+get_tty_settings (tty, tiop)
+     int tty;
+     TIOTYPE *tiop;
+{
+  set_winsize (tty);
+
+  tiop->flags = tiop->lflag = 0;
+
+  errno = 0;
+  if (ioctl (tty, TIOCGETP, &(tiop->sgttyb)) < 0)
+    return -1;
+  tiop->flags |= SGTTY_SET;
+
+#if defined (TIOCLGET)
+  if (ioctl (tty, TIOCLGET, &(tiop->lflag)) == 0)
+    tiop->flags |= LFLAG_SET;
+#endif
+
+#if defined (TIOCGETC)
+  if (ioctl (tty, TIOCGETC, &(tiop->tchars)) == 0)
+    tiop->flags |= TCHARS_SET;
+#endif
+
+#if defined (TIOCGLTC)
+  if (ioctl (tty, TIOCGLTC, &(tiop->ltchars)) == 0)
+    tiop->flags |= LTCHARS_SET;
+#endif
+
+  return 0;
+}
+
+static int
+set_tty_settings (tty, tiop)
+     int tty;
+     TIOTYPE *tiop;
+{
+  if (tiop->flags & SGTTY_SET)
+    {
+      ioctl (tty, TIOCSETN, &(tiop->sgttyb));
+      tiop->flags &= ~SGTTY_SET;
+    }
+  readline_echoing_p = 1;
+
+#if defined (TIOCLSET)
+  if (tiop->flags & LFLAG_SET)
+    {
+      ioctl (tty, TIOCLSET, &(tiop->lflag));
+      tiop->flags &= ~LFLAG_SET;
+    }
+#endif
+
+#if defined (TIOCSETC)
+  if (tiop->flags & TCHARS_SET)
+    {
+      ioctl (tty, TIOCSETC, &(tiop->tchars));
+      tiop->flags &= ~TCHARS_SET;
+    }
+#endif
+
+#if defined (TIOCSLTC)
+  if (tiop->flags & LTCHARS_SET)
+    {
+      ioctl (tty, TIOCSLTC, &(tiop->ltchars));
+      tiop->flags &= ~LTCHARS_SET;
+    }
+#endif
+
+  return 0;
+}
+
+static void
+prepare_terminal_settings (meta_flag, oldtio, tiop)
+     int meta_flag;
+     TIOTYPE oldtio, *tiop;
+{
+  readline_echoing_p = (oldtio.sgttyb.sg_flags & ECHO);
+
+  /* Copy the original settings to the structure we're going to use for
+     our settings. */
+  tiop->sgttyb = oldtio.sgttyb;
+  tiop->lflag = oldtio.lflag;
+#if defined (TIOCGETC)
+  tiop->tchars = oldtio.tchars;
+#endif
+#if defined (TIOCGLTC)
+  tiop->ltchars = oldtio.ltchars;
+#endif
+  tiop->flags = oldtio.flags;
+
+  /* First, the basic settings to put us into character-at-a-time, no-echo
+     input mode. */
+  tiop->sgttyb.sg_flags &= ~(ECHO | CRMOD);
+  tiop->sgttyb.sg_flags |= CBREAK;
+
+  /* If this terminal doesn't care how the 8th bit is used, then we can
+     use it for the meta-key.  If only one of even or odd parity is
+     specified, then the terminal is using parity, and we cannot. */
+#if !defined (ANYP)
+#  define ANYP (EVENP | ODDP)
+#endif
+  if (((oldtio.sgttyb.sg_flags & ANYP) == ANYP) ||
+      ((oldtio.sgttyb.sg_flags & ANYP) == 0))
+    {
+      tiop->sgttyb.sg_flags |= ANYP;
+
+      /* Hack on local mode flags if we can. */
+#if defined (TIOCLGET)
+#  if defined (LPASS8)
+      tiop->lflag |= LPASS8;
+#  endif /* LPASS8 */
+#endif /* TIOCLGET */
+    }
+
+#if defined (TIOCGETC)
+#  if defined (USE_XON_XOFF)
+  /* Get rid of terminal output start and stop characters. */
+  tiop->tchars.t_stopc = -1; /* C-s */
+  tiop->tchars.t_startc = -1; /* C-q */
+
+  /* If there is an XON character, bind it to restart the output. */
+  if (oldtio.tchars.t_startc != -1)
+    rl_bind_key (oldtio.tchars.t_startc, rl_restart_output);
+#  endif /* USE_XON_XOFF */
+
+  /* If there is an EOF char, bind _rl_eof_char to it. */
+  if (oldtio.tchars.t_eofc != -1)
+    _rl_eof_char = oldtio.tchars.t_eofc;
+
+#  if defined (NO_KILL_INTR)
+  /* Get rid of terminal-generated SIGQUIT and SIGINT. */
+  tiop->tchars.t_quitc = -1; /* C-\ */
+  tiop->tchars.t_intrc = -1; /* C-c */
+#  endif /* NO_KILL_INTR */
+#endif /* TIOCGETC */
+
+#if defined (TIOCGLTC)
+  /* Make the interrupt keys go away.  Just enough to make people happy. */
+  tiop->ltchars.t_dsuspc = -1; /* C-y */
+  tiop->ltchars.t_lnextc = -1; /* C-v */
+#endif /* TIOCGLTC */
+}
+
+#else  /* !defined (NEW_TTY_DRIVER) */
+
+#if !defined (VMIN)
+#  define VMIN VEOF
+#endif
+
+#if !defined (VTIME)
+#  define VTIME VEOL
+#endif
+
+#if defined (TERMIOS_TTY_DRIVER)
+#  define TIOTYPE struct termios
+#  define DRAIN_OUTPUT(fd)     tcdrain (fd)
+#  define GETATTR(tty, tiop)   (tcgetattr (tty, tiop))
+#  ifdef M_UNIX
+#    define SETATTR(tty, tiop) (tcsetattr (tty, TCSANOW, tiop))
+#  else
+#    define SETATTR(tty, tiop) (tcsetattr (tty, TCSADRAIN, tiop))
+#  endif /* !M_UNIX */
+#else
+#  define TIOTYPE struct termio
+#  define DRAIN_OUTPUT(fd)
+#  define GETATTR(tty, tiop)   (ioctl (tty, TCGETA, tiop))
+#  define SETATTR(tty, tiop)   (ioctl (tty, TCSETAW, tiop))
+#endif /* !TERMIOS_TTY_DRIVER */
+
+static TIOTYPE otio;
+
+static void save_tty_chars PARAMS((TIOTYPE *));
+static int _get_tty_settings PARAMS((int, TIOTYPE *));
+static int get_tty_settings PARAMS((int, TIOTYPE *));
+static int _set_tty_settings PARAMS((int, TIOTYPE *));
+static int set_tty_settings PARAMS((int, TIOTYPE *));
+
+static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *));
+
+static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t));
+static void _rl_bind_tty_special_chars PARAMS((Keymap, TIOTYPE));
+
+#if defined (FLUSHO)
+#  define OUTPUT_BEING_FLUSHED(tp)  (tp->c_lflag & FLUSHO)
+#else
+#  define OUTPUT_BEING_FLUSHED(tp)  0
+#endif
+
+static void
+save_tty_chars (tiop)
+     TIOTYPE *tiop;
+{
+  _rl_last_tty_chars = _rl_tty_chars;
+
+  _rl_tty_chars.t_eof = tiop->c_cc[VEOF];
+  _rl_tty_chars.t_eol = tiop->c_cc[VEOL];
+#ifdef VEOL2
+  _rl_tty_chars.t_eol2 = tiop->c_cc[VEOL2];
+#endif
+  _rl_tty_chars.t_erase = tiop->c_cc[VERASE];
+#ifdef VWERASE
+  _rl_tty_chars.t_werase = tiop->c_cc[VWERASE];
+#endif
+  _rl_tty_chars.t_kill = tiop->c_cc[VKILL];
+#ifdef VREPRINT
+  _rl_tty_chars.t_reprint = tiop->c_cc[VREPRINT];
+#endif
+  _rl_tty_chars.t_intr = tiop->c_cc[VINTR];
+  _rl_tty_chars.t_quit = tiop->c_cc[VQUIT];
+#ifdef VSUSP
+  _rl_tty_chars.t_susp = tiop->c_cc[VSUSP];
+#endif
+#ifdef VDSUSP
+  _rl_tty_chars.t_dsusp = tiop->c_cc[VDSUSP];
+#endif
+#ifdef VSTART
+  _rl_tty_chars.t_start = tiop->c_cc[VSTART];
+#endif
+#ifdef VSTOP
+  _rl_tty_chars.t_stop = tiop->c_cc[VSTOP];
+#endif
+#ifdef VLNEXT
+  _rl_tty_chars.t_lnext = tiop->c_cc[VLNEXT];
+#endif
+#ifdef VDISCARD
+  _rl_tty_chars.t_flush = tiop->c_cc[VDISCARD];
+#endif
+#ifdef VSTATUS
+  _rl_tty_chars.t_status = tiop->c_cc[VSTATUS];
+#endif
+}
+
+#if defined (_AIX) || defined (_AIX41)
+/* Currently this is only used on AIX */
+static void
+rltty_warning (msg)
+     char *msg;
+{
+  fprintf (stderr, "readline: warning: %s\n", msg);
+}
+#endif
+
+#if defined (_AIX)
+void
+setopost(tp)
+TIOTYPE *tp;
+{
+  if ((tp->c_oflag & OPOST) == 0)
+    {
+      rltty_warning ("turning on OPOST for terminal\r");
+      tp->c_oflag |= OPOST|ONLCR;
+    }
+}
+#endif
+
+static int
+_get_tty_settings (tty, tiop)
+     int tty;
+     TIOTYPE *tiop;
+{
+  int ioctl_ret;
+
+  while (1)
+    {
+      ioctl_ret = GETATTR (tty, tiop);
+      if (ioctl_ret < 0)
+       {
+         if (errno != EINTR)
+           return -1;
+         else
+           continue;
+       }
+      if (OUTPUT_BEING_FLUSHED (tiop))
+       {
+#if defined (FLUSHO) && defined (_AIX41)
+         rltty_warning ("turning off output flushing");
+         tiop->c_lflag &= ~FLUSHO;
+         break;
+#else
+         continue;
+#endif
+       }
+      break;
+    }
+
+  return 0;
+}
+
+static int
+get_tty_settings (tty, tiop)
+     int tty;
+     TIOTYPE *tiop;
+{
+  set_winsize (tty);
+
+  errno = 0;
+  if (_get_tty_settings (tty, tiop) < 0)
+    return -1;
+
+#if defined (_AIX)
+  setopost(tiop);
+#endif
+
+  return 0;
+}
+
+static int
+_set_tty_settings (tty, tiop)
+     int tty;
+     TIOTYPE *tiop;
+{
+  while (SETATTR (tty, tiop) < 0)
+    {
+      if (errno != EINTR)
+       return -1;
+      errno = 0;
+    }
+  return 0;
+}
+
+static int
+set_tty_settings (tty, tiop)
+     int tty;
+     TIOTYPE *tiop;
+{
+  if (_set_tty_settings (tty, tiop) < 0)
+    return -1;
+    
+#if 0
+
+#if defined (TERMIOS_TTY_DRIVER)
+#  if defined (__ksr1__)
+  if (ksrflow)
+    {
+      ksrflow = 0;
+      tcflow (tty, TCOON);
+    }
+#  else /* !ksr1 */
+  tcflow (tty, TCOON);         /* Simulate a ^Q. */
+#  endif /* !ksr1 */
+#else
+  ioctl (tty, TCXONC, 1);      /* Simulate a ^Q. */
+#endif /* !TERMIOS_TTY_DRIVER */
+
+#endif /* 0 */
+
+  return 0;
+}
+
+static void
+prepare_terminal_settings (meta_flag, oldtio, tiop)
+     int meta_flag;
+     TIOTYPE oldtio, *tiop;
+{
+  readline_echoing_p = (oldtio.c_lflag & ECHO);
+
+  tiop->c_lflag &= ~(ICANON | ECHO);
+
+  if ((unsigned char) oldtio.c_cc[VEOF] != (unsigned char) _POSIX_VDISABLE)
+    _rl_eof_char = oldtio.c_cc[VEOF];
+
+#if defined (USE_XON_XOFF)
+#if defined (IXANY)
+  tiop->c_iflag &= ~(IXON | IXOFF | IXANY);
+#else
+  /* `strict' Posix systems do not define IXANY. */
+  tiop->c_iflag &= ~(IXON | IXOFF);
+#endif /* IXANY */
+#endif /* USE_XON_XOFF */
+
+  /* Only turn this off if we are using all 8 bits. */
+  if (((tiop->c_cflag & CSIZE) == CS8) || meta_flag)
+    tiop->c_iflag &= ~(ISTRIP | INPCK);
+
+  /* Make sure we differentiate between CR and NL on input. */
+  tiop->c_iflag &= ~(ICRNL | INLCR);
+
+#if !defined (HANDLE_SIGNALS)
+  tiop->c_lflag &= ~ISIG;
+#else
+  tiop->c_lflag |= ISIG;
+#endif
+
+  tiop->c_cc[VMIN] = 1;
+  tiop->c_cc[VTIME] = 0;
+
+#if defined (FLUSHO)
+  if (OUTPUT_BEING_FLUSHED (tiop))
+    {
+      tiop->c_lflag &= ~FLUSHO;
+      oldtio.c_lflag &= ~FLUSHO;
+    }
+#endif
+
+  /* Turn off characters that we need on Posix systems with job control,
+     just to be sure.  This includes ^Y and ^V.  This should not really
+     be necessary.  */
+#if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_VDISABLE)
+
+#if defined (VLNEXT)
+  tiop->c_cc[VLNEXT] = _POSIX_VDISABLE;
+#endif
+
+#if defined (VDSUSP)
+  tiop->c_cc[VDSUSP] = _POSIX_VDISABLE;
+#endif
+
+#endif /* TERMIOS_TTY_DRIVER && _POSIX_VDISABLE */
+}
+#endif  /* NEW_TTY_DRIVER */
+
+/* Put the terminal in CBREAK mode so that we can detect key presses. */
+void
+rl_prep_terminal (meta_flag)
+     int meta_flag;
+{
+  int tty;
+  TIOTYPE tio;
+
+  if (terminal_prepped)
+    return;
+
+  /* Try to keep this function from being INTerrupted. */
+  block_sigint ();
+
+  tty = fileno (rl_instream);
+
+  if (get_tty_settings (tty, &tio) < 0)
+    {
+#if defined (ENOTSUP)
+      /* MacOS X, at least, lies about the value of errno if tcgetattr fails. */
+      if (errno == ENOTTY || errno == ENOTSUP)
+#else
+      if (errno == ENOTTY)
+#endif
+       readline_echoing_p = 1;         /* XXX */
+      release_sigint ();
+      return;
+    }
+
+  otio = tio;
+
+  if (_rl_bind_stty_chars)
+    rl_tty_unset_default_bindings (_rl_keymap);
+  save_tty_chars (&otio);
+  RL_SETSTATE(RL_STATE_TTYCSAVED);
+  if (_rl_bind_stty_chars)
+    _rl_bind_tty_special_chars (_rl_keymap, tio);
+
+  prepare_terminal_settings (meta_flag, otio, &tio);
+
+  if (set_tty_settings (tty, &tio) < 0)
+    {
+      release_sigint ();
+      return;
+    }
+
+  if (_rl_enable_keypad)
+    _rl_control_keypad (1);
+
+  fflush (rl_outstream);
+  terminal_prepped = 1;
+  RL_SETSTATE(RL_STATE_TERMPREPPED);
+
+  release_sigint ();
+}
+
+/* Restore the terminal's normal settings and modes. */
+void
+rl_deprep_terminal ()
+{
+  int tty;
+
+  if (!terminal_prepped)
+    return;
+
+  /* Try to keep this function from being interrupted. */
+  block_sigint ();
+
+  tty = fileno (rl_instream);
+
+  if (_rl_enable_keypad)
+    _rl_control_keypad (0);
+
+  fflush (rl_outstream);
+
+  if (set_tty_settings (tty, &otio) < 0)
+    {
+      release_sigint ();
+      return;
+    }
+
+  terminal_prepped = 0;
+  RL_UNSETSTATE(RL_STATE_TERMPREPPED);
+
+  release_sigint ();
+}
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Bogus Flow Control                          */
+/*                                                                 */
+/* **************************************************************** */
+
+int
+rl_restart_output (count, key)
+     int count, key;
+{
+#if defined (__MINGW32__)
+  return 0;
+#else /* !__MING32__ */
+  int fildes = fileno (rl_outstream);
+#if defined (TIOCSTART)
+#if defined (apollo)
+  ioctl (&fildes, TIOCSTART, 0);
+#else
+  ioctl (fildes, TIOCSTART, 0);
+#endif /* apollo */
+
+#else /* !TIOCSTART */
+#  if defined (TERMIOS_TTY_DRIVER)
+#    if defined (__ksr1__)
+  if (ksrflow)
+    {
+      ksrflow = 0;
+      tcflow (fildes, TCOON);
+    }
+#    else /* !ksr1 */
+  tcflow (fildes, TCOON);              /* Simulate a ^Q. */
+#    endif /* !ksr1 */
+#  else /* !TERMIOS_TTY_DRIVER */
+#    if defined (TCXONC)
+  ioctl (fildes, TCXONC, TCOON);
+#    endif /* TCXONC */
+#  endif /* !TERMIOS_TTY_DRIVER */
+#endif /* !TIOCSTART */
+
+  return 0;
+#endif /* !__MINGW32__ */
+}
+
+int
+rl_stop_output (count, key)
+     int count, key;
+{
+  int fildes = fileno (rl_instream);
+
+#if defined (TIOCSTOP)
+# if defined (apollo)
+  ioctl (&fildes, TIOCSTOP, 0);
+# else
+  ioctl (fildes, TIOCSTOP, 0);
+# endif /* apollo */
+#else /* !TIOCSTOP */
+# if defined (TERMIOS_TTY_DRIVER)
+#  if defined (__ksr1__)
+  ksrflow = 1;
+#  endif /* ksr1 */
+  tcflow (fildes, TCOOFF);
+# else
+#   if defined (TCXONC)
+  ioctl (fildes, TCXONC, TCOON);
+#   endif /* TCXONC */
+# endif /* !TERMIOS_TTY_DRIVER */
+#endif /* !TIOCSTOP */
+
+  return 0;
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Default Key Bindings                        */
+/*                                                                 */
+/* **************************************************************** */
+
+#define SET_SPECIAL(sc, func)  set_special_char(kmap, &ttybuff, sc, func)
+
+#if defined (NEW_TTY_DRIVER)
+static void
+set_special_char (kmap, tiop, sc, func)
+     Keymap kmap;
+     TIOTYPE *tiop;
+     int sc;
+     rl_command_func_t *func;
+{
+  if (sc != -1 && kmap[(unsigned char)sc].type == ISFUNC)
+    kmap[(unsigned char)sc].function = func;
+}
+
+#define RESET_SPECIAL(c) \
+  if (c != -1 && kmap[(unsigned char)c].type == ISFUNC)
+    kmap[(unsigned char)c].function = rl_insert;
+
+static void
+_rl_bind_tty_special_chars (kmap, ttybuff)
+     Keymap kmap;
+     TIOTYPE ttybuff;
+{
+  if (ttybuff.flags & SGTTY_SET)
+    {
+      SET_SPECIAL (ttybuff.sgttyb.sg_erase, rl_rubout);
+      SET_SPECIAL (ttybuff.sgttyb.sg_kill, rl_unix_line_discard);
+    }
+
+#  if defined (TIOCGLTC)
+  if (ttybuff.flags & LTCHARS_SET)
+    {
+      SET_SPECIAL (ttybuff.ltchars.t_werasc, rl_unix_word_rubout);
+      SET_SPECIAL (ttybuff.ltchars.t_lnextc, rl_quoted_insert);
+    }
+#  endif /* TIOCGLTC */
+}
+
+#else /* !NEW_TTY_DRIVER */
+static void
+set_special_char (kmap, tiop, sc, func)
+     Keymap kmap;
+     TIOTYPE *tiop;
+     int sc;
+     rl_command_func_t *func;
+{
+  unsigned char uc;
+
+  uc = tiop->c_cc[sc];
+  if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC)
+    kmap[uc].function = func;
+}
+
+/* used later */
+#define RESET_SPECIAL(uc) \
+  if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) \
+    kmap[uc].function = rl_insert;
+
+static void
+_rl_bind_tty_special_chars (kmap, ttybuff)
+     Keymap kmap;
+     TIOTYPE ttybuff;
+{
+  SET_SPECIAL (VERASE, rl_rubout);
+  SET_SPECIAL (VKILL, rl_unix_line_discard);
+
+#  if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER)
+  SET_SPECIAL (VLNEXT, rl_quoted_insert);
+#  endif /* VLNEXT && TERMIOS_TTY_DRIVER */
+
+#  if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER)
+  SET_SPECIAL (VWERASE, rl_unix_word_rubout);
+#  endif /* VWERASE && TERMIOS_TTY_DRIVER */
+}
+
+#endif /* !NEW_TTY_DRIVER */
+
+/* Set the system's default editing characters to their readline equivalents
+   in KMAP.  Should be static, now that we have rl_tty_set_default_bindings. */
+void
+rltty_set_default_bindings (kmap)
+     Keymap kmap;
+{
+#if !defined (__MINGW32__)
+  TIOTYPE ttybuff;
+  int tty;
+  static int called = 0;
+
+  tty = fileno (rl_instream);
+
+  if (get_tty_settings (tty, &ttybuff) == 0)
+    _rl_bind_tty_special_chars (kmap, ttybuff);
+#endif
+}
+
+/* New public way to set the system default editing chars to their readline
+   equivalents. */
+void
+rl_tty_set_default_bindings (kmap)
+     Keymap kmap;
+{
+#if !defined (__MINGW32__)
+  rltty_set_default_bindings (kmap);
+#endif
+}
+
+/* Rebind all of the tty special chars that readline worries about back
+   to self-insert.  Call this before saving the current terminal special
+   chars with save_tty_chars().  This only works on POSIX termios or termio
+   systems. */
+void
+rl_tty_unset_default_bindings (kmap)
+     Keymap kmap;
+{
+  /* Don't bother before we've saved the tty special chars at least once. */
+  if (RL_ISSTATE(RL_STATE_TTYCSAVED) == 0)
+    return;
+
+  RESET_SPECIAL (_rl_tty_chars.t_erase);
+  RESET_SPECIAL (_rl_tty_chars.t_kill);
+
+#  if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER)
+  RESET_SPECIAL (_rl_tty_chars.t_lnext);
+#  endif /* VLNEXT && TERMIOS_TTY_DRIVER */
+
+#  if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER)
+  RESET_SPECIAL (_rl_tty_chars.t_werase);
+#  endif /* VWERASE && TERMIOS_TTY_DRIVER */
+}
+
+#if defined (HANDLE_SIGNALS)
+
+#if defined (NEW_TTY_DRIVER) || defined (__MINGW32__)
+int
+_rl_disable_tty_signals ()
+{
+  return 0;
+}
+
+int
+_rl_restore_tty_signals ()
+{
+  return 0;
+}
+#else
+
+static TIOTYPE sigstty, nosigstty;
+static int tty_sigs_disabled = 0;
+
+int
+_rl_disable_tty_signals ()
+{
+  if (tty_sigs_disabled)
+    return 0;
+
+  if (_get_tty_settings (fileno (rl_instream), &sigstty) < 0)
+    return -1;
+
+  nosigstty = sigstty;
+
+  nosigstty.c_lflag &= ~ISIG;
+  nosigstty.c_iflag &= ~IXON;
+
+  if (_set_tty_settings (fileno (rl_instream), &nosigstty) < 0)
+    return (_set_tty_settings (fileno (rl_instream), &sigstty));
+
+  tty_sigs_disabled = 1;
+  return 0;
+}
+
+int
+_rl_restore_tty_signals ()
+{
+  int r;
+
+  if (tty_sigs_disabled == 0)
+    return 0;
+
+  r = _set_tty_settings (fileno (rl_instream), &sigstty);
+
+  if (r == 0)
+    tty_sigs_disabled = 0;
+
+  return r;
+}
+#endif /* !NEW_TTY_DRIVER */
+
+#endif /* HANDLE_SIGNALS */
index 22947bdb687d8e79f8137b1cdaf745cbd896dc9f..4bbbf8b4c644e3d963f3c6b7cb8954921c22a350 100644 (file)
@@ -1,7 +1,7 @@
 /* rltty.c -- functions to prepare and restore the terminal for readline's
    use. */
 
-/* Copyright (C) 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1992-2005 Free Software Foundation, Inc.
 
    This file is part of the GNU Readline Library, a library for
    reading lines of text with interactive input and history editing.
@@ -152,7 +152,9 @@ set_winsize (tty)
 #endif /* TIOCGWINSZ */
 }
 
-#if defined (NEW_TTY_DRIVER)
+#if defined (NO_TTY_DRIVER)
+
+#elif defined (NEW_TTY_DRIVER)
 
 /* Values for the `flags' field of a struct bsdtty.  This tells which
    elements of the struct bsdtty have been fetched from the system and
@@ -520,7 +522,6 @@ get_tty_settings (tty, tiop)
   set_winsize (tty);
 
   errno = 0;
-fprintf(stderr, "get_tty_settings: errno = %d\n", errno);
   if (_get_tty_settings (tty, tiop) < 0)
     return -1;
 
@@ -637,6 +638,20 @@ prepare_terminal_settings (meta_flag, oldtio, tiop)
 #endif  /* NEW_TTY_DRIVER */
 
 /* Put the terminal in CBREAK mode so that we can detect key presses. */
+#if defined (NO_TTY_DRIVER)
+void
+rl_prep_terminal (meta_flag)
+     int meta_flag;
+{
+  readline_echoing_p = 1;
+}
+
+void
+rl_deprep_terminal ()
+{
+}
+
+#else /* ! NO_TTY_DRIVER */
 void
 rl_prep_terminal (meta_flag)
      int meta_flag;
@@ -652,12 +667,15 @@ rl_prep_terminal (meta_flag)
 
   tty = fileno (rl_instream);
 
-  errno = 0;
   if (get_tty_settings (tty, &tio) < 0)
     {
+#if defined (ENOTSUP)
+      /* MacOS X, at least, lies about the value of errno if tcgetattr fails. */
+      if (errno == ENOTTY || errno == ENOTSUP)
+#else
       if (errno == ENOTTY)
+#endif
        readline_echoing_p = 1;         /* XXX */
-else fprintf(stderr, "get_tty_settings fails but errno == %d\n", errno);
       release_sigint ();
       return;
     }
@@ -719,6 +737,7 @@ rl_deprep_terminal ()
 
   release_sigint ();
 }
+#endif /* !NO_TTY_DRIVER */
 \f
 /* **************************************************************** */
 /*                                                                 */
@@ -730,6 +749,10 @@ int
 rl_restart_output (count, key)
      int count, key;
 {
+#if defined (__MINGW32__)
+  return 0;
+#else /* !__MING32__ */
+
   int fildes = fileno (rl_outstream);
 #if defined (TIOCSTART)
 #if defined (apollo)
@@ -757,12 +780,17 @@ rl_restart_output (count, key)
 #endif /* !TIOCSTART */
 
   return 0;
+#endif /* !__MINGW32__ */
 }
 
 int
 rl_stop_output (count, key)
      int count, key;
 {
+#if defined (__MINGW32__)
+  return 0;
+#else
+
   int fildes = fileno (rl_instream);
 
 #if defined (TIOCSTOP)
@@ -785,6 +813,7 @@ rl_stop_output (count, key)
 #endif /* !TIOCSTOP */
 
   return 0;
+#endif /* !__MINGW32__ */
 }
 
 /* **************************************************************** */
@@ -793,9 +822,16 @@ rl_stop_output (count, key)
 /*                                                                 */
 /* **************************************************************** */
 
+#if !defined (NO_TTY_DRIVER)
 #define SET_SPECIAL(sc, func)  set_special_char(kmap, &ttybuff, sc, func)
+#endif
 
-#if defined (NEW_TTY_DRIVER)
+#if defined (NO_TTY_DRIVER)
+
+#define SET_SPECIAL(sc, func)
+#define RESET_SPECIAL(c)
+
+#elif defined (NEW_TTY_DRIVER)
 static void
 set_special_char (kmap, tiop, sc, func)
      Keymap kmap;
@@ -876,6 +912,7 @@ void
 rltty_set_default_bindings (kmap)
      Keymap kmap;
 {
+#if !defined (NO_TTY_DRIVER)
   TIOTYPE ttybuff;
   int tty;
   static int called = 0;
@@ -884,6 +921,7 @@ rltty_set_default_bindings (kmap)
 
   if (get_tty_settings (tty, &ttybuff) == 0)
     _rl_bind_tty_special_chars (kmap, ttybuff);
+#endif
 }
 
 /* New public way to set the system default editing chars to their readline
@@ -921,7 +959,7 @@ rl_tty_unset_default_bindings (kmap)
 
 #if defined (HANDLE_SIGNALS)
 
-#if defined (NEW_TTY_DRIVER)
+#if defined (NEW_TTY_DRIVER) || defined (NO_TTY_DRIVER)
 int
 _rl_disable_tty_signals ()
 {
index abb0402edc0c07759d1cb8856bf3f8f84a855885..e992a66323134e723dd30a5ceb94853d20323fe6 100644 (file)
@@ -81,7 +81,8 @@ sh_double_quote (string)
 
   for (s = string; s && (c = *s); s++)
     {
-      if (sh_syntaxtab[c] & CBSDQUOTE)
+      /* Backslash-newline disappears within double quotes, so don't add one. */
+      if ((sh_syntaxtab[c] & CBSDQUOTE) && c != '\n')
        *r++ = '\\';
       else if (c == CTLESC || c == CTLNUL)
        *r++ = CTLESC;          /* could be '\\'? */
index aac2d3494721c9a0642e7ef7e33f5f90e126f2b9..87ab4b447e7f2dcc067ce3e5096dee60546c9aba 100644 (file)
@@ -81,7 +81,7 @@ sh_double_quote (string)
 
   for (s = string; s && (c = *s); s++)
     {
-      if (sh_syntaxtab[c] & CBSDQUOTE)
+      if ((sh_syntaxtab[c] & CBSDQUOTE) && c != '\n')
        *r++ = '\\';
       else if (c == CTLESC || c == CTLNUL)
        *r++ = CTLESC;          /* could be '\\'? */
@@ -95,6 +95,32 @@ sh_double_quote (string)
   return (result);
 }
 
+/* Turn S into a simple double-quoted string.  If FLAGS is non-zero, quote
+   double quote characters in S with backslashes. */
+char *
+sh_mkdoublequoted (s, slen, flags)
+     const char *s;
+     int slen, flags;
+{
+  char *r, *ret;
+  int rlen;
+
+  rlen = (flags == 0) ? slen + 3 : (2 * slen) + 1;
+  ret = r = (char *)xmalloc (rlen);
+  
+  *r++ = '"';
+  while (*s)
+    {
+      if (flags && *s == '"')
+       *r++ = '\\';
+      *r++ = *s++;
+    }
+  *r++ = '"';
+  *r = '\0';
+
+  return ret;
+}
+
 /* Remove backslashes that are quoting characters that are special between
    double quotes.  Return a new string.  XXX - should this handle CTLESC
    and CTLNUL? */
@@ -128,7 +154,11 @@ sh_un_double_quote (string)
 }
 
 /* Quote special characters in STRING using backslashes.  Return a new
-   string. */
+   string.  NOTE:  if the string is to be further expanded, we need a
+   way to protect the CTLESC and CTLNUL characters.  As I write this,
+   the current callers will never cause the string to be expanded without
+   going through the shell parser, which will protect the internal
+   quoting characters. */
 char *
 sh_backslash_quote (string)
      char *string;
@@ -160,11 +190,12 @@ sh_backslash_quote (string)
            *r++ = '\\';
          *r++ = c;
          break;
-#endif
+
        case CTLESC: case CTLNUL:               /* internal quoting characters */
          *r++ = CTLESC;                        /* could be '\\'? */
          *r++ = c;
          break;
+#endif
 
        case '#':                               /* comment char */
          if (s == string)
index 5e73a28a6f4bf3e27dbc4cf4d94bed31308ea9ca..49517ad79b7215ab13606f8a36d956c2ef30d85e 100644 (file)
@@ -259,7 +259,7 @@ make_arith_for_expr (s)
   if (s == 0 || *s == '\0')
     return ((WORD_LIST *)NULL);
   wd = make_word (s);
-  wd->flags |= W_NOGLOB|W_NOSPLIT|W_QUOTED   /* no word splitting or globbing */
+  wd->flags |= W_NOGLOB|W_NOSPLIT|W_QUOTED|W_DQUOTE;   /* no word splitting or globbing */
   result = make_word_list (wd, (WORD_LIST *)NULL);
   return result;
 }
index 0f2f986aac0e4cccb4659cbf45a547e73d9b7f61..5e73a28a6f4bf3e27dbc4cf4d94bed31308ea9ca 100644 (file)
@@ -1,7 +1,7 @@
 /* make_cmd.c -- Functions for making instances of the various
    parser constructs. */
 
-/* Copyright (C) 1989-2003 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2005 Free Software Foundation, Inc.
 
 This file is part of GNU Bash, the Bourne Again SHell.
 
diff --git a/parse.y b/parse.y
index 3ae6ea1888654ef947a5ab6dec1deae0dddfd05b..e510c994622caf1acfa8d230df3c54ce0a3749f8 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -2939,7 +2939,7 @@ parse_dparen (c)
        {
          wd = alloc_word_desc ();
          wd->word = wval;
-         wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB;
+         wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_DQUOTE;
          yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL);
          return (ARITH_CMD);
        }
index 9ea5b6dea1494e8c386c65b01da07e6b21c92a00..e510c994622caf1acfa8d230df3c54ce0a3749f8 100644 (file)
--- a/parse.y~
+++ b/parse.y~
@@ -1968,7 +1968,6 @@ shell_getc (remove_quoted_newline)
        }
 
       shell_input_line_index = 0;
-itrace("reset shell_input_line_index = 0");
       shell_input_line_len = i;                /* == strlen (shell_input_line) */
 
       set_line_mbstate ();
@@ -2940,7 +2939,7 @@ parse_dparen (c)
        {
          wd = alloc_word_desc ();
          wd->word = wval;
-         wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB;
+         wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_DQUOTE;
          yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL);
          return (ARITH_CMD);
        }
index 2533d2179837bbac965e877d5ca4b07ebf3ef999..7524f3ddeb19962c571076f93b809654a6dc23b0 100644 (file)
@@ -485,9 +485,9 @@ print_arith_for_command (arith_for_command)
 {
   cprintf ("for ((");
   command_print_word_list (arith_for_command->init, " ");
-  cprintf (" ; ");
+  cprintf ("; ");
   command_print_word_list (arith_for_command->test, " ");
-  cprintf (" ; ");
+  cprintf ("; ");
   command_print_word_list (arith_for_command->step, " ");
   cprintf ("))");
   newline ("do\n");
index 098daa150c7b4c1ae649fa65bd66233566e27900..2533d2179837bbac965e877d5ca4b07ebf3ef999 100644 (file)
@@ -1,6 +1,6 @@
 /* print_command -- A way to make readable commands from a command tree. */
 
-/* Copyright (C) 1989-2004 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2005 Free Software Foundation, Inc.
 
 This file is part of GNU Bash, the Bourne Again SHell.
 
diff --git a/redir.c b/redir.c
index 61e4d86e7067f3d5747ed5f4f75d8fa1d085591d..08715a0e5e29118a071c47efe8c499921e1723fc 100644 (file)
--- a/redir.c
+++ b/redir.c
@@ -1,6 +1,6 @@
 /* redir.c -- Functions to perform input and output redirection. */
 
-/* Copyright (C) 1997-2002 Free Software Foundation, Inc.
+/* Copyright (C) 1997-2005 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
diff --git a/subst.c b/subst.c
index c71801a3b28b4b77d08b1c51803ea013991d0550..7a8207fddf52076196eabad51c97153a9753b9a7 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -4512,7 +4512,7 @@ command_substitute (string, quoted)
   if ((subshell_environment & SUBSHELL_PIPE) == 0)
     pipeline_pgrp = shell_pgrp;
   cleanup_the_pipeline ();
-#endif
+#endif /* JOB_CONTROL */
 
   old_async_pid = last_asynchronous_pid;
 #if 0
@@ -6703,7 +6703,7 @@ add_string:
        case '<':
        case '>':
          {
-           if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || posixly_correct)
+           if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & W_DQUOTE) || posixly_correct)
              {
                sindex--;       /* add_character: label increments sindex */
                goto add_character;
@@ -6769,7 +6769,7 @@ add_string:
          /* If the word isn't supposed to be tilde expanded, or we're not
             at the start of a word or after an unquoted : or = in an
             assignment statement, we don't do tilde expansion. */
-         if ((word->flags & W_NOTILDE) ||
+         if ((word->flags & (W_NOTILDE|W_DQUOTE)) ||
              (sindex > 0 && ((word->flags & W_ITILDE) == 0)) ||
              (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
            {
@@ -6896,7 +6896,11 @@ add_twochars:
          break;
 
        case '"':
-         if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
+#if 0
+         if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE))
+#else
+         if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
+#endif
            goto add_character;
 
          t_index = ++sindex;
@@ -7042,7 +7046,11 @@ add_twochars:
          /* break; */
 
        case '\'':
-         if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
+#if 0
+         if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE))
+#else
+         if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
+#endif
            goto add_character;
 
          t_index = ++sindex;
index bc17f989d468d65b14443b2b9844459c252a3be0..b24e9c04d7b3224e5163c290ef815be235020566 100644 (file)
--- a/subst.c~
+++ b/subst.c~
@@ -3618,10 +3618,10 @@ match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
       *wp = '\0';
     }
   else
-    wp = wpat;
-  len = wcsmatch (wp, wstring, FNMATCH_EXTFLAG);
-  if (wp != wpat)
-    free (wp);
+    nwpat = wpat;
+  len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG);
+  if (nwpat != wpat)
+    free (nwpat);
   if (len == FNM_NOMATCH)
     return (0);
 
@@ -4512,7 +4512,7 @@ command_substitute (string, quoted)
   if ((subshell_environment & SUBSHELL_PIPE) == 0)
     pipeline_pgrp = shell_pgrp;
   cleanup_the_pipeline ();
-#endif
+#endif /* JOB_CONTROL */
 
   old_async_pid = last_asynchronous_pid;
 #if 0
@@ -6703,7 +6703,7 @@ add_string:
        case '<':
        case '>':
          {
-           if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || posixly_correct)
+           if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & W_DQUOTE) || posixly_correct)
              {
                sindex--;       /* add_character: label increments sindex */
                goto add_character;
@@ -6769,7 +6769,7 @@ add_string:
          /* If the word isn't supposed to be tilde expanded, or we're not
             at the start of a word or after an unquoted : or = in an
             assignment statement, we don't do tilde expansion. */
-         if ((word->flags & W_NOTILDE) ||
+         if ((word->flags & (W_NOTILDE|W_DQUOTE)) ||
              (sindex > 0 && ((word->flags & W_ITILDE) == 0)) ||
              (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
            {
@@ -6896,7 +6896,11 @@ add_twochars:
          break;
 
        case '"':
-         if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
+#if 0
+         if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE))
+#else
+         if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
+#endif
            goto add_character;
 
          t_index = ++sindex;
@@ -7042,7 +7046,7 @@ add_twochars:
          /* break; */
 
        case '\'':
-         if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
+         if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE))
            goto add_character;
 
          t_index = ++sindex;
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 c74baa48ab87af2c1780685bf8ff2ce6c5a4caf1..44941103f948018addc35209dc908a563b468c90 100644 (file)
@@ -14,24 +14,24 @@ fx is a function
 fx () 
 { 
     i=0;
-    for ((1 ; i < 3 ; i++ ))
+    for ((1; i < 3; i++ ))
     do
         echo $i;
     done;
-    for ((i=0 ; 1 ; i++ ))
+    for ((i=0; 1; i++ ))
     do
         if (( i >= 3 )); then
             break;
         fi;
         echo $i;
     done;
-    for ((i=0 ; i<3 ; 1))
+    for ((i=0; i<3; 1))
     do
         echo $i;
         (( i++ ));
     done;
     i=0;
-    for ((1 ; 1 ; 1))
+    for ((1; 1; 1))
     do
         if (( i > 2 )); then
             break;
@@ -40,7 +40,7 @@ fx ()
         (( i++ ));
     done;
     i=0;
-    for ((1 ; 1 ; 1))
+    for ((1; 1; 1))
     do
         if (( i > 2 )); then
             break;
index 2659aacecc207dc608e2c38fc6f4cc352a2381eb..80b01cf7ec045d1fe4729e4810060116038950b6 100644 (file)
@@ -24,5 +24,5 @@ f3 ()
 echo $(echo hi)
 echo ho
 echo off to work we go
-declare -a uu='([0]="" [1]="kghfjk" [2]="jkfzuk" [3]="i\
+declare -a uu='([0]="" [1]="kghfjk" [2]="jkfzuk" [3]="i
 ")'
diff --git a/tests/herestr.right~ b/tests/herestr.right~
new file mode 100644 (file)
index 0000000..2659aac
--- /dev/null
@@ -0,0 +1,28 @@
+abcde
+yo
+hot damn
+what a fabulous window treatment
+double"quote
+onetwothree
+first second third
+f1 () 
+{ 
+    cat <<< "abcde";
+    cat <<< "yo";
+    cat <<< "$a $b";
+    cat <<< 'what a fabulous window treatment';
+    cat <<< 'double"quote'
+}
+f2 () 
+{ 
+    cat <<< onetwothree
+}
+f3 () 
+{ 
+    cat <<< "$@"
+}
+echo $(echo hi)
+echo ho
+echo off to work we go
+declare -a uu='([0]="" [1]="kghfjk" [2]="jkfzuk" [3]="i\
+")'