]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20060727 snapshot
authorChet Ramey <chet.ramey@case.edu>
Sun, 4 Dec 2011 03:51:04 +0000 (22:51 -0500)
committerChet Ramey <chet.ramey@case.edu>
Sun, 4 Dec 2011 03:51:04 +0000 (22:51 -0500)
76 files changed:
CWRU/CWRU.chlog
CWRU/CWRU.chlog~
Makefile.in
Makefile.in~
arrayfunc.c
bashline.c
bashline.c~
builtins/caller.def
builtins/cd.def
builtins/cd.def~ [new file with mode: 0644]
builtins/common.c
builtins/echo.def
builtins/echo.def~ [new file with mode: 0644]
builtins/evalfile.c
builtins/evalfile.c~
builtins/evalstring.c
builtins/evalstring.c~ [new file with mode: 0644]
builtins/fc.def
builtins/fc.def~ [new file with mode: 0644]
builtins/printf.def
builtins/printf.def~ [new file with mode: 0644]
builtins/set.def
builtins/source.def
builtins/source.def~ [new file with mode: 0644]
builtins/suspend.def
builtins/suspend.def~ [new file with mode: 0644]
builtins/trap.def
builtins/wait.def
builtins/wait.def~ [new file with mode: 0644]
error.c
error.c~ [new file with mode: 0644]
externs.h
externs.h~
general.c
general.c~
input.c
input.c~ [new file with mode: 0644]
jobs.c
jobs.c~
lib/glob/glob.c
lib/glob/smatch.c
lib/readline/bind.c
lib/readline/complete.c
lib/readline/complete.c~
lib/readline/display.c
lib/readline/display.c~
lib/readline/histexpand.c
lib/readline/histexpand.c~ [new file with mode: 0644]
lib/readline/input.c
lib/readline/input.c~
lib/readline/text.c
lib/readline/text.c~
lib/readline/vi_mode.c
lib/readline/vi_mode.c~
lib/sh/netopen.c
lib/sh/netopen.c~ [new file with mode: 0644]
lib/sh/shmatch.c
lib/sh/shmatch.c~ [new file with mode: 0644]
lib/sh/strtrans.c
lib/sh/tmpfile.c
lib/sh/tmpfile.c~ [new file with mode: 0644]
lib/sh/winsize.c
lib/sh/winsize.c~ [new file with mode: 0644]
locale.c
make_cmd.c
parse.y
parse.y~
pcomplete.c
subst.c
subst.c~
trap.c
trap.c~
unwind_prot.c
unwind_prot.c~ [new file with mode: 0644]
variables.c
variables.h

index c0eeaa1156aadb3baa8523cf3f6c6605b1b3105a..1f9dc27a4399a7c954995c04faeeae65fc845941 100644 (file)
@@ -13516,7 +13516,7 @@ lib/readline/display.c
                                    7/5
                                    ---
 builtins/printf.def
-       - add echo's write error handling to printf.  Suggested by
+       - add more of echo's write error handling to printf.  Suggested by
          martin.wilck@fujitsu-siemens.com
 
                                    7/7
@@ -13566,3 +13566,17 @@ lib/malloc/{stats,table}.h
 lib/termcap/{termcap,tparam}.c
        - include <string.h> and provide macro replacement for bcopy if
          necessary
+
+                                  7/27
+                                  ----
+lib/readline/histexpand.c
+       - add support for `<<<' here-string redirection operator to
+         history_tokenize_word.  Bug reported by agriffis@gentoo.org
+
+externs.h      
+       - don't add prototype for strerror() if HAVE_STRERROR defined
+
+                                  7/29
+                                  ----
+subst.c
+       - in list_string, use `string' instead of `s' -- s is not initialized
index 56fb9dce9936010d2278b340fa32b77a2b15800d..154072d419ecf7e1f121a19ff37cc4361fa06041 100644 (file)
@@ -13516,7 +13516,7 @@ lib/readline/display.c
                                    7/5
                                    ---
 builtins/printf.def
-       - add echo's write error handling to printf.  Suggested by
+       - add more of echo's write error handling to printf.  Suggested by
          martin.wilck@fujitsu-siemens.com
 
                                    7/7
@@ -13562,3 +13562,16 @@ lib/readline/display.c
                                   ----
 lib/malloc/{stats,table}.h
        - include <string.h> for prototypes for memset, strlen
+
+lib/termcap/{termcap,tparam}.c
+       - include <string.h> and provide macro replacement for bcopy if
+         necessary
+
+                                  7/27
+                                  ----
+lib/readline/histexpand.c
+       - add support for `<<<' here-string redirection operator to
+         history_tokenize_word.  Bug reported by agriffis@gentoo.org
+
+externs.h      
+       - don't add prototype for strerror() if HAVE_STRERROR defined
index 8220f3b8e3657c5c0e2b744206f10f9d9d61d107..f753631005b3dce2d335663bd84f050d615d7523 100644 (file)
@@ -147,8 +147,11 @@ LDFLAGS_FOR_BUILD = $(LDFLAGS)
 
 INCLUDES = -I. @RL_INCLUDE@ -I$(srcdir) -I$(BASHINCDIR) -I$(LIBSRC) $(INTL_INC)
 
-GCC_LINT_FLAGS = -Wall -Wshadow -Wpointer-arith -Wcast-qual \
-                -Wcast-align -Wstrict-prototypes -Wconversion \
+# Maybe add: -Wextra
+GCC_LINT_FLAGS = -O -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wno-parentheses \
+                -Wcast-align -Wstrict-prototypes -Wconversion -Wformat \
+                -Wformat-nonliteral -Wmissing-braces -Wuninitialized \
+                -Wmissing-declarations  -Winline \
                 -Wmissing-prototypes -Wtraditional -Wredundant-decls -pedantic
 
 GCC_LINT_CFLAGS = $(BASE_CCFLAGS) $(CPPFLAGS) $(GCC_LINT_FLAGS)
index 02e8e2c52b6b68693a16c10bf423b11146086866..35cd448e6febf27c8c52376ec8d22495858b2958 100644 (file)
@@ -147,8 +147,11 @@ LDFLAGS_FOR_BUILD = $(LDFLAGS)
 
 INCLUDES = -I. @RL_INCLUDE@ -I$(srcdir) -I$(BASHINCDIR) -I$(LIBSRC) $(INTL_INC)
 
-GCC_LINT_FLAGS = -Wall -Wshadow -Wpointer-arith -Wcast-qual \
-                -Wcast-align -Wstrict-prototypes -Wconversion \
+# Maybe add: -Wextra
+GCC_LINT_FLAGS = -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wno-parentheses \
+                -Wcast-align -Wstrict-prototypes -Wconversion -Wformat \
+                -Wformat-nonliteral -Wmissing-braces -Wuninitialized \
+                -Wmissing-declarations  -Winline \
                 -Wmissing-prototypes -Wtraditional -Wredundant-decls -pedantic
 
 GCC_LINT_CFLAGS = $(BASE_CCFLAGS) $(CPPFLAGS) $(GCC_LINT_FLAGS)
@@ -201,7 +204,7 @@ SHLIB_SOURCE =      ${SH_LIBSRC}/clktck.c ${SH_LIBSRC}/getcwd.c \
                ${SH_LIBSRC}/memset.c ${SH_LIBSRC}/xstrchr.c \
                ${SH_LIBSRC}/zcatfd.c ${SH_LIBSRC}/shmatch.c \
                ${SH_LIBSRC}/strnlen.c ${SH_LIBSRC}/winsize.c \
-               ${SH_LIBSRC}/shaccess.c
+               ${SH_LIBSRC}/eaccess.c ${SH_LIBSRC}/wcsdup.c
 
 SHLIB_LIB = -lsh
 SHLIB_LIBNAME = libsh.a
@@ -499,7 +502,7 @@ CREATED_SUPPORT = signames.h recho$(EXEEXT) zecho$(EXEEXT) printenv$(EXEEXT) \
                  tests/recho$(EXEEXT) tests/zecho$(EXEEXT) \
                  tests/printenv$(EXEEXT) mksignames$(EXEEXT) lsignames.h \
                  mksyntax${EXEEXT} syntax.c $(VERSPROG) $(VERSOBJ) \
-                 buildversion.o mksignames.o signames.o
+                 buildversion.o mksignames.o signames.o buildsignames.o
 CREATED_CONFIGURE = config.h config.cache config.status config.log \
                    stamp-h po/POTFILES
 CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \
index 58f1c1b7c20ec8a5afd1a3ddaa6a411cfa2482e2..48a099dde0ee1676f7495281aa2d3c1287eb24dd 100644 (file)
@@ -273,7 +273,6 @@ expand_compound_array_assignment (value, flags)
   WORD_LIST *list, *nlist;
   char *val;
   int ni;
-  arrayind_t ind, last_ind;
 
   /* I don't believe this condition is ever true any more. */
   if (*value == '(')   /*)*/
index 249f43b7ad627cfbdaae2fcb0627d13056671124..809fe32b636f5a3f4deb0a2b65375da14ef549bc 100644 (file)
@@ -1461,7 +1461,9 @@ command_word_completion_function (hint_text, state)
   else
     {
       int match, freetemp;
-      char *temp;
+#if 0
+      char *temp;              /* shadows previous declaration */
+#endif
 
       if (absolute_program (hint))
        {
@@ -1760,8 +1762,9 @@ bash_servicename_completion_function (text, state)
       if (snamelen == 0 || (STREQN (sname, srvent->s_name, snamelen)))
        break;
       /* Not primary, check aliases */
-      for (alist = srvent->s_aliases; aentry = *alist; alist++)
+      for (alist = srvent->s_aliases; *alist; alist++)
        {
+         aentry = *alist;
          if (STREQN (sname, aentry, snamelen))
            {
              afound = 1;
index a515f63b219f352cefab939b1a3813b6ba74d92d..4b11de926f3a427aa8ec393527e3423f94fe9e97 100644 (file)
@@ -1254,7 +1254,6 @@ command_word_completion_function (hint_text, state)
 
       mapping_over = searching_path = 0;
       hint_is_dir = CMD_IS_DIR (hint_text);
-
       val = (char *)NULL;
 
       temp = rl_variable_value ("completion-ignore-case");
@@ -1462,7 +1461,9 @@ command_word_completion_function (hint_text, state)
   else
     {
       int match, freetemp;
-      char *temp;
+#if 0
+      char *temp;              /* shadows previous declaration */
+#endif
 
       if (absolute_program (hint))
        {
index 5142cab9a68e5e7dd4618b3eb5f8d724070f467f..b6e8238829dc37eb3fda053dfd8a44595486a6a1 100644 (file)
@@ -76,7 +76,6 @@ caller_builtin (list)
   SHELL_VAR *funcname_v, *bash_source_v, *bash_lineno_v;
   ARRAY *funcname_a, *bash_source_a, *bash_lineno_a;
   char *funcname_s, *source_s, *lineno_s;
-  ARRAY_ELEMENT *ae;
   intmax_t num;
 
   GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a);
index 025e4f5e1f1209afe6700899aa7d89ec0ef128be..54e328e4f5fda9b32d57c4ec1ee47f04a76afdec 100644 (file)
@@ -60,6 +60,7 @@ extern char *bash_getcwd_errstr;
 
 static int bindpwd __P((int));
 static void setpwd __P((char *));
+static char *resetpwd __P((char *));
 static int change_to_directory __P((char *, int));
 
 static char *cdspell __P((char *));
diff --git a/builtins/cd.def~ b/builtins/cd.def~
new file mode 100644 (file)
index 0000000..025e4f5
--- /dev/null
@@ -0,0 +1,525 @@
+This file is cd.def, from which is created cd.c.  It implements the
+builtins "cd" and "pwd" in Bash.
+
+Copyright (C) 1987-2005 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 cd.c
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+#  ifdef _MINIX
+#    include <sys/types.h>
+#  endif
+#  include <unistd.h>
+#endif
+
+#include "../bashtypes.h"
+#include "posixdir.h"
+#include "posixstat.h"
+#ifndef _MINIX
+#include <sys/param.h>
+#endif
+
+#include <stdio.h>
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include <errno.h>
+#include <tilde/tilde.h>
+
+#include "../shell.h"
+#include "../flags.h"
+#include "maxpath.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+extern int posixly_correct;
+extern int array_needs_making;
+extern char *bash_getcwd_errstr;
+
+static int bindpwd __P((int));
+static void setpwd __P((char *));
+static int change_to_directory __P((char *, int));
+
+static char *cdspell __P((char *));
+
+/* Change this to 1 to get cd spelling correction by default. */
+int cdspelling = 0;
+
+int cdable_vars;
+
+$BUILTIN cd
+$FUNCTION cd_builtin
+$SHORT_DOC cd [-L|-P] [dir]
+Change the current directory to DIR.  The variable $HOME is the
+default DIR.  The variable CDPATH defines the search path for
+the directory containing DIR.  Alternative directory names in CDPATH
+are separated by a colon (:).  A null directory name is the same as
+the current directory, i.e. `.'.  If DIR begins with a slash (/),
+then CDPATH is not used.  If the directory is not found, and the
+shell option `cdable_vars' is set, then try the word as a variable
+name.  If that variable has a value, then cd to the value of that
+variable.  The -P option says to use the physical directory structure
+instead of following symbolic links; the -L option forces symbolic links
+to be followed.
+$END
+
+/* Just set $PWD, don't change OLDPWD.  Used by `pwd -P' in posix mode. */
+static void
+setpwd (dirname)
+     char *dirname;
+{
+  int old_anm;
+  SHELL_VAR *tvar;
+
+  old_anm = array_needs_making;
+  tvar = bind_variable ("PWD", dirname ? dirname : "", 0);
+  if (old_anm == 0 && array_needs_making && exported_p (tvar))
+    {
+      update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
+      array_needs_making = 0;
+    }
+}
+
+static int
+bindpwd (no_symlinks)
+     int no_symlinks;
+{
+  char *dirname, *pwdvar;
+  int old_anm;
+  SHELL_VAR *tvar;
+
+#define tcwd the_current_working_directory
+  dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd)
+                : get_working_directory ("cd");
+#undef tcwd
+
+  old_anm = array_needs_making;
+  pwdvar = get_string_value ("PWD");
+
+  tvar = bind_variable ("OLDPWD", pwdvar, 0);
+  if (old_anm == 0 && array_needs_making && exported_p (tvar))
+    {
+      update_export_env_inplace ("OLDPWD=", 7, pwdvar);
+      array_needs_making = 0;
+    }
+
+  setpwd (dirname);
+
+  if (dirname && dirname != the_current_working_directory)
+    free (dirname);
+
+  return (EXECUTION_SUCCESS);
+}
+
+/* Call get_working_directory to reset the value of
+   the_current_working_directory () */
+static char *
+resetpwd (caller)
+     char *caller;
+{
+  char *tdir;
+      
+  FREE (the_current_working_directory);
+  the_current_working_directory = (char *)NULL;
+  tdir = get_working_directory (caller);
+  return (tdir);
+}
+
+#define LCD_DOVARS     0x001
+#define LCD_DOSPELL    0x002
+#define LCD_PRINTPATH  0x004
+#define LCD_FREEDIRNAME        0x010
+
+/* This builtin is ultimately the way that all user-visible commands should
+   change the current working directory.  It is called by cd_to_string (),
+   so the programming interface is simple, and it handles errors and
+   restrictions properly. */
+int
+cd_builtin (list)
+     WORD_LIST *list;
+{
+  char *dirname, *cdpath, *path, *temp;
+  int path_index, no_symlinks, opt, lflag;
+
+#if defined (RESTRICTED_SHELL)
+  if (restricted)
+    {
+      sh_restricted ((char *)NULL);
+      return (EXECUTION_FAILURE);
+    }
+#endif /* RESTRICTED_SHELL */
+
+  no_symlinks = no_symbolic_links;
+  reset_internal_getopt ();
+  while ((opt = internal_getopt (list, "LP")) != -1)
+    {
+      switch (opt)
+       {
+       case 'P':
+         no_symlinks = 1;
+         break;
+       case 'L':
+         no_symlinks = 0;
+         break;
+       default:
+         builtin_usage ();
+         return (EXECUTION_FAILURE);
+       }
+    }
+  list = loptend;
+
+  lflag = (cdable_vars ? LCD_DOVARS : 0) |
+         ((interactive && cdspelling) ? LCD_DOSPELL : 0);
+
+  if (list == 0)
+    {
+      /* `cd' without arguments is equivalent to `cd $HOME' */
+      dirname = get_string_value ("HOME");
+
+      if (dirname == 0)
+       {
+         builtin_error (_("HOME not set"));
+         return (EXECUTION_FAILURE);
+       }
+      lflag = 0;
+    }
+  else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
+    {
+      /* This is `cd -', equivalent to `cd $OLDPWD' */
+      dirname = get_string_value ("OLDPWD");
+
+      if (dirname == 0)
+       {
+         builtin_error (_("OLDPWD not set"));
+         return (EXECUTION_FAILURE);
+       }
+#if 0
+      lflag = interactive ? LCD_PRINTPATH : 0;
+#else
+      lflag = LCD_PRINTPATH;           /* According to SUSv3 */
+#endif
+    }
+  else if (absolute_pathname (list->word->word))
+    dirname = list->word->word;
+  else if (cdpath = get_string_value ("CDPATH"))
+    {
+      dirname = list->word->word;
+
+      /* Find directory in $CDPATH. */
+      path_index = 0;
+      while (path = extract_colon_unit (cdpath, &path_index))
+       {
+         /* OPT is 1 if the path element is non-empty */
+         opt = path[0] != '\0';
+         temp = sh_makepath (path, dirname, MP_DOTILDE);
+         free (path);
+
+         if (change_to_directory (temp, no_symlinks))
+           {
+             /* POSIX.2 says that if a nonempty directory from CDPATH
+                is used to find the directory to change to, the new
+                directory name is echoed to stdout, whether or not
+                the shell is interactive. */
+             if (opt && (path = no_symlinks ? temp : the_current_working_directory))
+               printf ("%s\n", path);
+
+             free (temp);
+#if 0
+             /* Posix.2 says that after using CDPATH, the resultant
+                value of $PWD will not contain `.' or `..'. */
+             return (bindpwd (posixly_correct || no_symlinks));
+#else
+             return (bindpwd (no_symlinks));
+#endif
+           }
+         else
+           free (temp);
+       }
+
+      /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
+        try the current directory, so we just punt now with an error
+        message if POSIXLY_CORRECT is non-zero.  The check for cdpath[0]
+        is so we don't mistakenly treat a CDPATH value of "" as not
+        specifying the current directory. */
+      if (posixly_correct && cdpath[0])
+       {
+         builtin_error ("%s: %s", dirname, strerror (ENOENT));
+         return (EXECUTION_FAILURE);
+       }
+    }
+  else
+    dirname = list->word->word;
+
+  /* When we get here, DIRNAME is the directory to change to.  If we
+     chdir successfully, just return. */
+  if (change_to_directory (dirname, no_symlinks))
+    {
+      if (lflag & LCD_PRINTPATH)
+       printf ("%s\n", dirname);
+      return (bindpwd (no_symlinks));
+    }
+
+  /* If the user requests it, then perhaps this is the name of
+     a shell variable, whose value contains the directory to
+     change to. */
+  if (lflag & LCD_DOVARS)
+    {
+      temp = get_string_value (dirname);
+      if (temp && change_to_directory (temp, no_symlinks))
+       {
+         printf ("%s\n", temp);
+         return (bindpwd (no_symlinks));
+       }
+    }
+
+  /* If the user requests it, try to find a directory name similar in
+     spelling to the one requested, in case the user made a simple
+     typo.  This is similar to the UNIX 8th and 9th Edition shells. */
+  if (lflag & LCD_DOSPELL)
+    {
+      temp = cdspell (dirname);
+      if (temp && change_to_directory (temp, no_symlinks))
+       {
+         printf ("%s\n", temp);
+         return (bindpwd (no_symlinks));
+       }
+      else
+       FREE (temp);
+    }
+
+  builtin_error ("%s: %s", dirname, strerror (errno));
+  return (EXECUTION_FAILURE);
+}
+
+$BUILTIN pwd
+$FUNCTION pwd_builtin
+$SHORT_DOC pwd [-LP]
+Print the current working directory.  With the -P option, pwd prints
+the physical directory, without any symbolic links; the -L option
+makes pwd follow symbolic links.
+$END
+
+/* Non-zero means that pwd always prints the physical directory, without
+   symbolic links. */
+static int verbatim_pwd;
+
+/* Print the name of the current working directory. */
+int
+pwd_builtin (list)
+     WORD_LIST *list;
+{
+  char *directory;
+  int opt, pflag;
+
+  verbatim_pwd = no_symbolic_links;
+  pflag = 0;
+  reset_internal_getopt ();
+  while ((opt = internal_getopt (list, "LP")) != -1)
+    {
+      switch (opt)
+       {
+       case 'P':
+         verbatim_pwd = pflag = 1;
+         break;
+       case 'L':
+         verbatim_pwd = 0;
+         break;
+       default:
+         builtin_usage ();
+         return (EXECUTION_FAILURE);
+       }
+    }
+  list = loptend;
+
+#define tcwd the_current_working_directory
+
+  directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
+                  : get_working_directory ("pwd");
+
+  /* Try again using getcwd() if canonicalization fails (for instance, if
+     the file system has changed state underneath bash). */
+  if ((tcwd && directory == 0) ||
+      (posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0))
+    directory = resetpwd ("pwd");
+
+#undef tcwd
+
+  if (directory)
+    {
+      printf ("%s\n", directory);
+      /* This is dumb but posix-mandated. */
+      if (posixly_correct && pflag)
+       setpwd (directory);
+      if (directory != the_current_working_directory)
+       free (directory);
+      fflush (stdout);
+      if (ferror (stdout))
+       {
+         sh_wrerror ();
+         clearerr (stdout);
+         return (EXECUTION_FAILURE);
+       }
+
+      return (EXECUTION_SUCCESS);
+    }
+  else
+    return (EXECUTION_FAILURE);
+}
+
+/* Do the work of changing to the directory NEWDIR.  Handle symbolic
+   link following, etc.  This function *must* return with
+   the_current_working_directory either set to NULL (in which case
+   getcwd() will eventually be called), or set to a string corresponding
+   to the working directory.  Return 1 on success, 0 on failure. */
+
+static int
+change_to_directory (newdir, nolinks)
+     char *newdir;
+     int nolinks;
+{
+  char *t, *tdir;
+  int err, canon_failed, r, ndlen, dlen;
+
+  tdir = (char *)NULL;
+
+  if (the_current_working_directory == 0)
+    {
+      t = get_working_directory ("chdir");
+      FREE (t);
+    }
+
+  t = make_absolute (newdir, the_current_working_directory);
+
+  /* TDIR is either the canonicalized absolute pathname of NEWDIR
+     (nolinks == 0) or the absolute physical pathname of NEWDIR
+     (nolinks != 0). */
+  tdir = nolinks ? sh_physpath (t, 0)
+                : sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
+
+  ndlen = strlen (newdir);
+  dlen = strlen (t);
+
+  /* Use the canonicalized version of NEWDIR, or, if canonicalization
+     failed, use the non-canonical form. */
+  canon_failed = 0;
+  if (tdir && *tdir)
+    free (t);
+  else
+    {
+      FREE (tdir);
+      tdir = t;
+      canon_failed = 1;
+    }
+
+  /* In POSIX mode, if we're resolving symlinks logically and sh_canonpath
+     returns NULL (because it checks the path, it will return NULL if the
+     resolved path doesn't exist), fail immediately. */
+  if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX))
+    {
+#if defined ENAMETOOLONG
+      if (errno != ENOENT && errno != ENAMETOOLONG)
+#else
+      if (errno != ENOENT)
+#endif
+       errno = ENOTDIR;
+      free (tdir);
+      return (0);
+    }
+
+  /* If the chdir succeeds, update the_current_working_directory. */
+  if (chdir (nolinks ? newdir : tdir) == 0)
+    {
+      /* If canonicalization failed, but the chdir succeeded, reset the
+        shell's idea of the_current_working_directory. */
+      if (canon_failed)
+       {
+         t = resetpwd ("cd");
+         if (t == 0)
+           set_working_directory (tdir);
+       }
+      else
+       set_working_directory (tdir);
+
+      free (tdir);
+      return (1);
+    }
+
+  /* We failed to change to the appropriate directory name.  If we tried
+     what the user passed (nolinks != 0), punt now. */
+  if (nolinks)
+    {
+      free (tdir);
+      return (0);
+    }
+
+  err = errno;
+
+  /* We're not in physical mode (nolinks == 0), but we failed to change to
+     the canonicalized directory name (TDIR).  Try what the user passed
+     verbatim. If we succeed, reinitialize the_current_working_directory. */
+  if (chdir (newdir) == 0)
+    {
+      t = resetpwd ("cd");
+      if (t == 0)
+       set_working_directory (tdir);
+      else
+       free (t);
+
+      r = 1;
+    }
+  else
+    {
+      errno = err;
+      r = 0;
+    }
+
+  free (tdir);
+  return r;
+}
+
+/* Code for cd spelling correction.  Original patch submitted by
+   Neil Russel (caret@c-side.com). */
+
+static char *
+cdspell (dirname)
+     char *dirname;
+{
+  int n;
+  char *guess;
+
+  n = (strlen (dirname) * 3 + 1) / 2 + 1;
+  guess = (char *)xmalloc (n);
+
+  switch (spname (dirname, guess))
+    {
+    case -1:
+    default:
+      free (guess);
+      return (char *)NULL;
+    case 0:
+    case 1:
+      return guess;
+    }
+}
index 9d8f09ab49768dd3127eda66eab1ae90c561e372..7b9613e1fae749943ef1b733ffc584d508e270b1 100644 (file)
@@ -467,9 +467,6 @@ char *
 get_working_directory (for_whom)
      char *for_whom;
 {
-  char *directory;
-  size_t dsize;
-
   if (no_symbolic_links)
     {
       FREE (the_current_working_directory);
index 6792659a7d214b34e562cbaa3021dc8a41a06fa1..0effc89454433248086c79e455eecca370b845ec 100644 (file)
@@ -31,6 +31,8 @@ $PRODUCES echo.c
 #include <stdio.h>
 #include "../shell.h"
 
+#include "common.h"
+
 $BUILTIN echo
 $FUNCTION echo_builtin
 $DEPENDS_ON V9_ECHO
diff --git a/builtins/echo.def~ b/builtins/echo.def~
new file mode 100644 (file)
index 0000000..6792659
--- /dev/null
@@ -0,0 +1,183 @@
+This file is echo.def, from which is created echo.c.
+It implements the builtin "echo" in Bash.
+
+Copyright (C) 1987-2002 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 echo.c
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include "../bashansi.h"
+
+#include <stdio.h>
+#include "../shell.h"
+
+$BUILTIN echo
+$FUNCTION echo_builtin
+$DEPENDS_ON V9_ECHO
+$SHORT_DOC echo [-neE] [arg ...]
+Output the ARGs.  If -n is specified, the trailing newline is
+suppressed.  If the -e option is given, interpretation of the
+following backslash-escaped characters is turned on:
+       \a      alert (bell)
+       \b      backspace
+       \c      suppress trailing newline
+       \E      escape character
+       \f      form feed
+       \n      new line
+       \r      carriage return
+       \t      horizontal tab
+       \v      vertical tab
+       \\      backslash
+       \num    the character whose ASCII code is NUM (octal).
+
+You can explicitly turn off the interpretation of the above characters
+with the -E option.
+$END
+
+$BUILTIN echo
+$FUNCTION echo_builtin
+$DEPENDS_ON !V9_ECHO
+$SHORT_DOC echo [-n] [arg ...]
+Output the ARGs.  If -n is specified, the trailing newline is suppressed.
+$END
+
+#if defined (V9_ECHO)
+#  define VALID_ECHO_OPTIONS "neE"
+#else /* !V9_ECHO */
+#  define VALID_ECHO_OPTIONS "n"
+#endif /* !V9_ECHO */
+
+/* System V machines already have a /bin/sh with a v9 behaviour.  We
+   give Bash the identical behaviour for these machines so that the
+   existing system shells won't barf.  Regrettably, the SUS v2 has
+   standardized the Sys V echo behavior.  This variable is external
+   so that we can have a `shopt' variable to control it at runtime. */
+#if defined (DEFAULT_ECHO_TO_XPG) || defined (STRICT_POSIX)
+int xpg_echo = 1;
+#else
+int xpg_echo = 0;
+#endif /* DEFAULT_ECHO_TO_XPG */
+
+extern int posixly_correct;
+
+/* Print the words in LIST to standard output.  If the first word is
+   `-n', then don't print a trailing newline.  We also support the
+   echo syntax from Version 9 Unix systems. */
+int
+echo_builtin (list)
+     WORD_LIST *list;
+{
+  int display_return, do_v9, i, len;
+  char *temp, *s;
+
+  do_v9 = xpg_echo;
+  display_return = 1;
+
+  if (posixly_correct && xpg_echo)
+    goto just_echo;
+
+  for (; list && (temp = list->word->word) && *temp == '-'; list = list->next)
+    {
+      /* If it appears that we are handling options, then make sure that
+        all of the options specified are actually valid.  Otherwise, the
+        string should just be echoed. */
+      temp++;
+
+      for (i = 0; temp[i]; i++)
+       {
+         if (strchr (VALID_ECHO_OPTIONS, temp[i]) == 0)
+           break;
+       }
+
+      /* echo - and echo -<nonopt> both mean to just echo the arguments. */
+      if (*temp == 0 || temp[i])
+       break;
+
+      /* All of the options in TEMP are valid options to ECHO.
+        Handle them. */
+      while (i = *temp++)
+       {
+         switch (i)
+           {
+           case 'n':
+             display_return = 0;
+             break;
+#if defined (V9_ECHO)
+           case 'e':
+             do_v9 = 1;
+             break;
+           case 'E':
+             do_v9 = 0;
+             break;
+#endif /* V9_ECHO */
+           default:
+             goto just_echo;   /* XXX */
+           }
+       }
+    }
+
+just_echo:
+
+  clearerr (stdout);   /* clear error before writing and testing success */
+
+  while (list)
+    {
+      i = len = 0;
+      temp = do_v9 ? ansicstr (list->word->word, STRLEN (list->word->word), 1, &i, &len)
+                  : list->word->word;
+      if (temp)
+       {
+         if (do_v9)
+           {
+             for (s = temp; len > 0; len--)
+               putchar (*s++);
+           }
+         else      
+           printf ("%s", temp);
+#if defined (SunOS5)
+         fflush (stdout);      /* Fix for bug in SunOS 5.5 printf(3) */
+#endif
+       }
+      if (do_v9 && temp)
+       free (temp);
+      list = list->next;
+      if (i)
+       {
+         display_return = 0;
+         break;
+       }
+      if (list)
+       putchar(' ');
+    }
+
+  if (display_return)
+    putchar ('\n');
+  fflush (stdout);
+  if (ferror (stdout))
+    {
+      sh_wrerror ();
+      clearerr (stdout);
+      return (EXECUTION_FAILURE);
+    }
+  return (EXECUTION_SUCCESS);
+}
index 81be017bd36b44a66144c5f74cd2b7da7f313ec2..d05bc7bb369d854014024b75d5bf29b66c69a4d5 100644 (file)
@@ -63,7 +63,7 @@ extern int errno;
 #define FEVAL_NOPUSHARGS       0x100
 
 extern int posixly_correct;
-extern int indirection_level, startup_state, subshell_environment;
+extern int indirection_level, subshell_environment;
 extern int return_catch_flag, return_catch_value;
 extern int last_command_exit_value;
 
index 75314e2bfc89e8712ea5de824881eb5a2f2ada06..81be017bd36b44a66144c5f74cd2b7da7f313ec2 100644 (file)
@@ -201,7 +201,6 @@ file_error_and_exit:
 #if defined (ARRAY_VARS)
   array_push (bash_source_a, (char *)filename);
   t = itos (executing_line_number ());
-itrace("evalfile: pushing %s to bash_lineno array");
   array_push (bash_lineno_a, t);
   free (t);
   array_push (funcname_a, "source");   /* not exactly right */
index 04afac3d75c58aae6f6ce605ae3dd4bb5dbe87e4..36f0ad398c33fcb163dba45d9038f083a9746d60 100644 (file)
@@ -56,7 +56,7 @@ extern int errno;
 
 #define IS_BUILTIN(s)  (builtin_address_internal(s, 0) != (struct builtin *)NULL)
 
-extern int indirection_level, startup_state, subshell_environment;
+extern int indirection_level, subshell_environment;
 extern int line_number;
 extern int last_command_exit_value;
 extern int running_trap;
@@ -316,9 +316,8 @@ static int
 cat_file (r)
      REDIRECT *r;
 {
-  char lbuf[128], *fn;
+  char *fn;
   int fd, rval;
-  ssize_t nr;
 
   if (r->instruction != r_input_direction)
     return -1;
diff --git a/builtins/evalstring.c~ b/builtins/evalstring.c~
new file mode 100644 (file)
index 0000000..610fa9c
--- /dev/null
@@ -0,0 +1,352 @@
+/* Evaluate a string as one or more shell commands.
+
+   Copyright (C) 1996-2005 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   Bash is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2, or (at your option) any later
+   version.
+
+   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
+   
+   You should have received a copy of the GNU General Public License along
+   with Bash; see the file COPYING.  If not, write to the Free Software
+   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+#  ifdef _MINIX
+#    include <sys/types.h>
+#  endif
+#  include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <signal.h>
+
+#include <errno.h>
+
+#include "filecntl.h"
+#include "../bashansi.h"
+
+#include "../shell.h"
+#include "../jobs.h"
+#include "../builtins.h"
+#include "../flags.h"
+#include "../input.h"
+#include "../execute_cmd.h"
+#include "../redir.h"
+#include "../trap.h"
+
+#if defined (HISTORY)
+#  include "../bashhist.h"
+#endif
+
+#include "common.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+#define IS_BUILTIN(s)  (builtin_address_internal(s, 0) != (struct builtin *)NULL)
+
+extern int indirection_level, startup_state, subshell_environment;
+extern int line_number;
+extern int last_command_exit_value;
+extern int running_trap;
+extern int loop_level;
+extern int posixly_correct;
+
+int parse_and_execute_level = 0;
+
+static int cat_file __P((REDIRECT *));
+
+/* How to force parse_and_execute () to clean up after itself. */
+void
+parse_and_execute_cleanup ()
+{
+  if (running_trap)
+    {
+      run_trap_cleanup (running_trap - 1);
+      unfreeze_jobs_list ();
+    }
+  run_unwind_frame ("parse_and_execute_top");
+}
+
+/* Parse and execute the commands in STRING.  Returns whatever
+   execute_command () returns.  This frees STRING.  FLAGS is a
+   flags word; look in common.h for the possible values.  Actions
+   are:
+       (flags & SEVAL_NONINT) -> interactive = 0;
+       (flags & SEVAL_INTERACT) -> interactive = 1;
+       (flags & SEVAL_NOHIST) -> call bash_history_disable ()
+       (flags & SEVAL_NOFREE) -> don't free STRING when finished
+       (flags & SEVAL_RESETLINE) -> reset line_number to 1
+*/
+
+int
+parse_and_execute (string, from_file, flags)
+     char *string;
+     const char *from_file;
+     int flags;
+{
+  int code, x, lreset;
+  volatile int should_jump_to_top_level, last_result;
+  char *orig_string;
+  COMMAND *volatile command;
+
+  orig_string = string;
+  /* Unwind protect this invocation of parse_and_execute (). */
+  begin_unwind_frame ("parse_and_execute_top");
+  unwind_protect_int (parse_and_execute_level);
+  unwind_protect_jmp_buf (top_level);
+  unwind_protect_int (indirection_level);
+  unwind_protect_int (line_number);
+  unwind_protect_int (loop_level);
+  if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
+    unwind_protect_int (interactive);
+
+  lreset = flags & SEVAL_RESETLINE;
+
+#if defined (HISTORY)
+  unwind_protect_int (remember_on_history);    /* can be used in scripts */
+#  if defined (BANG_HISTORY)
+  if (interactive_shell)
+    {
+      unwind_protect_int (history_expansion_inhibited);
+    }
+#  endif /* BANG_HISTORY */
+#endif /* HISTORY */
+
+  if (interactive_shell)
+    {
+      x = get_current_prompt_level ();
+      add_unwind_protect (set_current_prompt_level, x);
+    }
+  
+  add_unwind_protect (pop_stream, (char *)NULL);
+  if (orig_string && ((flags & SEVAL_NOFREE) == 0))
+    add_unwind_protect (xfree, orig_string);
+  end_unwind_frame ();
+
+  parse_and_execute_level++;
+
+  /* Reset the line number if the caller wants us to.  If we don't reset the
+     line number, we have to subtract one, because we will add one just
+     before executing the next command (resetting the line number sets it to
+     0; the first line number is 1). */
+  push_stream (lreset);
+  if (lreset == 0)
+    line_number--;
+    
+  indirection_level++;
+  if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
+    interactive = (flags & SEVAL_NONINT) ? 0 : 1;
+
+#if defined (HISTORY)
+  if (flags & SEVAL_NOHIST)
+    bash_history_disable ();
+#endif /* HISTORY */
+
+  code = should_jump_to_top_level = 0;
+  last_result = EXECUTION_SUCCESS;
+
+  with_input_from_string (string, from_file);
+  while (*(bash_input.location.string))
+    {
+      command = (COMMAND *)NULL;
+
+      if (interrupt_state)
+       {
+         last_result = EXECUTION_FAILURE;
+         break;
+       }
+
+      /* Provide a location for functions which `longjmp (top_level)' to
+        jump to.  This prevents errors in substitution from restarting
+        the reader loop directly, for example. */
+      code = setjmp (top_level);
+
+      if (code)
+       {
+         should_jump_to_top_level = 0;
+         switch (code)
+           {
+           case FORCE_EOF:
+           case ERREXIT:
+           case EXITPROG:
+             if (command)
+               run_unwind_frame ("pe_dispose");
+             /* Remember to call longjmp (top_level) after the old
+                value for it is restored. */
+             should_jump_to_top_level = 1;
+             goto out;
+
+           case DISCARD:
+             if (command)
+               run_unwind_frame ("pe_dispose");
+             last_result = last_command_exit_value = EXECUTION_FAILURE; /* XXX */
+             if (subshell_environment)
+               {
+                 should_jump_to_top_level = 1;
+                 goto out;
+               }
+             else
+               {
+#if 0
+                 dispose_command (command);    /* pe_dispose does this */
+#endif
+                 continue;
+               }
+
+           default:
+             command_error ("parse_and_execute", CMDERR_BADJUMP, code, 0);
+             break;
+           }
+       }
+         
+      if (parse_command () == 0)
+       {
+         if (interactive_shell == 0 && read_but_dont_execute)
+           {
+             last_result = EXECUTION_SUCCESS;
+             dispose_command (global_command);
+             global_command = (COMMAND *)NULL;
+           }
+         else if (command = global_command)
+           {
+             struct fd_bitmap *bitmap;
+
+             bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
+             begin_unwind_frame ("pe_dispose");
+             add_unwind_protect (dispose_fd_bitmap, bitmap);
+             add_unwind_protect (dispose_command, command);    /* XXX */
+
+             global_command = (COMMAND *)NULL;
+
+#if defined (ONESHOT)
+             /*
+              * IF
+              *   we were invoked as `bash -c' (startup_state == 2) AND
+              *   parse_and_execute has not been called recursively AND
+              *   we're not running a trap AND
+              *   we have parsed the full command (string == '\0') AND
+              *   we have a simple command without redirections AND
+              *   the command is not being timed AND
+              *   the command's return status is not being inverted
+              * THEN
+              *   tell the execution code that we don't need to fork
+              */
+             if (startup_state == 2 && parse_and_execute_level == 1 &&
+                 running_trap == 0 &&
+                 *bash_input.location.string == '\0' &&
+                 command->type == cm_simple &&
+                 !command->redirects && !command->value.Simple->redirects &&
+                 ((command->flags & CMD_TIME_PIPELINE) == 0) &&
+                 ((command->flags & CMD_INVERT_RETURN) == 0))
+               {
+                 command->flags |= CMD_NO_FORK;
+                 command->value.Simple->flags |= CMD_NO_FORK;
+               }
+#endif /* ONESHOT */
+
+             /* See if this is a candidate for $( <file ). */
+             if (startup_state == 2 &&
+                 (subshell_environment & SUBSHELL_COMSUB) &&
+                 *bash_input.location.string == '\0' &&
+                 command->type == cm_simple && !command->redirects &&
+                 (command->flags & CMD_TIME_PIPELINE) == 0 &&
+                 command->value.Simple->words == 0 &&
+                 command->value.Simple->redirects &&
+                 command->value.Simple->redirects->next == 0 &&
+                 command->value.Simple->redirects->instruction == r_input_direction)
+               {
+                 int r;
+                 r = cat_file (command->value.Simple->redirects);
+                 last_result = (r < 0) ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
+               }
+             else
+               last_result = execute_command_internal
+                               (command, 0, NO_PIPE, NO_PIPE, bitmap);
+
+             dispose_command (command);
+             dispose_fd_bitmap (bitmap);
+             discard_unwind_frame ("pe_dispose");
+           }
+       }
+      else
+       {
+         last_result = EXECUTION_FAILURE;
+
+         /* Since we are shell compatible, syntax errors in a script
+            abort the execution of the script.  Right? */
+         break;
+       }
+    }
+
+ out:
+
+  run_unwind_frame ("parse_and_execute_top");
+
+  if (interrupt_state && parse_and_execute_level == 0)
+    {
+      /* An interrupt during non-interactive execution in an
+        interactive shell (e.g. via $PROMPT_COMMAND) should
+        not cause the shell to exit. */
+      interactive = interactive_shell;
+      throw_to_top_level ();
+    }
+
+  if (should_jump_to_top_level)
+    jump_to_top_level (code);
+
+  return (last_result);
+}
+
+/* Handle a $( < file ) command substitution.  This expands the filename,
+   returning errors as appropriate, then just cats the file to the standard
+   output. */
+static int
+cat_file (r)
+     REDIRECT *r;
+{
+  char *fn;
+  int fd, rval;
+
+  if (r->instruction != r_input_direction)
+    return -1;
+
+  /* Get the filename. */
+  if (posixly_correct && !interactive_shell)
+    disallow_filename_globbing++;
+  fn = redirection_expand (r->redirectee.filename);
+  if (posixly_correct && !interactive_shell)
+    disallow_filename_globbing--;
+
+  if (fn == 0)
+    {
+      redirection_error (r, AMBIGUOUS_REDIRECT);
+      return -1;
+    }
+
+  fd = open(fn, O_RDONLY);
+  if (fd < 0)
+    {
+      file_error (fn);
+      free (fn);
+      return -1;
+    }
+
+  rval = zcatfd (fd, 1, fn);
+
+  free (fn);
+  close (fd);
+
+  return (rval);
+}
index ebe368326c2480cbeeaaea1055116dcc51fcfe26..101eb008cbd46c7e21548f63f3465fb8c42156c4 100644 (file)
@@ -81,7 +81,6 @@ $END
 extern int errno;
 #endif /* !errno */
 
-extern int echo_input_at_read;
 extern int current_command_line_count;
 extern int literal_history;
 extern int posixly_correct;
diff --git a/builtins/fc.def~ b/builtins/fc.def~
new file mode 100644 (file)
index 0000000..ebe3683
--- /dev/null
@@ -0,0 +1,631 @@
+This file is fc.def, from which is created fc.c.
+It implements the builtin "fc" in Bash.
+
+Copyright (C) 1987-2005 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 fc.c
+
+$BUILTIN fc
+$FUNCTION fc_builtin
+$DEPENDS_ON HISTORY
+$SHORT_DOC fc [-e ename] [-nlr] [first] [last] or fc -s [pat=rep] [cmd]
+fc is used to list or edit and re-execute commands from the history list.
+FIRST and LAST can be numbers specifying the range, or FIRST can be a
+string, which means the most recent command beginning with that
+string.
+
+   -e ENAME selects which editor to use.  Default is FCEDIT, then EDITOR,
+      then vi.
+
+   -l means list lines instead of editing.
+   -n means no line numbers listed.
+   -r means reverse the order of the lines (making it newest listed first).
+
+With the `fc -s [pat=rep ...] [command]' format, the command is
+re-executed after the substitution OLD=NEW is performed.
+
+A useful alias to use with this is r='fc -s', so that typing `r cc'
+runs the last command beginning with `cc' and typing `r' re-executes
+the last command.
+$END
+
+#include <config.h>
+
+#if defined (HISTORY)
+#ifndef _MINIX
+#  include <sys/param.h>
+#endif
+#include "../bashtypes.h"
+#include "posixstat.h"
+#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
+#  include <sys/file.h>
+#endif
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <chartypes.h>
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+#include <errno.h>
+
+#include "../shell.h"
+#include "../builtins.h"
+#include "../flags.h"
+#include "../bashhist.h"
+#include "maxpath.h"
+#include <readline/history.h>
+#include "bashgetopt.h"
+#include "common.h"
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+extern int echo_input_at_read;
+extern int current_command_line_count;
+extern int literal_history;
+extern int posixly_correct;
+
+extern int unlink __P((const char *));
+
+extern FILE *sh_mktmpfp __P((char *, int, char **));
+extern int delete_last_history __P((void));
+
+/* **************************************************************** */
+/*                                                                 */
+/*     The K*rn shell style fc command (Fix Command)               */
+/*                                                                 */
+/* **************************************************************** */
+
+/* fc builtin command (fix command) for Bash for those who
+   like K*rn-style history better than csh-style.
+
+     fc [-e ename] [-nlr] [first] [last]
+
+   FIRST and LAST can be numbers specifying the range, or FIRST can be
+   a string, which means the most recent command beginning with that
+   string.
+
+   -e ENAME selects which editor to use.  Default is FCEDIT, then EDITOR,
+      then the editor which corresponds to the current readline editing
+      mode, then vi.
+
+   -l means list lines instead of editing.
+   -n means no line numbers listed.
+   -r means reverse the order of the lines (making it newest listed first).
+
+     fc -e - [pat=rep ...] [command]
+     fc -s [pat=rep ...] [command]
+
+   Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's.
+*/
+
+/* Data structure describing a list of global replacements to perform. */
+typedef struct repl {
+  struct repl *next;
+  char *pat;
+  char *rep;
+} REPL;
+
+/* Accessors for HIST_ENTRY lists that are called HLIST. */
+#define histline(i) (hlist[(i)]->line)
+#define histdata(i) (hlist[(i)]->data)
+
+#define FREE_RLIST() \
+       do { \
+               for (rl = rlist; rl; ) { \
+                       REPL *r;        \
+                       r = rl->next; \
+                       if (rl->pat) \
+                               free (rl->pat); \
+                       if (rl->rep) \
+                               free (rl->rep); \
+                       free (rl); \
+                       rl = r; \
+               } \
+       } while (0)
+
+static char *fc_dosubs __P((char *, REPL *));
+static char *fc_gethist __P((char *, HIST_ENTRY **));
+static int fc_gethnum __P((char *, HIST_ENTRY **));
+static int fc_number __P((WORD_LIST *));
+static void fc_replhist __P((char *));
+#ifdef INCLUDE_UNUSED
+static char *fc_readline __P((FILE *));
+static void fc_addhist __P((char *));
+#endif
+
+/* String to execute on a file that we want to edit. */
+#define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
+#if defined (STRICT_POSIX)
+#  define POSIX_FC_EDIT_COMMAND "${FCEDIT:-ed}"
+#else
+#  define POSIX_FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-ed}}"
+#endif
+
+int
+fc_builtin (list)
+     WORD_LIST *list;
+{
+  register int i;
+  register char *sep;
+  int numbering, reverse, listing, execute;
+  int histbeg, histend, last_hist, retval, opt;
+  FILE *stream;
+  REPL *rlist, *rl;
+  char *ename, *command, *newcom, *fcedit;
+  HIST_ENTRY **hlist;
+  char *fn;
+
+  numbering = 1;
+  reverse = listing = execute = 0;
+  ename = (char *)NULL;
+
+  /* Parse out the options and set which of the two forms we're in. */
+  reset_internal_getopt ();
+  lcurrent = list;             /* XXX */
+  while (fc_number (loptend = lcurrent) == 0 &&
+        (opt = internal_getopt (list, ":e:lnrs")) != -1)
+    {
+      switch (opt)
+       {
+       case 'n':
+         numbering = 0;
+         break;
+
+       case 'l':
+         listing = 1;
+         break;
+
+       case 'r':
+         reverse = 1;
+         break;
+
+       case 's':
+         execute = 1;
+         break;
+
+       case 'e':
+         ename = list_optarg;
+         break;
+
+       default:
+         builtin_usage ();
+         return (EX_USAGE);
+       }
+    }
+
+  list = loptend;
+
+  if (ename && (*ename == '-') && (ename[1] == '\0'))
+    execute = 1;
+
+  /* The "execute" form of the command (re-run, with possible string
+     substitutions). */
+  if (execute)
+    {
+      rlist = (REPL *)NULL;
+      while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL))
+       {
+         *sep++ = '\0';
+         rl = (REPL *)xmalloc (sizeof (REPL));
+         rl->next = (REPL *)NULL;
+         rl->pat = savestring (list->word->word);
+         rl->rep = savestring (sep);
+
+         if (rlist == NULL)
+           rlist = rl;
+         else
+           {
+             rl->next = rlist;
+             rlist = rl;
+           }
+         list = list->next;
+       }
+
+      /* If we have a list of substitutions to do, then reverse it
+        to get the replacements in the proper order. */
+
+      rlist = REVERSE_LIST (rlist, REPL *);
+
+      hlist = history_list ();
+
+      /* If we still have something in list, it is a command spec.
+        Otherwise, we use the most recent command in time. */
+      command = fc_gethist (list ? list->word->word : (char *)NULL, hlist);
+
+      if (command == NULL)
+       {
+         builtin_error (_("no command found"));
+         if (rlist)
+           FREE_RLIST ();
+
+         return (EXECUTION_FAILURE);
+       }
+
+      if (rlist)
+       {
+         newcom = fc_dosubs (command, rlist);
+         free (command);
+         FREE_RLIST ();
+         command = newcom;
+       }
+
+      fprintf (stderr, "%s\n", command);
+      fc_replhist (command);   /* replace `fc -s' with command */
+      return (parse_and_execute (command, "fc", SEVAL_NOHIST));
+    }
+
+  /* This is the second form of the command (the list-or-edit-and-rerun
+     form). */
+  hlist = history_list ();
+  if (hlist == 0)
+    return (EXECUTION_SUCCESS);
+  for (i = 0; hlist[i]; i++);
+
+  /* With the Bash implementation of history, the current command line
+     ("fc blah..." and so on) is already part of the history list by
+     the time we get to this point.  This just skips over that command
+     and makes the last command that this deals with be the last command
+     the user entered before the fc.  We need to check whether the
+     line was actually added (HISTIGNORE may have caused it to not be),
+     so we check hist_last_line_added. */
+
+  /* "When not  listing, he fc command that caused the editing shall not be
+     entered into the history list." */
+  if (listing == 0 && hist_last_line_added)
+    delete_last_history ();
+
+  last_hist = i - 1 - hist_last_line_added;
+
+  if (list)
+    {
+      histbeg = fc_gethnum (list->word->word, hlist);
+      list = list->next;
+
+      if (list)
+       histend = fc_gethnum (list->word->word, hlist);
+      else
+       histend = listing ? last_hist : histbeg;
+    }
+  else
+    {
+      /* The default for listing is the last 16 history items. */
+      if (listing)
+       {
+         histend = last_hist;
+         histbeg = histend - 16 + 1;   /* +1 because loop below uses >= */
+         if (histbeg < 0)
+           histbeg = 0;
+       }
+      else
+       /* For editing, it is the last history command. */
+       histbeg = histend = last_hist;
+    }
+
+  /* We print error messages for line specifications out of range. */
+  if ((histbeg < 0) || (histend < 0))
+    {
+      sh_erange ((char *)NULL, _("history specification"));
+      return (EXECUTION_FAILURE);
+    }
+
+  if (histend < histbeg)
+    {
+      i = histend;
+      histend = histbeg;
+      histbeg = i;
+
+      reverse = 1;
+    }
+
+  if (listing)
+    stream = stdout;
+  else
+    {
+      numbering = 0;
+      stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn);
+      if (stream == 0)
+       {
+         builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno));
+         FREE (fn);
+         return (EXECUTION_FAILURE);
+       }
+    }
+
+  for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++)
+    {
+      QUIT;
+      if (numbering)
+       fprintf (stream, "%d", i + history_base);
+      if (listing)
+       {
+         if (posixly_correct)
+           fputs ("\t", stream);
+         else
+           fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
+       }
+      fprintf (stream, "%s\n", histline (i));
+    }
+
+  if (listing)
+    return (EXECUTION_SUCCESS);
+
+  fclose (stream);
+
+  /* Now edit the file of commands. */
+  if (ename)
+    {
+      command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2);
+      sprintf (command, "%s %s", ename, fn);
+    }
+  else
+    {
+      fcedit = posixly_correct ? POSIX_FC_EDIT_COMMAND : FC_EDIT_COMMAND;
+      command = (char *)xmalloc (3 + strlen (fcedit) + strlen (fn));
+      sprintf (command, "%s %s", fcedit, fn);
+    }
+  retval = parse_and_execute (command, "fc", SEVAL_NOHIST);
+  if (retval != EXECUTION_SUCCESS)
+    {
+      unlink (fn);
+      free (fn);
+      return (EXECUTION_FAILURE);
+    }
+
+  /* Make sure parse_and_execute doesn't turn this off, even though a
+     call to parse_and_execute farther up the function call stack (e.g.,
+     if this is called by vi_edit_and_execute_command) may have already
+     called bash_history_disable. */
+  remember_on_history = 1;
+
+  /* Turn on the `v' flag while fc_execute_file runs so the commands
+     will be echoed as they are read by the parser. */
+  begin_unwind_frame ("fc builtin");
+  add_unwind_protect ((Function *)xfree, fn);
+  add_unwind_protect (unlink, fn);
+  unwind_protect_int (echo_input_at_read);
+  echo_input_at_read = 1;
+    
+  retval = fc_execute_file (fn);
+
+  run_unwind_frame ("fc builtin");
+
+  return (retval);
+}
+
+/* Return 1 if LIST->word->word is a legal number for fc's use. */
+static int
+fc_number (list)
+     WORD_LIST *list;
+{
+  char *s;
+
+  if (list == 0)
+    return 0;
+  s = list->word->word;
+  if (*s == '-')
+    s++;
+  return (legal_number (s, (intmax_t *)NULL));
+}
+
+/* Return an absolute index into HLIST which corresponds to COMMAND.  If
+   COMMAND is a number, then it was specified in relative terms.  If it
+   is a string, then it is the start of a command line present in HLIST. */
+static int
+fc_gethnum (command, hlist)
+     char *command;
+     HIST_ENTRY **hlist;
+{
+  int sign = 1, n, clen;
+  register int i, j;
+  register char *s;
+
+  /* Count history elements. */
+  for (i = 0; hlist[i]; i++);
+
+  /* With the Bash implementation of history, the current command line
+     ("fc blah..." and so on) is already part of the history list by
+     the time we get to this point.  This just skips over that command
+     and makes the last command that this deals with be the last command
+     the user entered before the fc.  We need to check whether the
+     line was actually added (HISTIGNORE may have caused it to not be),
+     so we check hist_last_line_added. */
+  i -= 1 + hist_last_line_added;
+
+  /* No specification defaults to most recent command. */
+  if (command == NULL)
+    return (i);
+
+  /* Otherwise, there is a specification.  It can be a number relative to
+     the current position, or an absolute history number. */
+  s = command;
+
+  /* Handle possible leading minus sign. */
+  if (s && (*s == '-'))
+    {
+      sign = -1;
+      s++;
+    }
+
+  if (s && DIGIT(*s))
+    {
+      n = atoi (s);
+      n *= sign;
+
+      /* If the value is negative or zero, then it is an offset from
+        the current history item. */
+      if (n < 0)
+       {
+         n += i + 1;
+         return (n < 0 ? 0 : n);
+       }
+      else if (n == 0)
+       return (i);
+      else
+       {
+         n -= history_base;
+         return (i < n ? i : n);
+       }
+    }
+
+  clen = strlen (command);
+  for (j = i; j >= 0; j--)
+    {
+      if (STREQN (command, histline (j), clen))
+       return (j);
+    }
+  return (-1);
+}
+
+/* Locate the most recent history line which begins with
+   COMMAND in HLIST, and return a malloc()'ed copy of it. */
+static char *
+fc_gethist (command, hlist)
+     char *command;
+     HIST_ENTRY **hlist;
+{
+  int i;
+
+  if (hlist == 0)
+    return ((char *)NULL);
+
+  i = fc_gethnum (command, hlist);
+
+  if (i >= 0)
+    return (savestring (histline (i)));
+  else
+    return ((char *)NULL);
+}
+
+#ifdef INCLUDE_UNUSED
+/* Read the edited history lines from STREAM and return them
+   one at a time.  This can read unlimited length lines.  The
+   caller should free the storage. */
+static char *
+fc_readline (stream)
+     FILE *stream;
+{
+  register int c;
+  int line_len = 0, lindex = 0;
+  char *line = (char *)NULL;
+
+  while ((c = getc (stream)) != EOF)
+    {
+      if ((lindex + 2) >= line_len)
+       line = (char *)xrealloc (line, (line_len += 128));
+
+      if (c == '\n')
+       {
+         line[lindex++] = '\n';
+         line[lindex++] = '\0';
+         return (line);
+       }
+      else
+       line[lindex++] = c;
+    }
+
+  if (!lindex)
+    {
+      if (line)
+       free (line);
+
+      return ((char *)NULL);
+    }
+
+  if (lindex + 2 >= line_len)
+    line = (char *)xrealloc (line, lindex + 3);
+
+  line[lindex++] = '\n';           /* Finish with newline if none in file */
+  line[lindex++] = '\0';
+  return (line);
+}
+#endif
+
+/* Perform the SUBS on COMMAND.
+   SUBS is a list of substitutions, and COMMAND is a simple string.
+   Return a pointer to a malloc'ed string which contains the substituted
+   command. */
+static char *
+fc_dosubs (command, subs)
+     char *command;
+     REPL *subs;
+{
+  register char *new, *t;
+  register REPL *r;
+
+  for (new = savestring (command), r = subs; r; r = r->next)
+    {
+      t = strsub (new, r->pat, r->rep, 1);
+      free (new);
+      new = t;
+    }
+  return (new);
+}
+
+/* Use `command' to replace the last entry in the history list, which,
+   by this time, is `fc blah...'.  The intent is that the new command
+   become the history entry, and that `fc' should never appear in the
+   history list.  This way you can do `r' to your heart's content. */
+static void
+fc_replhist (command)
+     char *command;
+{
+  int n;
+
+  if (command == 0 || *command == '\0')
+    return;
+
+  n = strlen (command);
+  if (command[n - 1] == '\n')
+    command[n - 1] = '\0';
+
+  if (command && *command)
+    {
+      delete_last_history ();
+      maybe_add_history (command);     /* Obeys HISTCONTROL setting. */
+    }
+}
+
+#ifdef INCLUDE_UNUSED
+/* Add LINE to the history, after removing a single trailing newline. */
+static void
+fc_addhist (line)
+     char *line;
+{
+  register int n;
+
+  if (line == 0 || *line == 0)
+    return;
+
+  n = strlen (line);
+
+  if (line[n - 1] == '\n')
+    line[n - 1] = '\0';
+
+  if (line && *line)
+    maybe_add_history (line);          /* Obeys HISTCONTROL setting. */
+}
+#endif
+
+#endif /* HISTORY */
index c2fa5c4ef0f229d8cf8ae31bf6115b4ea4f5bd4e..3658b48ae88da0e2ad92a722d764f66879ee2fc1 100644 (file)
@@ -108,6 +108,7 @@ extern int errno;
          (void)fputs (b, stdout); \
        if (ferror (stdout)) \
          { \
+           sh_wrerror (); \
            clearerr (stdout); \
            return (EXECUTION_FAILURE); \
          } \
@@ -826,7 +827,7 @@ vbadd (buf, blen)
 
 #ifdef DEBUG
   if  (strlen (vbuf) != vblen)
-    internal_error  ("printf:vbadd: vblen (%d) != strlen (vbuf) (%d)", vblen, strlen (vbuf));
+    internal_error  ("printf:vbadd: vblen (%d) != strlen (vbuf) (%d)", vblen, (int)strlen (vbuf));
 #endif
 
   return vbuf;
diff --git a/builtins/printf.def~ b/builtins/printf.def~
new file mode 100644 (file)
index 0000000..67e978e
--- /dev/null
@@ -0,0 +1,1008 @@
+This file is printf.def, from which is created printf.c.
+It implements the builtin "printf" in Bash.
+
+Copyright (C) 1997-2005 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+
+$PRODUCES printf.c
+
+$BUILTIN printf
+$FUNCTION printf_builtin
+$SHORT_DOC printf [-v var] format [arguments]
+printf formats and prints ARGUMENTS under control of the FORMAT. FORMAT
+is a character string which contains three types of objects: plain
+characters, which are simply copied to standard output, character escape
+sequences which are converted and copied to the standard output, and
+format specifications, each of which causes printing of the next successive
+argument.  In addition to the standard printf(1) formats, %b means to
+expand backslash escape sequences in the corresponding argument, and %q
+means to quote the argument in a way that can be reused as shell input.
+If the -v option is supplied, the output is placed into the value of the
+shell variable VAR rather than being sent to the standard output.
+$END
+
+#include <config.h>
+
+#include "../bashtypes.h"
+
+#include <errno.h>
+#if defined (HAVE_LIMITS_H)
+#  include <limits.h>
+#else
+   /* Assume 32-bit ints. */
+#  define INT_MAX              2147483647
+#  define INT_MIN              (-2147483647-1)
+#endif
+
+#include <stdio.h>
+#include <chartypes.h>
+
+#ifdef HAVE_INTTYPES_H
+#  include <inttypes.h>
+#endif
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "stdc.h"
+#include "bashgetopt.h"
+#include "common.h"
+
+#if !defined (PRIdMAX)
+#  if HAVE_LONG_LONG
+#    define PRIdMAX    "lld"
+#  else
+#    define PRIdMAX    "ld"
+#  endif
+#endif
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+#define PC(c) \
+  do { \
+    char b[2]; \
+    tw++; \
+    b[0] = c; b[1] = '\0'; \
+    if (vflag) \
+      vbadd (b, 1); \
+    else \
+      putchar (c); \
+  } while (0)
+
+#define PF(f, func) \
+  do { \
+    char *b = 0; \
+    int nw; \
+    if (have_fieldwidth && have_precision) \
+      nw = asprintf(&b, f, fieldwidth, precision, func); \
+    else if (have_fieldwidth) \
+      nw = asprintf(&b, f, fieldwidth, func); \
+    else if (have_precision) \
+      nw = asprintf(&b, f, precision, func); \
+    else \
+      nw = asprintf(&b, f, func); \
+    tw += nw; \
+    if (b) \
+      { \
+       if (vflag) \
+         (void)vbadd (b, nw); \
+       else \
+         (void)fputs (b, stdout); \
+       if (ferror (stdout)) \
+         { \
+           sh_wrerror (); \
+           clearerr (stdout); \
+           return (EXECUTION_FAILURE); \
+         } \
+       free (b); \
+      } \
+  } while (0)
+
+/* We free the buffer used by mklong() if it's `too big'. */
+#define PRETURN(value) \
+  do \
+    { \
+      if (vflag) \
+       { \
+         bind_variable  (vname, vbuf, 0); \
+         stupidly_hack_special_variables (vname); \
+       } \
+      if (conv_bufsize > 4096 ) \
+       { \
+         free (conv_buf); \
+         conv_bufsize = 0; \
+         conv_buf = 0; \
+       } \
+      if (vbsize > 4096) \
+       { \
+         free (vbuf); \
+         vbsize = 0; \
+         vbuf = 0; \
+       } \
+      fflush (stdout); \
+      if (ferror (stdout)) \
+       { \
+         clearerr (stdout); \
+         return (EXECUTION_FAILURE); \
+       } \
+      return (value); \
+    } \
+  while (0)
+
+#define SKIP1 "#'-+ 0"
+#define LENMODS "hjlLtz"
+
+static void printf_erange __P((char *));
+static int printstr __P((char *, char *, int, int, int));
+static int tescape __P((char *, char *, int *));
+static char *bexpand __P((char *, int, int *, int *));
+static char *vbadd __P((char *, int));
+static char *mklong __P((char *, char *, size_t));
+static int getchr __P((void));
+static char *getstr __P((void));
+static int  getint __P((void));
+static intmax_t getintmax __P((void));
+static uintmax_t getuintmax __P((void));
+
+#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD && !defined(STRTOLD_BROKEN)
+typedef long double floatmax_t;
+#  define FLOATMAX_CONV        "L"
+#  define strtofltmax  strtold
+#else
+typedef double floatmax_t;
+#  define FLOATMAX_CONV        ""
+#  define strtofltmax  strtod
+#endif
+static floatmax_t getfloatmax __P((void));
+
+static int asciicode __P((void));
+
+static WORD_LIST *garglist;
+static int retval;
+static int conversion_error;
+
+/* printf -v var support */
+static int vflag = 0;
+static char *vbuf, *vname;
+static size_t vbsize;
+static int vblen;
+
+static intmax_t tw;
+
+static char *conv_buf;
+static size_t conv_bufsize;
+
+int
+printf_builtin (list)
+     WORD_LIST *list;
+{
+  int ch, fieldwidth, precision;
+  int have_fieldwidth, have_precision;
+  char convch, thisch, nextch, *format, *modstart, *fmt, *start;
+
+  conversion_error = 0;
+  retval = EXECUTION_SUCCESS;
+
+  vflag = 0;
+
+  reset_internal_getopt ();
+  while ((ch = internal_getopt (list, "v:")) != -1)
+    {
+      switch (ch)
+       {
+       case 'v':
+         if (legal_identifier (vname = list_optarg))
+           {
+             vflag = 1;
+             vblen = 0;
+           }
+         else
+           {
+             sh_invalidid (vname);
+             return (EX_USAGE);
+           }
+         break;
+       default:
+         builtin_usage ();
+         return (EX_USAGE);
+       }
+    }
+  list = loptend;      /* skip over possible `--' */
+
+  if (list == 0)
+    {
+      builtin_usage ();
+      return (EX_USAGE);
+    }
+
+  if (list->word->word == 0 || list->word->word[0] == '\0')
+    return (EXECUTION_SUCCESS);
+
+  format = list->word->word;
+  tw = 0;
+
+  garglist = list->next;
+
+  /* If the format string is empty after preprocessing, return immediately. */
+  if (format == 0 || *format == 0)
+    return (EXECUTION_SUCCESS);
+         
+  /* Basic algorithm is to scan the format string for conversion
+     specifications -- once one is found, find out if the field
+     width or precision is a '*'; if it is, gather up value.  Note,
+     format strings are reused as necessary to use up the provided
+     arguments, arguments of zero/null string are provided to use
+     up the format string. */
+  do
+    {
+      tw = 0;
+      /* find next format specification */
+      for (fmt = format; *fmt; fmt++)
+       {
+         precision = fieldwidth = 0;
+         have_fieldwidth = have_precision = 0;
+
+         if (*fmt == '\\')
+           {
+             fmt++;
+             /* A NULL third argument to tescape means to bypass the
+                special processing for arguments to %b. */
+             fmt += tescape (fmt, &nextch, (int *)NULL);
+             PC (nextch);
+             fmt--;    /* for loop will increment it for us again */
+             continue;
+           }
+
+         if (*fmt != '%')
+           {
+             PC (*fmt);
+             continue;
+           }
+
+         /* ASSERT(*fmt == '%') */
+         start = fmt++;
+
+         if (*fmt == '%')              /* %% prints a % */
+           {
+             PC ('%');
+             continue;
+           }
+
+         /* found format specification, skip to field width */
+         for (; *fmt && strchr(SKIP1, *fmt); ++fmt)
+           ;
+
+         /* Skip optional field width. */
+         if (*fmt == '*')
+           {
+             fmt++;
+             have_fieldwidth = 1;
+             fieldwidth = getint ();
+           }
+         else
+           while (DIGIT (*fmt))
+             fmt++;
+
+         /* Skip optional '.' and precision */
+         if (*fmt == '.')
+           {
+             ++fmt;
+             if (*fmt == '*')
+               {
+                 fmt++;
+                 have_precision = 1;
+                 precision = getint ();
+               }
+             else
+               {
+                 /* Negative precisions are allowed but treated as if the
+                    precision were missing; I would like to allow a leading
+                    `+' in the precision number as an extension, but lots
+                    of asprintf/fprintf implementations get this wrong. */
+#if 0
+                 if (*fmt == '-' || *fmt == '+')
+#else
+                 if (*fmt == '-')
+#endif
+                   fmt++;
+                 while (DIGIT (*fmt))
+                   fmt++;
+               }
+           }
+
+         /* skip possible format modifiers */
+         modstart = fmt;
+         while (*fmt && strchr (LENMODS, *fmt))
+           fmt++;
+           
+         if (*fmt == 0)
+           {
+             builtin_error (_("`%s': missing format character"), start);
+             PRETURN (EXECUTION_FAILURE);
+           }
+
+         convch = *fmt;
+         thisch = modstart[0];
+         nextch = modstart[1];
+         modstart[0] = convch;
+         modstart[1] = '\0';
+
+         switch(convch)
+           {
+           case 'c':
+             {
+               char p;
+
+               p = getchr ();
+               PF(start, p);
+               break;
+             }
+
+           case 's':
+             {
+               char *p;
+
+               p = getstr ();
+               PF(start, p);
+               break;
+             }
+
+           case 'n':
+             {
+               char *var;
+
+               var = getstr ();
+               if (var && *var)
+                 {
+                   if (legal_identifier (var))
+                     bind_var_to_int (var, tw);
+                   else
+                     {
+                       sh_invalidid (var);
+                       PRETURN (EXECUTION_FAILURE);
+                     }
+                 }
+               break;
+             }
+
+           case 'b':           /* expand escapes in argument */
+             {
+               char *p, *xp;
+               int rlen, r;
+
+               p = getstr ();
+               ch = rlen = r = 0;
+               xp = bexpand (p, strlen (p), &ch, &rlen);
+
+               if (xp)
+                 {
+                   /* Have to use printstr because of possible NUL bytes
+                      in XP -- printf does not handle that well. */
+                   r = printstr (start, xp, rlen, fieldwidth, precision);
+                   if (r < 0)
+                     {
+                       sh_wrerror ();
+                       clearerr (stdout);
+                       retval = EXECUTION_FAILURE;
+                     }
+                   free (xp);
+                 }
+
+               if (ch || r < 0)
+                 PRETURN (retval);
+               break;
+             }
+
+           case 'q':           /* print with shell quoting */
+             {
+               char *p, *xp;
+               int r;
+
+               r = 0;
+               p = getstr ();
+               if (ansic_shouldquote (p))
+                 xp = ansic_quote (p, 0, (int *)0);
+               else
+                 xp = sh_backslash_quote (p);
+               if (xp)
+                 {
+                   /* Use printstr to get fieldwidth and precision right. */
+                   r = printstr (start, xp, strlen (xp), fieldwidth, precision);
+                   if (r < 0)
+                     {
+                       sh_wrerror ();
+                       clearerr (stdout);
+                     }
+                   free (xp);
+                 }
+
+               if (r < 0)
+                 PRETURN (EXECUTION_FAILURE);
+               break;
+             }
+
+           case 'd':
+           case 'i':
+             {
+               char *f;
+               long p;
+               intmax_t pp;
+
+               p = pp = getintmax ();
+               if (p != pp)
+                 {
+                   f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2);
+                   PF (f, pp);
+                 }
+               else
+                 {
+                   /* Optimize the common case where the integer fits
+                      in "long".  This also works around some long
+                      long and/or intmax_t library bugs in the common
+                      case, e.g. glibc 2.2 x86.  */
+                   f = mklong (start, "l", 1);
+                   PF (f, p);
+                 }
+               break;
+             }
+
+           case 'o':
+           case 'u':
+           case 'x':
+           case 'X':
+             {
+               char *f;
+               unsigned long p;
+               uintmax_t pp;
+
+               p = pp = getuintmax ();
+               if (p != pp)
+                 {
+                   f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2);
+                   PF (f, pp);
+                 }
+               else
+                 {
+                   f = mklong (start, "l", 1);
+                   PF (f, p);
+                 }
+               break;
+             }
+
+           case 'e':
+           case 'E':
+           case 'f':
+           case 'F':
+           case 'g':
+           case 'G':
+#if defined (HAVE_PRINTF_A_FORMAT)
+           case 'a':
+           case 'A':
+#endif
+             {
+               char *f;
+               floatmax_t p;
+
+               p = getfloatmax ();
+               f = mklong (start, FLOATMAX_CONV, sizeof(FLOATMAX_CONV) - 1);
+               PF (f, p);
+               break;
+             }
+
+           /* We don't output unrecognized format characters; we print an
+              error message and return a failure exit status. */
+           default:
+             builtin_error (_("`%c': invalid format character"), convch);
+             PRETURN (EXECUTION_FAILURE);
+           }
+
+         modstart[0] = thisch;
+         modstart[1] = nextch;
+       }
+
+      if (ferror (stdout))
+       {
+         sh_wrerror ();
+         clearerr (stdout);
+         PRETURN (EXECUTION_FAILURE);
+       }
+    }
+  while (garglist && garglist != list->next);
+
+  if (conversion_error)
+    retval = EXECUTION_FAILURE;
+
+  PRETURN (retval);
+}
+
+static void
+printf_erange (s)
+     char *s;
+{
+  builtin_error ("warning: %s: %s", s, strerror(ERANGE));
+}
+
+/* We duplicate a lot of what printf(3) does here. */
+static int
+printstr (fmt, string, len, fieldwidth, precision)
+     char *fmt;                        /* format */
+     char *string;             /* expanded string argument */
+     int len;                  /* length of expanded string */
+     int fieldwidth;           /* argument for width of `*' */
+     int precision;            /* argument for precision of `*' */
+{
+#if 0
+  char *s;
+#endif
+  int padlen, nc, ljust, i;
+  int fw, pr;                  /* fieldwidth and precision */
+
+#if 0
+  if (string == 0 || *string == '\0')
+#else
+  if (string == 0 || len == 0)
+#endif
+    return;
+
+#if 0
+  s = fmt;
+#endif
+  if (*fmt == '%')
+    fmt++;
+
+  ljust = fw = 0;
+  pr = -1;
+
+  /* skip flags */
+  while (strchr (SKIP1, *fmt))
+    {
+      if (*fmt == '-')
+       ljust = 1;
+      fmt++;
+    }
+
+  /* get fieldwidth, if present */
+  if (*fmt == '*')
+    {
+      fmt++;
+      fw = fieldwidth;
+      if (fw < 0)
+       {
+         fw = -fw;
+         ljust = 1;
+       }
+    }
+  else if (DIGIT (*fmt))
+    {
+      fw = *fmt++ - '0';
+      while (DIGIT (*fmt))
+       fw = (fw * 10) + (*fmt++ - '0');
+    }
+
+  /* get precision, if present */
+  if (*fmt == '.')
+    {
+      fmt++;
+      if (*fmt == '*')
+       {
+         fmt++;
+         pr = precision;
+       }
+      else if (DIGIT (*fmt))
+       {
+         pr = *fmt++ - '0';
+         while (DIGIT (*fmt))
+           pr = (pr * 10) + (*fmt++ - '0');
+       }
+    }
+
+#if 0
+  /* If we remove this, get rid of `s'. */
+  if (*fmt != 'b' && *fmt != 'q')
+    {
+      internal_error ("format parsing problem: %s", s);
+      fw = pr = 0;
+    }
+#endif
+
+  /* chars from string to print */
+  nc = (pr >= 0 && pr <= len) ? pr : len;
+
+  padlen = fw - nc;
+  if (padlen < 0)
+    padlen = 0;
+  if (ljust)
+    padlen = -padlen;
+
+  /* leading pad characters */
+  for (; padlen > 0; padlen--)
+    PC (' ');
+
+  /* output NC characters from STRING */
+  for (i = 0; i < nc; i++)
+    PC (string[i]);
+
+  /* output any necessary trailing padding */
+  for (; padlen < 0; padlen++)
+    PC (' ');
+
+  return (ferror (stdout) ? -1 : 0);
+}
+  
+/* Convert STRING by expanding the escape sequences specified by the
+   POSIX standard for printf's `%b' format string.  If SAWC is non-null,
+   perform the processing appropriate for %b arguments.  In particular,
+   recognize `\c' and use that as a string terminator.  If we see \c, set
+   *SAWC to 1 before returning.  LEN is the length of STRING. */
+
+/* Translate a single backslash-escape sequence starting at ESTART (the
+   character after the backslash) and return the number of characters
+   consumed by the sequence.  CP is the place to return the translated
+   value.  *SAWC is set to 1 if the escape sequence was \c, since that means
+   to short-circuit the rest of the processing.  If SAWC is null, we don't
+   do the \c short-circuiting, and \c is treated as an unrecognized escape
+   sequence; we also bypass the other processing specific to %b arguments.  */
+static int
+tescape (estart, cp, sawc)
+     char *estart;
+     char *cp;
+     int *sawc;
+{
+  register char *p;
+  int temp, c, evalue;
+
+  p = estart;
+
+  switch (c = *p++)
+    {
+#if defined (__STDC__)
+      case 'a': *cp = '\a'; break;
+#else
+      case 'a': *cp = '\007'; break;
+#endif
+
+      case 'b': *cp = '\b'; break;
+
+      case 'e':
+      case 'E': *cp = '\033'; break;   /* ESC -- non-ANSI */
+
+      case 'f': *cp = '\f'; break;
+
+      case 'n': *cp = '\n'; break;
+
+      case 'r': *cp = '\r'; break;
+
+      case 't': *cp = '\t'; break;
+
+      case 'v': *cp = '\v'; break;
+
+      /* The octal escape sequences are `\0' followed by up to three octal
+        digits (if SAWC), or `\' followed by up to three octal digits (if
+        !SAWC).  As an extension, we allow the latter form even if SAWC. */
+      case '0': case '1': case '2': case '3':
+      case '4': case '5': case '6': case '7':
+       evalue = OCTVALUE (c);
+       for (temp = 2 + (!evalue && !!sawc); ISOCTAL (*p) && temp--; p++)
+         evalue = (evalue * 8) + OCTVALUE (*p);
+       *cp = evalue & 0xFF;
+       break;
+
+      /* And, as another extension, we allow \xNNN, where each N is a
+        hex digit. */
+      case 'x':
+#if 0
+       for (evalue = 0; ISXDIGIT ((unsigned char)*p); p++)
+#else
+       for (temp = 2, evalue = 0; ISXDIGIT ((unsigned char)*p) && temp--; p++)
+#endif
+         evalue = (evalue * 16) + HEXVALUE (*p);
+       if (p == estart + 1)
+         {
+           builtin_error (_("missing hex digit for \\x"));
+           *cp = '\\';
+           return 0;
+         }
+       *cp = evalue & 0xFF;
+       break;
+
+      case '\\':       /* \\ -> \ */
+       *cp = c;
+       break;
+
+      /* SAWC == 0 means that \', \", and \? are recognized as escape
+        sequences, though the only processing performed is backslash
+        removal. */
+      case '\'': case '"': case '?':
+       if (!sawc)
+         *cp = c;
+       else
+         {
+           *cp = '\\';
+           return 0;
+         }
+       break;
+
+      case 'c':
+       if (sawc)
+         {
+           *sawc = 1;
+           break;
+         }
+      /* other backslash escapes are passed through unaltered */
+      default:
+       *cp = '\\';
+       return 0;
+      }
+  return (p - estart);
+}
+
+static char *
+bexpand (string, len, sawc, lenp)
+     char *string;
+     int len, *sawc, *lenp;
+{
+  int temp;
+  char *ret, *r, *s, c;
+
+#if 0
+  if (string == 0 || *string == '\0')
+#else
+  if (string == 0 || len == 0)
+#endif
+    {
+      if (sawc)
+       *sawc = 0;
+      if (lenp)
+       *lenp = 0;
+      return ((char *)NULL);
+    }
+
+  ret = (char *)xmalloc (len + 1);
+  for (r = ret, s = string; s && *s; )
+    {
+      c = *s++;
+      if (c != '\\' || *s == '\0')
+       {
+         *r++ = c;
+         continue;
+       }
+      temp = 0;
+      s += tescape (s, &c, &temp);
+      if (temp)
+       {
+         if (sawc)
+           *sawc = 1;
+         break;
+       }
+
+      *r++ = c;
+    }
+
+  *r = '\0';
+  if (lenp)
+    *lenp = r - ret;
+  return ret;
+}
+
+static char *
+vbadd (buf, blen)
+     char *buf;
+     int blen;
+{
+  size_t nlen;
+
+  nlen = vblen + blen + 1;
+  if (nlen >= vbsize)
+    {
+      vbsize = ((nlen + 63) >> 6) << 6;
+      vbuf = (char *)xrealloc (vbuf, vbsize);
+    }
+
+  if (blen == 1)
+    vbuf[vblen++] = buf[0];
+  else
+    {
+      FASTCOPY (buf, vbuf  + vblen, blen);
+      vblen += blen;
+    }
+  vbuf[vblen] = '\0';
+
+#ifdef DEBUG
+  if  (strlen (vbuf) != vblen)
+    internal_error  ("printf:vbadd: vblen (%d) != strlen (vbuf) (%d)", vblen, strlen (vbuf));
+#endif
+
+  return vbuf;
+}
+
+static char *
+mklong (str, modifiers, mlen)
+     char *str;
+     char *modifiers;
+     size_t mlen;
+{
+  size_t len, slen;
+
+  slen = strlen (str);
+  len = slen + mlen + 1;
+
+  if (len > conv_bufsize)
+    {
+      conv_bufsize = (((len + 1023) >> 10) << 10);
+      conv_buf = (char *)xrealloc (conv_buf, conv_bufsize);
+    }
+
+  FASTCOPY (str, conv_buf, slen - 1);
+  FASTCOPY (modifiers, conv_buf + slen - 1, mlen);
+
+  conv_buf[len - 2] = str[slen - 1];
+  conv_buf[len - 1] = '\0';
+  return (conv_buf);
+}
+
+static int
+getchr ()
+{
+  int ret;
+
+  if (garglist == 0)
+    return ('\0');
+
+  ret = (int)garglist->word->word[0];
+  garglist = garglist->next;
+  return ret;
+}
+
+static char *
+getstr ()
+{
+  char *ret;
+
+  if (garglist == 0)
+    return ("");
+
+  ret = garglist->word->word;
+  garglist = garglist->next;
+  return ret;
+}
+
+static int
+getint ()
+{
+  intmax_t ret;
+
+  ret = getintmax ();
+
+  if (ret > INT_MAX)
+    {
+      printf_erange (garglist->word->word);
+      ret = INT_MAX;
+    }
+  else if (ret < INT_MIN)
+    {
+      printf_erange (garglist->word->word);
+      ret = INT_MIN;
+    }
+
+  return ((int)ret);
+}
+
+static intmax_t
+getintmax ()
+{
+  intmax_t ret;
+  char *ep;
+
+  if (garglist == 0)
+    return (0);
+
+  if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
+    return asciicode ();
+
+  errno = 0;
+  ret = strtoimax (garglist->word->word, &ep, 0);
+
+  if (*ep)
+    {
+      sh_invalidnum (garglist->word->word);
+      /* POSIX.2 says ``...a diagnostic message shall be written to standard
+        error, and the utility shall not exit with a zero exit status, but
+        shall continue processing any remaining operands and shall write the
+         value accumulated at the time the error was detected to standard
+        output.''  Yecch. */
+      ret = 0;
+      conversion_error = 1;
+    }
+  else if (errno == ERANGE)
+    printf_erange (garglist->word->word);
+
+  garglist = garglist->next;
+  return (ret);
+}
+
+static uintmax_t
+getuintmax ()
+{
+  uintmax_t ret;
+  char *ep;
+
+  if (garglist == 0)
+    return (0);
+
+  if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
+    return asciicode ();
+
+  errno = 0;
+  ret = strtoumax (garglist->word->word, &ep, 0);
+  
+  if (*ep)
+    {
+      sh_invalidnum (garglist->word->word);
+      /* Same POSIX.2 conversion error requirements as getintmax(). */
+      ret = 0;
+      conversion_error = 1;
+    }
+  else if (errno == ERANGE)
+    printf_erange (garglist->word->word);
+
+  garglist = garglist->next;
+  return (ret);
+}
+
+static floatmax_t
+getfloatmax ()
+{
+  floatmax_t ret;
+  char *ep;
+
+  if (garglist == 0)
+    return (0);
+
+  if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
+    return asciicode ();
+
+  errno = 0;
+  ret = strtofltmax (garglist->word->word, &ep);
+
+  if (*ep)
+    {
+      sh_invalidnum (garglist->word->word);
+      /* Same thing about POSIX.2 conversion error requirements. */
+      ret = 0;
+      conversion_error = 1;
+    }
+  else if (errno == ERANGE)
+    printf_erange (garglist->word->word);
+
+  garglist = garglist->next;
+  return (ret);
+}
+
+/* NO check is needed for garglist here. */
+static int
+asciicode ()
+{
+  register int ch;
+
+  ch = garglist->word->word[1];
+  garglist = garglist->next;
+  return (ch);
+}
index 3bb327040f99abd48224ce6cd3a5489411dfccfa..d1086695a3d89171ccae84852ea464e9281f3d08 100644 (file)
@@ -578,7 +578,6 @@ set_builtin (list)
      WORD_LIST *list;
 {
   int on_or_off, flag_name, force_assignment, opts_changed;
-  WORD_LIST *l;
   register char *arg;
   char s[3];
 
index f9f812f8991f0c105879c50ce441cea82e83b65d..9576f09e1f0f8e267dfe0aaa78acfcdeab41ffb5 100644 (file)
@@ -68,9 +68,7 @@ $END
 extern int errno;
 #endif /* !errno */
 
-#if defined (RESTRICTED_SHELL)
-extern int restricted;
-#endif
+static void maybe_pop_dollar_vars __P((void));
 
 /* If non-zero, `.' uses $PATH to look up the script to be sourced. */
 int source_uses_path = 1;
diff --git a/builtins/source.def~ b/builtins/source.def~
new file mode 100644 (file)
index 0000000..f9f812f
--- /dev/null
@@ -0,0 +1,174 @@
+This file is source.def, from which is created source.c.
+It implements the builtins "." and  "source" 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 source.c
+
+$BUILTIN source
+$FUNCTION source_builtin
+$SHORT_DOC source filename [arguments]
+Read and execute commands from FILENAME and return.  The pathnames
+in $PATH are used to find the directory containing FILENAME.  If any
+ARGUMENTS are supplied, they become the positional parameters when
+FILENAME is executed.
+$END
+$BUILTIN .
+$DOCNAME dot
+$FUNCTION source_builtin
+$SHORT_DOC . filename [arguments]
+Read and execute commands from FILENAME and return.  The pathnames
+in $PATH are used to find the directory containing FILENAME.  If any
+ARGUMENTS are supplied, they become the positional parameters when
+FILENAME is executed.
+$END
+/* source.c - Implements the `.' and `source' builtins. */
+
+#include <config.h>
+
+#include "../bashtypes.h"
+#include "posixstat.h"
+#include "filecntl.h"
+#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
+#  include <sys/file.h>
+#endif
+#include <errno.h>
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../flags.h"
+#include "../findcmd.h"
+#include "common.h"
+#include "bashgetopt.h"
+#include "../trap.h"
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+#if defined (RESTRICTED_SHELL)
+extern int restricted;
+#endif
+
+/* If non-zero, `.' uses $PATH to look up the script to be sourced. */
+int source_uses_path = 1;
+
+/* If non-zero, `.' looks in the current directory if the filename argument
+   is not found in the $PATH. */
+int source_searches_cwd = 1;
+
+/* If this . script is supplied arguments, we save the dollar vars and
+   replace them with the script arguments for the duration of the script's
+   execution.  If the script does not change the dollar vars, we restore
+   what we saved.  If the dollar vars are changed in the script, and we are
+   not executing a shell function, we leave the new values alone and free
+   the saved values. */
+static void
+maybe_pop_dollar_vars ()
+{
+  if (variable_context == 0 && (dollar_vars_changed () & ARGS_SETBLTIN))
+    dispose_saved_dollar_vars ();
+  else
+    pop_dollar_vars ();
+  if (debugging_mode)
+    pop_args ();       /* restore BASH_ARGC and BASH_ARGV */
+  set_dollar_vars_unchanged ();
+}
+
+/* Read and execute commands from the file passed as argument.  Guess what.
+   This cannot be done in a subshell, since things like variable assignments
+   take place in there.  So, I open the file, place it into a large string,
+   close the file, and then execute the string. */
+int
+source_builtin (list)
+     WORD_LIST *list;
+{
+  int result;
+  char *filename, *debug_trap;
+
+  if (no_options (list))
+    return (EX_USAGE);
+  list = loptend;
+
+  if (list == 0)
+    {
+      builtin_error (_("filename argument required"));
+      builtin_usage ();
+      return (EX_USAGE);
+    }
+
+#if defined (RESTRICTED_SHELL)
+  if (restricted && strchr (list->word->word, '/'))
+    {
+      sh_restricted (list->word->word);
+      return (EXECUTION_FAILURE);
+    }
+#endif
+
+  filename = (char *)NULL;
+  if (source_uses_path)
+    filename = find_path_file (list->word->word);
+  if (filename == 0)
+    {
+      if (source_searches_cwd == 0)
+       {
+         builtin_error (_("%s: file not found"), list->word->word);
+         return (EXECUTION_FAILURE);
+       }
+      else
+       filename = savestring (list->word->word);
+    }
+
+  begin_unwind_frame ("source");
+  add_unwind_protect ((Function *)xfree, filename);
+
+  if (list->next)
+    {
+      push_dollar_vars ();
+      add_unwind_protect ((Function *)maybe_pop_dollar_vars, (char *)NULL);
+      remember_args (list->next, 1);
+      if (debugging_mode)
+       push_args (list->next); /* Update BASH_ARGV and BASH_ARGC */
+    }
+  set_dollar_vars_unchanged ();
+
+  /* Don't inherit the DEBUG trap unless function_trace_mode (overloaded)
+     is set.  XXX - should sourced files inherit the RETURN trap?  Functions
+     don't. */
+  debug_trap = TRAP_STRING (DEBUG_TRAP);
+  if (debug_trap && function_trace_mode == 0)
+    {
+      debug_trap = savestring (debug_trap);
+      add_unwind_protect (xfree, debug_trap);
+      add_unwind_protect (set_debug_trap, debug_trap);
+      restore_default_signal (DEBUG_TRAP);
+    }
+
+  result = source_file (filename, (list && list->next));
+
+  run_unwind_frame ("source");
+
+  return (result);
+}
index d616d775bf2dfe38a717adce4d6aa574cb22c5b1..ea86ae22ce02ba8e9eaa94de9569de093701a13d 100644 (file)
@@ -48,13 +48,15 @@ $END
 #include "common.h"
 #include "bashgetopt.h"
 
+static sighandler suspend_continue __P((int));
+
 static SigHandler *old_cont;
 #if 0
 static SigHandler *old_stop;
 #endif
 
 /* Continue handler. */
-sighandler
+static sighandler
 suspend_continue (sig)
      int sig;
 {
diff --git a/builtins/suspend.def~ b/builtins/suspend.def~
new file mode 100644 (file)
index 0000000..d616d77
--- /dev/null
@@ -0,0 +1,119 @@
+This file is suspend.def, from which is created suspend.c.
+It implements the builtin "suspend" 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 suspend.c
+
+$BUILTIN suspend
+$DEPENDS_ON JOB_CONTROL
+$FUNCTION suspend_builtin
+$SHORT_DOC suspend [-f]
+Suspend the execution of this shell until it receives a SIGCONT
+signal.  The `-f' if specified says not to complain about this
+being a login shell if it is; just suspend anyway.
+$END
+
+#include <config.h>
+
+#if defined (JOB_CONTROL)
+#if defined (HAVE_UNISTD_H)
+#  ifdef _MINIX
+#    include <sys/types.h>
+#  endif
+#  include <unistd.h>
+#endif
+
+#include "../bashtypes.h"
+#include <signal.h>
+#include "../bashintl.h"
+#include "../shell.h"
+#include "../jobs.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+static SigHandler *old_cont;
+#if 0
+static SigHandler *old_stop;
+#endif
+
+/* Continue handler. */
+sighandler
+suspend_continue (sig)
+     int sig;
+{
+  set_signal_handler (SIGCONT, old_cont);
+#if 0
+  set_signal_handler (SIGSTOP, old_stop);
+#endif
+  SIGRETURN (0);
+}
+
+/* Suspending the shell.  If -f is the arg, then do the suspend
+   no matter what.  Otherwise, complain if a login shell. */
+int
+suspend_builtin (list)
+     WORD_LIST *list;
+{
+  int opt, force;
+
+  reset_internal_getopt ();
+  force = 0;
+  while ((opt = internal_getopt (list, "f")) != -1)
+    switch (opt)
+      {
+      case 'f':
+       force++;
+       break;
+      default:
+       builtin_usage ();
+       return (EX_USAGE);
+      }
+      
+  list = loptend;
+
+  if (job_control == 0)
+    {
+      sh_nojobs (_("cannot suspend"));
+      return (EXECUTION_FAILURE);
+    }
+
+  if (force == 0)  
+    {
+      no_args (list);
+
+      if (login_shell)
+       {
+         builtin_error (_("cannot suspend a login shell"));
+         return (EXECUTION_FAILURE);
+       }
+    }
+
+  /* XXX - should we put ourselves back into the original pgrp now?  If so,
+     call end_job_control() here and do the right thing in suspend_continue
+     (that is, call restart_job_control()). */
+  old_cont = (SigHandler *)set_signal_handler (SIGCONT, suspend_continue);
+#if 0
+  old_stop = (SigHandler *)set_signal_handler (SIGSTOP, SIG_DFL);
+#endif
+  killpg (shell_pgrp, SIGSTOP);
+  return (EXECUTION_SUCCESS);
+}
+
+#endif /* JOB_CONTROL */
index 426833a156aec3914a84599bc2778d537838606a..2735791e4ccd8216b897b015762f521984a5624a 100644 (file)
@@ -87,7 +87,7 @@ int
 trap_builtin (list)
      WORD_LIST *list;
 {
-  int list_signal_names, display, result, opt, first_signal;
+  int list_signal_names, display, result, opt;
 
   list_signal_names = display = 0;
   result = EXECUTION_SUCCESS;
index 22a92bea06d506b8de9f1707ff1b9e5643c7811d..a30959528fe96ae8e151ce0fa2c1cf983831bf45 100644 (file)
@@ -59,7 +59,6 @@ $END
 #include "common.h"
 #include "bashgetopt.h"
 
-extern int interrupt_immediately;
 extern int wait_signal_received;
 
 procenv_t wait_intr_buf;
diff --git a/builtins/wait.def~ b/builtins/wait.def~
new file mode 100644 (file)
index 0000000..22a92be
--- /dev/null
@@ -0,0 +1,177 @@
+This file is wait.def, from which is created wait.c.
+It implements the builtin "wait" in Bash.
+
+Copyright (C) 1987-2005 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.
+
+$BUILTIN wait
+$FUNCTION wait_builtin
+$DEPENDS_ON JOB_CONTROL
+$PRODUCES wait.c
+$SHORT_DOC wait [n]
+Wait for the specified process and report its termination status.  If
+N is not given, all currently active child processes are waited for,
+and the return code is zero.  N may be a process ID or a job
+specification; if a job spec is given, all processes in the job's
+pipeline are waited for.
+$END
+
+$BUILTIN wait
+$FUNCTION wait_builtin
+$DEPENDS_ON !JOB_CONTROL
+$SHORT_DOC wait [n]
+Wait for the specified process and report its termination status.  If
+N is not given, all currently active child processes are waited for,
+and the return code is zero.  N is a process ID; if it is not given,
+all child processes of the shell are waited for.
+$END
+
+#include <config.h>
+
+#include "../bashtypes.h"
+#include <signal.h>
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include <chartypes.h>
+
+#include "../bashansi.h"
+
+#include "../shell.h"
+#include "../jobs.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+extern int interrupt_immediately;
+extern int wait_signal_received;
+
+procenv_t wait_intr_buf;
+
+/* Wait for the pid in LIST to stop or die.  If no arguments are given, then
+   wait for all of the active background processes of the shell and return
+   0.  If a list of pids or job specs are given, return the exit status of
+   the last one waited for. */
+
+#define WAIT_RETURN(s) \
+  do \
+    { \
+      interrupt_immediately = old_interrupt_immediately;\
+      return (s);\
+    } \
+  while (0)
+
+int
+wait_builtin (list)
+     WORD_LIST *list;
+{
+  int status, code;
+  volatile int old_interrupt_immediately;
+
+  USE_VAR(list);
+
+  if (no_options (list))
+    return (EX_USAGE);
+  list = loptend;
+
+  old_interrupt_immediately = interrupt_immediately;
+  interrupt_immediately++;
+
+  /* POSIX.2 says:  When the shell is waiting (by means of the wait utility)
+     for asynchronous commands to complete, the reception of a signal for
+     which a trap has been set shall cause the wait utility to return
+     immediately with an exit status greater than 128, after which the trap
+     associated with the signal shall be taken.
+
+     We handle SIGINT here; it's the only one that needs to be treated
+     specially (I think), since it's handled specially in {no,}jobs.c. */
+  code = setjmp (wait_intr_buf);
+  if (code)
+    {
+      status = 128 + wait_signal_received;
+      WAIT_RETURN (status);
+    }
+
+  /* We support jobs or pids.
+     wait <pid-or-job> [pid-or-job ...] */
+
+  /* But wait without any arguments means to wait for all of the shell's
+     currently active background processes. */
+  if (list == 0)
+    {
+      wait_for_background_pids ();
+      WAIT_RETURN (EXECUTION_SUCCESS);
+    }
+
+  status = EXECUTION_SUCCESS;
+  while (list)
+    {
+      pid_t pid;
+      char *w;
+      intmax_t pid_value;
+
+      w = list->word->word;
+      if (DIGIT (*w))
+       {
+         if (legal_number (w, &pid_value) && pid_value == (pid_t)pid_value)
+           {
+             pid = (pid_t)pid_value;
+             status = wait_for_single_pid (pid);
+           }
+         else
+           {
+             sh_badpid (w);
+             WAIT_RETURN (EXECUTION_FAILURE);
+           }
+       }
+#if defined (JOB_CONTROL)
+      else if (*w && *w == '%')
+       /* Must be a job spec.  Check it out. */
+       {
+         int job;
+         sigset_t set, oset;
+
+         BLOCK_CHILD (set, oset);
+         job = get_job_spec (list);
+
+         if (INVALID_JOB (job))
+           {
+             if (job != DUP_JOB)
+               sh_badjob (list->word->word);
+             UNBLOCK_CHILD (oset);
+             status = 127;     /* As per Posix.2, section 4.70.2 */
+             list = list->next;
+             continue;
+           }
+
+         /* Job spec used.  Wait for the last pid in the pipeline. */
+         UNBLOCK_CHILD (oset);
+         status = wait_for_job (job);
+       }
+#endif /* JOB_CONTROL */
+      else
+       {
+         sh_badpid (w);
+         status = EXECUTION_FAILURE;
+       }
+      list = list->next;
+    }
+
+  WAIT_RETURN (status);
+}
diff --git a/error.c b/error.c
index edb0e2e9ad46133a036b80ffac388b8662e3b34a..83f6a7a9fc6cb2983a59fcf6f64c25ce6cd5a91f 100644 (file)
--- a/error.c
+++ b/error.c
@@ -52,8 +52,6 @@ extern int errno;
 
 extern int executing_line_number __P((void));
 
-extern int interactive_shell, interactive, startup_state;
-extern char *dollar_vars[];
 extern char *shell_name;
 #if defined (JOB_CONTROL)
 extern pid_t shell_pgrp;
diff --git a/error.c~ b/error.c~
new file mode 100644 (file)
index 0000000..edb0e2e
--- /dev/null
+++ b/error.c~
@@ -0,0 +1,454 @@
+/* error.c -- Functions for handling errors. */
+/* Copyright (C) 1993-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. */
+
+#include "config.h"
+
+#include "bashtypes.h"
+#include <fcntl.h>
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#if defined (PREFER_STDARG)
+#  include <stdarg.h>
+#else
+#  include <varargs.h>
+#endif
+
+#include <stdio.h>
+
+#include <errno.h>
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+#include "bashansi.h"
+#include "bashintl.h"
+
+#include "shell.h"
+#include "flags.h"
+#include "input.h"
+
+#if defined (HISTORY)
+#  include "bashhist.h"
+#endif
+
+extern int executing_line_number __P((void));
+
+extern int interactive_shell, interactive, startup_state;
+extern char *dollar_vars[];
+extern char *shell_name;
+#if defined (JOB_CONTROL)
+extern pid_t shell_pgrp;
+extern int give_terminal_to __P((pid_t, int));
+#endif /* JOB_CONTROL */
+
+#if defined (ARRAY_VARS)
+extern char *bash_badsub_errmsg;
+#endif
+
+static void error_prolog __P((int));
+
+/* The current maintainer of the shell.  You change this in the
+   Makefile. */
+#if !defined (MAINTAINER)
+#define MAINTAINER "bash-maintainers@gnu.org"
+#endif
+
+char *the_current_maintainer = MAINTAINER;
+
+int gnu_error_format = 0;
+
+static void
+error_prolog (print_lineno)
+     int print_lineno;
+{
+  char *ename;
+  int line;
+
+  ename = get_name_for_error ();
+  line = (print_lineno && interactive_shell == 0) ? executing_line_number () : -1;
+
+  if (line > 0)
+    fprintf (stderr, "%s:%s%d: ", ename, gnu_error_format ? "" : " line ", line);
+  else
+    fprintf (stderr, "%s: ", ename);
+}
+
+/* Return the name of the shell or the shell script for error reporting. */
+char *
+get_name_for_error ()
+{
+  char *name;
+#if defined (ARRAY_VARS)
+  SHELL_VAR *bash_source_v;
+  ARRAY *bash_source_a;
+#endif
+
+  name = (char *)NULL;
+  if (interactive_shell == 0)
+    {
+#if defined (ARRAY_VARS)
+      bash_source_v = find_variable ("BASH_SOURCE");
+      if (bash_source_v && array_p (bash_source_v) &&
+         (bash_source_a = array_cell (bash_source_v)))
+       name = array_reference (bash_source_a, 0);
+      if (name == 0)
+#endif
+       name = dollar_vars[0];
+    }
+  if (name == 0 && shell_name && *shell_name)
+    name = base_pathname (shell_name);
+  if (name == 0)
+#if defined (PROGRAM)
+    name = PROGRAM;
+#else
+    name = "bash";
+#endif
+
+  return (name);
+}
+
+/* Report an error having to do with FILENAME.  This does not use
+   sys_error so the filename is not interpreted as a printf-style
+   format string. */
+void
+file_error (filename)
+     const char *filename;
+{
+  report_error ("%s: %s", filename, strerror (errno));
+}
+
+void
+#if defined (PREFER_STDARG)
+programming_error (const char *format, ...)
+#else
+programming_error (format, va_alist)
+     const char *format;
+     va_dcl
+#endif
+{
+  va_list args;
+  char *h;
+
+#if defined (JOB_CONTROL)
+  give_terminal_to (shell_pgrp, 0);
+#endif /* JOB_CONTROL */
+
+  SH_VA_START (args, format);
+
+  vfprintf (stderr, format, args);
+  fprintf (stderr, "\n");
+  va_end (args);
+
+#if defined (HISTORY)
+  if (remember_on_history)
+    {
+      h = last_history_line ();
+      fprintf (stderr, _("last command: %s\n"), h ? h : "(null)");
+    }
+#endif
+
+#if 0
+  fprintf (stderr, "Report this to %s\n", the_current_maintainer);
+#endif
+
+  fprintf (stderr, _("Aborting..."));
+  fflush (stderr);
+
+  abort ();
+}
+
+/* Print an error message and, if `set -e' has been executed, exit the
+   shell.  Used in this file by file_error and programming_error.  Used
+   outside this file mostly to report substitution and expansion errors,
+   and for bad invocation options. */
+void
+#if defined (PREFER_STDARG)
+report_error (const char *format, ...)
+#else
+report_error (format, va_alist)
+     const char *format;
+     va_dcl
+#endif
+{
+  va_list args;
+
+  error_prolog (1);
+
+  SH_VA_START (args, format);
+
+  vfprintf (stderr, format, args);
+  fprintf (stderr, "\n");
+
+  va_end (args);
+  if (exit_immediately_on_error)
+    exit_shell (1);
+}
+
+void
+#if defined (PREFER_STDARG)
+fatal_error (const char *format, ...)
+#else
+fatal_error (format, va_alist)
+     const char *format;
+     va_dcl
+#endif
+{
+  va_list args;
+
+  error_prolog (0);
+
+  SH_VA_START (args, format);
+
+  vfprintf (stderr, format, args);
+  fprintf (stderr, "\n");
+
+  va_end (args);
+  sh_exit (2);
+}
+
+void
+#if defined (PREFER_STDARG)
+internal_error (const char *format, ...)
+#else
+internal_error (format, va_alist)
+     const char *format;
+     va_dcl
+#endif
+{
+  va_list args;
+
+  error_prolog (1);
+
+  SH_VA_START (args, format);
+
+  vfprintf (stderr, format, args);
+  fprintf (stderr, "\n");
+
+  va_end (args);
+}
+
+void
+#if defined (PREFER_STDARG)
+internal_warning (const char *format, ...)
+#else
+internal_warning (format, va_alist)
+     const char *format;
+     va_dcl
+#endif
+{
+  va_list args;
+
+  fprintf (stderr, _("%s: warning: "), get_name_for_error ());
+
+  SH_VA_START (args, format);
+
+  vfprintf (stderr, format, args);
+  fprintf (stderr, "\n");
+
+  va_end (args);
+}
+
+void
+#if defined (PREFER_STDARG)
+sys_error (const char *format, ...)
+#else
+sys_error (format, va_alist)
+     const char *format;
+     va_dcl
+#endif
+{
+  int e;
+  va_list args;
+
+  e = errno;
+  error_prolog (0);
+
+  SH_VA_START (args, format);
+
+  vfprintf (stderr, format, args);
+  fprintf (stderr, ": %s\n", strerror (e));
+
+  va_end (args);
+}
+
+/* An error from the parser takes the general form
+
+       shell_name: input file name: line number: message
+
+   The input file name and line number are omitted if the shell is
+   currently interactive.  If the shell is not currently interactive,
+   the input file name is inserted only if it is different from the
+   shell name. */
+void
+#if defined (PREFER_STDARG)
+parser_error (int lineno, const char *format, ...)
+#else
+parser_error (lineno, format, va_alist)
+     int lineno;
+     const char *format;
+     va_dcl
+#endif
+{
+  va_list args;
+  char *ename, *iname;
+
+  ename = get_name_for_error ();
+  iname = yy_input_name ();
+
+  if (interactive)
+    fprintf (stderr, "%s: ", ename);
+  else if (interactive_shell)
+    fprintf (stderr, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : " line ", lineno);
+  else if (STREQ (ename, iname))
+    fprintf (stderr, "%s:%s%d: ", ename, gnu_error_format ? "" : " line ", lineno);
+  else
+    fprintf (stderr, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : " line ", lineno);
+
+  SH_VA_START (args, format);
+
+  vfprintf (stderr, format, args);
+  fprintf (stderr, "\n");
+
+  va_end (args);
+
+  if (exit_immediately_on_error)
+    exit_shell (2);
+}
+
+#ifdef DEBUG
+void
+#if defined (PREFER_STDARG)
+itrace (const char *format, ...)
+#else
+itrace (format, va_alist)
+     const char *format;
+     va_dcl
+#endif
+{
+  va_list args;
+
+  fprintf(stderr, "TRACE: pid %ld: ", (long)getpid());
+
+  SH_VA_START (args, format);
+
+  vfprintf (stderr, format, args);
+  fprintf (stderr, "\n");
+
+  va_end (args);
+
+  fflush(stderr);
+}
+
+/* A trace function for silent debugging -- doesn't require a control
+   terminal. */
+void
+#if defined (PREFER_STDARG)
+trace (const char *format, ...)
+#else
+trace (format, va_alist)
+     const char *format;
+     va_dcl
+#endif
+{
+  va_list args;
+  static FILE *tracefp = (FILE *)NULL;
+
+  if (tracefp == NULL)
+    tracefp = fopen("/tmp/bash-trace.log", "a+");
+
+  if (tracefp == NULL)
+    tracefp = stderr;
+  else
+    fcntl (fileno (tracefp), F_SETFD, 1);     /* close-on-exec */
+
+  fprintf(tracefp, "TRACE: pid %ld: ", (long)getpid());
+
+  SH_VA_START (args, format);
+
+  vfprintf (tracefp, format, args);
+  fprintf (tracefp, "\n");
+
+  va_end (args);
+
+  fflush(tracefp);
+}
+
+#endif /* DEBUG */
+
+/* **************************************************************** */
+/*                                                                 */
+/*                 Common error reporting                          */
+/*                                                                 */
+/* **************************************************************** */
+
+
+static char *cmd_error_table[] = {
+       N_("unknown command error"),    /* CMDERR_DEFAULT */
+       N_("bad command type"),         /* CMDERR_BADTYPE */
+       N_("bad connector"),            /* CMDERR_BADCONN */
+       N_("bad jump"),                 /* CMDERR_BADJUMP */
+       0
+};
+
+void
+command_error (func, code, e, flags)
+     const char *func;
+     int code, e, flags;       /* flags currently unused */
+{
+  if (code > CMDERR_LAST)
+    code = CMDERR_DEFAULT;
+
+  programming_error ("%s: %s: %d", func, _(cmd_error_table[code]), e);
+}
+
+char *
+command_errstr (code)
+     int code;
+{
+  if (code > CMDERR_LAST)
+    code = CMDERR_DEFAULT;
+
+  return (_(cmd_error_table[code]));
+}
+
+#ifdef ARRAY_VARS
+void
+err_badarraysub (s)
+     const char *s;
+{
+  report_error ("%s: %s", s, _(bash_badsub_errmsg));
+}
+#endif
+
+void
+err_unboundvar (s)
+     const char *s;
+{
+  report_error (_("%s: unbound variable"), s);
+}
+
+void
+err_readonly (s)
+     const char *s;
+{
+  report_error (_("%s: readonly variable"), s);
+}
index 6c05ba306f06ac42010944262fbd3f911813e16f..bc28eda2fc839eff5ac69c78a5accc80bd8ca853 100644 (file)
--- a/externs.h
+++ b/externs.h
@@ -112,6 +112,7 @@ extern void set_default_locale __P((void));
 extern void set_default_locale_vars __P((void));
 extern int set_locale_var __P((char *, char *));
 extern int set_lang __P((char *, char *));
+extern void set_default_lang __P((void));
 extern char *get_locale_var __P((char *));
 extern char *localetrans __P((char *, int, int *));
 extern char *mk_msgstr __P((char *, int *));
@@ -254,7 +255,7 @@ extern int strcasecmp __P((const char *, const char *));
 #endif /* HAVE_STRCASECMP */
 
 /* declarations for functions defined in lib/sh/strerror.c */
-#if !defined (strerror)
+#if !defined (HAVE_STRERROR) && !defined (strerror)
 extern char *strerror __P((int));
 #endif
 
index 094d924555b366e9b467532e09476bfaae5fa3f2..d2cd6fb837f61c5428693352fc650cd5716f5a91 100644 (file)
@@ -112,6 +112,7 @@ extern void set_default_locale __P((void));
 extern void set_default_locale_vars __P((void));
 extern int set_locale_var __P((char *, char *));
 extern int set_lang __P((char *, char *));
+extern void set_default_lang __P((void));
 extern char *get_locale_var __P((char *));
 extern char *localetrans __P((char *, int, int *));
 extern char *mk_msgstr __P((char *, int *));
@@ -225,6 +226,9 @@ extern char *sh_realpath __P((const char *, char *));
 extern int sh_setlinebuf __P((FILE *));
 #endif
 
+/* declarations for functions defined in lib/sh/shaccess.c */
+extern int sh_eaccess __P((char *, int));
+
 /* declarations for functions defined in lib/sh/shmatch.c */
 extern int sh_regmatch __P((const char *, const char *, int));
 
index 20dbd4443ca4be0fa19dd6211f104432ea1b169a..4ac4de0419ca74f596ce6d852aa81293aa383c86 100644 (file)
--- a/general.c
+++ b/general.c
@@ -48,7 +48,6 @@ extern int errno;
 #endif /* !errno */
 
 extern int expand_aliases;
-extern int interrupt_immediately;
 extern int interactive_comments;
 extern int check_hashed_filenames;
 extern int source_uses_path;
index 3384e84b9edfb6b38fae02fa48c275d9f51cbbe3..20dbd4443ca4be0fa19dd6211f104432ea1b169a 100644 (file)
@@ -477,8 +477,13 @@ check_binary_file (sample, sample_len)
       if (c == '\n')
        return (0);
 
+#if 0
       if (ISSPACE (c) == 0 && ISPRINT (c) == 0)
+#else
+      if (c == '\0')
+#endif
        return (1);
+      
     }
 
   return (0);
@@ -503,7 +508,7 @@ int
 file_iswdir (fn)
      char *fn;
 {
-  return (file_isdir (fn) && test_eaccess (fn, W_OK) == 0);
+  return (file_isdir (fn) && sh_eaccess (fn, W_OK) == 0);
 }
 
 /* Return 1 if STRING contains an absolute pathname, else 0.  Used by `cd'
diff --git a/input.c b/input.c
index f6af14c276d18f37afc55ae7159f3c103f7475e4..7933da2f2ee3a5e385817e3b98b337c8dd7bac19 100644 (file)
--- a/input.c
+++ b/input.c
@@ -47,6 +47,8 @@
 extern int errno;
 #endif /* !errno */
 
+extern void termsig_handler __P((int));
+
 /* Functions to handle reading input on systems that don't restart read(2)
    if a signal is received. */
 
diff --git a/input.c~ b/input.c~
new file mode 100644 (file)
index 0000000..f6af14c
--- /dev/null
+++ b/input.c~
@@ -0,0 +1,625 @@
+/* input.c -- functions to perform buffered input with synchronization. */
+
+/* Copyright (C) 1992 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"
+
+#include "bashtypes.h"
+#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
+#  include <sys/file.h>
+#endif
+#include "filecntl.h"
+#include "posixstat.h"
+#include <stdio.h>
+#include <errno.h>
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include "bashansi.h"
+#include "bashintl.h"
+
+#include "command.h"
+#include "general.h"
+#include "input.h"
+#include "error.h"
+#include "externs.h"
+#include "quit.h"
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+/* Functions to handle reading input on systems that don't restart read(2)
+   if a signal is received. */
+
+static char localbuf[128];
+static int local_index = 0, local_bufused = 0;
+
+/* Posix and USG systems do not guarantee to restart read () if it is
+   interrupted by a signal.  We do the read ourselves, and restart it
+   if it returns EINTR. */
+int
+getc_with_restart (stream)
+     FILE *stream;
+{
+  unsigned char uc;
+
+  CHECK_TERMSIG;
+
+  /* Try local buffering to reduce the number of read(2) calls. */
+  if (local_index == local_bufused || local_bufused == 0)
+    {
+      while (1)
+       {
+         CHECK_TERMSIG;
+         local_bufused = read (fileno (stream), localbuf, sizeof(localbuf));
+         if (local_bufused > 0)
+           break;
+         else if (local_bufused == 0 || errno != EINTR)
+           {
+             local_index = 0;
+             return EOF;
+           }
+       }
+      local_index = 0;
+    }
+  uc = localbuf[local_index++];
+  return uc;
+}
+
+int
+ungetc_with_restart (c, stream)
+     int c;
+     FILE *stream;
+{
+  if (local_index == 0 || c == EOF)
+    return EOF;
+  localbuf[--local_index] = c;
+  return c;
+}
+
+#if defined (BUFFERED_INPUT)
+
+/* A facility similar to stdio, but input-only. */
+
+#if defined (USING_BASH_MALLOC)
+#  define MAX_INPUT_BUFFER_SIZE        8176
+#else
+#  define MAX_INPUT_BUFFER_SIZE        8192
+#endif
+
+#if !defined (SEEK_CUR)
+#  define SEEK_CUR 1
+#endif /* !SEEK_CUR */
+
+#ifdef max
+#  undef max
+#endif
+#define max(a, b)      (((a) > (b)) ? (a) : (b))
+#ifdef min
+#  undef min
+#endif
+#define min(a, b)      ((a) > (b) ? (b) : (a))
+
+extern int interactive_shell;
+
+int bash_input_fd_changed;
+
+/* This provides a way to map from a file descriptor to the buffer
+   associated with that file descriptor, rather than just the other
+   way around.  This is needed so that buffers are managed properly
+   in constructs like 3<&4.  buffers[x]->b_fd == x -- that is how the
+   correspondence is maintained. */
+static BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL;
+static int nbuffers;
+
+#define ALLOCATE_BUFFERS(n) \
+       do { if ((n) >= nbuffers) allocate_buffers (n); } while (0)
+
+/* Make sure `buffers' has at least N elements. */
+static void
+allocate_buffers (n)
+     int n;
+{
+  register int i, orig_nbuffers;
+
+  orig_nbuffers = nbuffers;
+  nbuffers = n + 20;
+  buffers = (BUFFERED_STREAM **)xrealloc
+    (buffers, nbuffers * sizeof (BUFFERED_STREAM *));
+
+  /* Zero out the new buffers. */
+  for (i = orig_nbuffers; i < nbuffers; i++)
+    buffers[i] = (BUFFERED_STREAM *)NULL;
+}
+
+/* Construct and return a BUFFERED_STREAM corresponding to file descriptor
+   FD, using BUFFER. */
+static BUFFERED_STREAM *
+make_buffered_stream (fd, buffer, bufsize)
+     int fd;
+     char *buffer;
+     size_t bufsize;
+{
+  BUFFERED_STREAM *bp;
+
+  bp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
+  ALLOCATE_BUFFERS (fd);
+  buffers[fd] = bp;
+  bp->b_fd = fd;
+  bp->b_buffer = buffer;
+  bp->b_size = bufsize;
+  bp->b_used = bp->b_inputp = bp->b_flag = 0;
+  if (bufsize == 1)
+    bp->b_flag |= B_UNBUFF;
+  return (bp);
+}
+
+/* Allocate a new BUFFERED_STREAM, copy BP to it, and return the new copy. */
+static BUFFERED_STREAM *
+copy_buffered_stream (bp)
+     BUFFERED_STREAM *bp;
+{
+  BUFFERED_STREAM *nbp;
+
+  if (!bp)
+    return ((BUFFERED_STREAM *)NULL);
+
+  nbp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
+  xbcopy ((char *)bp, (char *)nbp, sizeof (BUFFERED_STREAM));
+  return (nbp);
+}
+
+int
+set_bash_input_fd (fd)
+     int fd;
+{
+  if (bash_input.type == st_bstream)
+    bash_input.location.buffered_fd = fd;
+  else if (interactive_shell == 0)
+    default_buffered_input = fd;
+  return 0;
+}
+
+int
+fd_is_bash_input (fd)
+     int fd;
+{
+  if (bash_input.type == st_bstream && bash_input.location.buffered_fd == fd)
+    return 1;
+  else if (interactive_shell == 0 && default_buffered_input == fd)
+    return 1;
+  return 0;
+}
+
+/* Save the buffered stream corresponding to file descriptor FD (which bash
+   is using to read input) to a buffered stream associated with NEW_FD.  If
+   NEW_FD is -1, a new file descriptor is allocated with fcntl.  The new
+   file descriptor is returned on success, -1 on error. */
+int
+save_bash_input (fd, new_fd)
+     int fd, new_fd;
+{
+  int nfd;
+
+  /* Sync the stream so we can re-read from the new file descriptor.  We
+     might be able to avoid this by copying the buffered stream verbatim
+     to the new file descriptor. */
+  if (buffers[fd])
+    sync_buffered_stream (fd);
+
+  /* Now take care of duplicating the file descriptor that bash is
+     using for input, so we can reinitialize it later. */
+  nfd = (new_fd == -1) ? fcntl (fd, F_DUPFD, 10) : new_fd;
+  if (nfd == -1)
+    {
+      if (fcntl (fd, F_GETFD, 0) == 0)
+       sys_error (_("cannot allocate new file descriptor for bash input from fd %d"), fd);
+      return -1;
+    }
+
+  if (buffers[nfd])
+    {
+      /* What's this?  A stray buffer without an associated open file
+        descriptor?  Free up the buffer and report the error. */
+      internal_error (_("save_bash_input: buffer already exists for new fd %d"), nfd);
+      free_buffered_stream (buffers[nfd]);
+    }
+
+  /* Reinitialize bash_input.location. */
+  if (bash_input.type == st_bstream)
+    {
+      bash_input.location.buffered_fd = nfd;
+      fd_to_buffered_stream (nfd);
+      close_buffered_fd (fd);  /* XXX */
+    }
+  else
+    /* If the current input type is not a buffered stream, but the shell
+       is not interactive and therefore using a buffered stream to read
+       input (e.g. with an `eval exec 3>output' inside a script), note
+       that the input fd has been changed.  pop_stream() looks at this
+       value and adjusts the input fd to the new value of
+       default_buffered_input accordingly. */
+    bash_input_fd_changed++;
+
+  if (default_buffered_input == fd)
+    default_buffered_input = nfd;
+
+  SET_CLOSE_ON_EXEC (nfd);
+  return nfd;
+}
+
+/* Check that file descriptor FD is not the one that bash is currently
+   using to read input from a script.  FD is about to be duplicated onto,
+   which means that the kernel will close it for us.  If FD is the bash
+   input file descriptor, we need to seek backwards in the script (if
+   possible and necessary -- scripts read from stdin are still unbuffered),
+   allocate a new file descriptor to use for bash input, and re-initialize
+   the buffered stream.  Make sure the file descriptor used to save bash
+   input is set close-on-exec. Returns 0 on success, -1 on failure.  This
+   works only if fd is > 0 -- if fd == 0 and bash is reading input from
+   fd 0, save_bash_input is used instead, to cooperate with input
+   redirection (look at redir.c:add_undo_redirect()). */
+int
+check_bash_input (fd)
+     int fd;
+{
+  if (fd_is_bash_input (fd))
+    {
+      if (fd > 0)
+       return ((save_bash_input (fd, -1) == -1) ? -1 : 0);
+      else if (fd == 0)
+        return ((sync_buffered_stream (fd) == -1) ? -1 : 0);
+    }
+  return 0;
+}
+      
+/* This is the buffered stream analogue of dup2(fd1, fd2).  The
+   BUFFERED_STREAM corresponding to fd2 is deallocated, if one exists.
+   BUFFERS[fd1] is copied to BUFFERS[fd2].  This is called by the
+   redirect code for constructs like 4<&0 and 3</etc/rc.local. */
+int
+duplicate_buffered_stream (fd1, fd2)
+     int fd1, fd2;
+{
+  int is_bash_input, m;
+
+  if (fd1 == fd2)
+    return 0;
+
+  m = max (fd1, fd2);
+  ALLOCATE_BUFFERS (m);
+
+  /* If FD2 is the file descriptor bash is currently using for shell input,
+     we need to do some extra work to make sure that the buffered stream
+     actually exists (it might not if fd1 was not active, and the copy
+     didn't actually do anything). */
+  is_bash_input = (bash_input.type == st_bstream) &&
+                 (bash_input.location.buffered_fd == fd2);
+
+  if (buffers[fd2])
+    {
+      /* If the two objects share the same b_buffer, don't free it. */
+      if (buffers[fd1] && buffers[fd1]->b_buffer && buffers[fd1]->b_buffer == buffers[fd2]->b_buffer)
+       buffers[fd2] = (BUFFERED_STREAM *)NULL;
+      else
+       free_buffered_stream (buffers[fd2]);
+    }
+  buffers[fd2] = copy_buffered_stream (buffers[fd1]);
+  if (buffers[fd2])
+    buffers[fd2]->b_fd = fd2;
+
+  if (is_bash_input)
+    {
+      if (!buffers[fd2])
+       fd_to_buffered_stream (fd2);
+      buffers[fd2]->b_flag |= B_WASBASHINPUT;
+    }
+
+  return (fd2);
+}
+
+/* Return 1 if a seek on FD will succeed. */
+#ifndef __CYGWIN__
+#  define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
+#else
+#  define fd_is_seekable(fd) 0
+#endif /* __CYGWIN__ */
+
+/* Take FD, a file descriptor, and create and return a buffered stream
+   corresponding to it.  If something is wrong and the file descriptor
+   is invalid, return a NULL stream. */
+BUFFERED_STREAM *
+fd_to_buffered_stream (fd)
+     int fd;
+{
+  char *buffer;
+  size_t size;
+  struct stat sb;
+
+  if (fstat (fd, &sb) < 0)
+    {
+      close (fd);
+      return ((BUFFERED_STREAM *)NULL);
+    }
+
+  size = (fd_is_seekable (fd)) ? min (sb.st_size, MAX_INPUT_BUFFER_SIZE) : 1;
+  if (size == 0)
+    size = 1;
+  buffer = (char *)xmalloc (size);
+
+  return (make_buffered_stream (fd, buffer, size));
+}
+
+/* Return a buffered stream corresponding to FILE, a file name. */
+BUFFERED_STREAM *
+open_buffered_stream (file)
+     char *file;
+{
+  int fd;
+
+  fd = open (file, O_RDONLY);
+  return ((fd >= 0) ? fd_to_buffered_stream (fd) : (BUFFERED_STREAM *)NULL);
+}
+
+/* Deallocate a buffered stream and free up its resources.  Make sure we
+   zero out the slot in BUFFERS that points to BP. */
+void
+free_buffered_stream (bp)
+     BUFFERED_STREAM *bp;
+{
+  int n;
+
+  if (!bp)
+    return;
+
+  n = bp->b_fd;
+  if (bp->b_buffer)
+    free (bp->b_buffer);
+  free (bp);
+  buffers[n] = (BUFFERED_STREAM *)NULL;
+}
+
+/* Close the file descriptor associated with BP, a buffered stream, and free
+   up the stream.  Return the status of closing BP's file descriptor. */
+int
+close_buffered_stream (bp)
+     BUFFERED_STREAM *bp;
+{
+  int fd;
+
+  if (!bp)
+    return (0);
+  fd = bp->b_fd;
+  free_buffered_stream (bp);
+  return (close (fd));
+}
+
+/* Deallocate the buffered stream associated with file descriptor FD, and
+   close FD.  Return the status of the close on FD. */
+int
+close_buffered_fd (fd)
+     int fd;
+{
+  if (fd < 0)
+    {
+      errno = EBADF;
+      return -1;
+    }
+  if (fd >= nbuffers || !buffers || !buffers[fd])
+    return (close (fd));
+  return (close_buffered_stream (buffers[fd]));
+}
+
+/* Make the BUFFERED_STREAM associcated with buffers[FD] be BP, and return
+   the old BUFFERED_STREAM. */
+BUFFERED_STREAM *
+set_buffered_stream (fd, bp)
+     int fd;
+     BUFFERED_STREAM *bp;
+{
+  BUFFERED_STREAM *ret;
+
+  ret = buffers[fd];
+  buffers[fd] = bp;
+  return ret;
+}
+
+/* Read a buffer full of characters from BP, a buffered stream. */
+static int
+b_fill_buffer (bp)
+     BUFFERED_STREAM *bp;
+{
+  ssize_t nr;
+
+  CHECK_TERMSIG;
+  nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
+  if (nr <= 0)
+    {
+      bp->b_used = 0;
+      bp->b_buffer[0] = 0;
+      if (nr == 0)
+       bp->b_flag |= B_EOF;
+      else
+       bp->b_flag |= B_ERROR;
+      return (EOF);
+    }
+
+#if defined (__CYGWIN__)
+  /* If on cygwin, translate \r\n to \n. */
+  if (nr >= 2 && bp->b_buffer[nr - 2] == '\r' && bp->b_buffer[nr - 1] == '\n')
+    {
+      bp->b_buffer[nr - 2] = '\n';
+      nr--;
+    }
+#endif
+
+  bp->b_used = nr;
+  bp->b_inputp = 0;
+  return (bp->b_buffer[bp->b_inputp++] & 0xFF);
+}
+
+/* Get a character from buffered stream BP. */
+#define bufstream_getc(bp) \
+  (bp->b_inputp == bp->b_used || !bp->b_used) \
+               ? b_fill_buffer (bp) \
+               : bp->b_buffer[bp->b_inputp++] & 0xFF
+
+/* Push C back onto buffered stream BP. */
+static int
+bufstream_ungetc(c, bp)
+     int c;
+     BUFFERED_STREAM *bp;
+{
+  if (c == EOF || bp->b_inputp == 0)
+    return (EOF);
+
+  bp->b_buffer[--bp->b_inputp] = c;
+  return (c);
+}
+
+/* Seek backwards on file BFD to synchronize what we've read so far
+   with the underlying file pointer. */
+int
+sync_buffered_stream (bfd)
+     int bfd;
+{
+  BUFFERED_STREAM *bp;
+  off_t chars_left;
+
+  if (buffers == 0 || (bp = buffers[bfd]) == 0)
+    return (-1);
+
+  chars_left = bp->b_used - bp->b_inputp;
+  if (chars_left)
+    lseek (bp->b_fd, -chars_left, SEEK_CUR);
+  bp->b_used = bp->b_inputp = 0;
+  return (0);
+}
+
+int
+buffered_getchar ()
+{
+  CHECK_TERMSIG;
+
+#if !defined (DJGPP)
+  return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
+#else
+  /* On DJGPP, ignore \r. */
+  int ch;
+  while ((ch = bufstream_getc (buffers[bash_input.location.buffered_fd])) == '\r')
+    ;
+  return ch;
+#endif
+}
+
+int
+buffered_ungetchar (c)
+     int c;
+{
+  return (bufstream_ungetc (c, buffers[bash_input.location.buffered_fd]));
+}
+
+/* Make input come from file descriptor BFD through a buffered stream. */
+void
+with_input_from_buffered_stream (bfd, name)
+     int bfd;
+     char *name;
+{
+  INPUT_STREAM location;
+  BUFFERED_STREAM *bp;
+
+  location.buffered_fd = bfd;
+  /* Make sure the buffered stream exists. */
+  bp = fd_to_buffered_stream (bfd);
+  init_yy_io (bp == 0 ? return_EOF : buffered_getchar,
+             buffered_ungetchar, st_bstream, name, location);
+}
+
+#if defined (TEST)
+void *
+xmalloc(s)
+int s;
+{
+       return (malloc (s));
+}
+
+void *
+xrealloc(s, size)
+char   *s;
+int    size;
+{
+       if (!s)
+               return(malloc (size));
+       else
+               return(realloc (s, size));
+}
+
+void
+init_yy_io ()
+{
+}
+
+process(bp)
+BUFFERED_STREAM *bp;
+{
+       int c;
+
+       while ((c = bufstream_getc(bp)) != EOF)
+               putchar(c);
+}
+
+BASH_INPUT bash_input;
+
+struct stat dsb;               /* can be used from gdb */
+
+/* imitate /bin/cat */
+main(argc, argv)
+int    argc;
+char   **argv;
+{
+       register int i;
+       BUFFERED_STREAM *bp;
+
+       if (argc == 1) {
+               bp = fd_to_buffered_stream (0);
+               process(bp);
+               exit(0);
+       }
+       for (i = 1; i < argc; i++) {
+               if (argv[i][0] == '-' && argv[i][1] == '\0') {
+                       bp = fd_to_buffered_stream (0);
+                       if (!bp)
+                               continue;
+                       process(bp);
+                       free_buffered_stream (bp);
+               } else {
+                       bp = open_buffered_stream (argv[i]);
+                       if (!bp)
+                               continue;
+                       process(bp);
+                       close_buffered_stream (bp);
+               }
+       }
+       exit(0);
+}
+#endif /* TEST */
+#endif /* BUFFERED_INPUT */
diff --git a/jobs.c b/jobs.c
index 32df5a0a370481eb43bbae26a7f8c7c98e7e6512..5e4b1f67589299a67edbb883370de2d4294b363c 100644 (file)
--- a/jobs.c
+++ b/jobs.c
@@ -142,7 +142,6 @@ typedef int sh_job_map_func_t __P((JOB *, int, int, int));
 /* Variables used here but defined in other files. */
 extern int subshell_environment, line_number;
 extern int posixly_correct, shell_level;
-extern int interrupt_immediately;
 extern int last_command_exit_value, last_command_exit_signal;
 extern int loop_level, breaking;
 extern int sourcelevel;
@@ -761,7 +760,7 @@ bgp_search (pid)
 static void
 bgp_prune ()
 {
-  struct pidstat *ps, *p;
+  struct pidstat *ps;
 
   while (bgpids.npid > js.c_childmax)
     {
@@ -975,8 +974,7 @@ delete_job (job_index, dflags)
 {
   register JOB *temp;
   PROCESS *proc;
-  int ndel, status;
-  pid_t pid;
+  int ndel;
 
   if (js.j_jobslots == 0 || jobs_list_frozen)
     return;
@@ -2827,14 +2825,14 @@ start_job (job, foreground)
   if (foreground)
     {
       pid_t pid;
-      int s;
+      int st;
 
       pid = find_last_pid (job, 0);
       UNBLOCK_CHILD (oset);
-      s = wait_for (pid);
+      st = wait_for (pid);
       shell_tty_info = save_stty;
       set_tty_state ();
-      return (s);
+      return (st);
     }
   else
     {
diff --git a/jobs.c~ b/jobs.c~
index bdd0e0ab0bdb880a721f8a358b323362573e037b..9a970cd90696cfe7e42cf2e51de8d676898ce831 100644 (file)
--- a/jobs.c~
+++ b/jobs.c~
@@ -142,7 +142,6 @@ typedef int sh_job_map_func_t __P((JOB *, int, int, int));
 /* Variables used here but defined in other files. */
 extern int subshell_environment, line_number;
 extern int posixly_correct, shell_level;
-extern int interrupt_immediately;
 extern int last_command_exit_value, last_command_exit_signal;
 extern int loop_level, breaking;
 extern int sourcelevel;
@@ -761,7 +760,7 @@ bgp_search (pid)
 static void
 bgp_prune ()
 {
-  struct pidstat *ps, *p;
+  struct pidstat *ps;
 
   while (bgpids.npid > js.c_childmax)
     {
@@ -975,8 +974,7 @@ delete_job (job_index, dflags)
 {
   register JOB *temp;
   PROCESS *proc;
-  int ndel, status;
-  pid_t pid;
+  int ndel;
 
   if (js.j_jobslots == 0 || jobs_list_frozen)
     return;
@@ -1079,7 +1077,6 @@ add_process (name, pid)
 {
   PROCESS *t, *p;
 
-itrace("add_process: name = %s running_trap = %d", name, running_trap);
 #if defined (RECYCLES_PIDS)
   int j;
   p = find_process (pid, 0, &j);
@@ -1670,7 +1667,6 @@ make_child (command, async_p)
   sigemptyset (&oset);
   sigprocmask (SIG_BLOCK, &set, &oset);
 
-itrace("make_child: command = %s", command ? command : "");
   making_children ();
 
 #if defined (BUFFERED_INPUT)
@@ -3436,7 +3432,6 @@ notify_of_job_status ()
              fprintf (stderr, "\n");
              if (dir == 0)
                dir = current_working_directory ();
-itrace("calling pretty_print_job for job %d", job);
              pretty_print_job (job, JLIST_STANDARD, stderr);
              if (dir && (strcmp (dir, jobs[job]->wd) != 0))
                fprintf (stderr,
index 5c564f660b280bfc1158231d009883311d0532b8..08a7da8532a4dca674a5e832967676da05cf7c47 100644 (file)
@@ -184,7 +184,7 @@ mbskipname (pat, dname)
 {
   int ret;
   wchar_t *pat_wc, *dn_wc;
-  size_t pat_n, dn_n, n;
+  size_t pat_n, dn_n;
 
   pat_n = xdupmbstowcs (&pat_wc, NULL, pat);
   dn_n = xdupmbstowcs (&dn_wc, NULL, dname);
index 12fde3d0ff4ba1def425c9591b41779d1d05d4ad..be4f927c735b283f894acfbbb13fa18b40ca52f2 100644 (file)
@@ -247,7 +247,6 @@ rangecmp_wc (c1, c2)
 {
   static wchar_t s1[2] = { L' ', L'\0' };
   static wchar_t s2[2] = { L' ', L'\0' };
-  int ret;
 
   if (c1 == c2)
     return 0;
index c40e4ef76cbe6b5a0fd9603625cbe3227791c3f8..08c906bfcc3371682f4bd91945b858d7770e5af1 100644 (file)
@@ -1537,7 +1537,6 @@ rl_variable_value (name)
      const char *name;
 {
   register int i;
-  int  v;
 
   /* Check for simple variables first. */
   i = find_boolean_var (name);
index e7f6af108771d8764e426c079ae807bd948f03b2..73f834a68a79a2fe0d47087de3c06dd7e5fab282 100644 (file)
@@ -1104,7 +1104,8 @@ compute_lcd_of_matches (match_list, matches, text)
 #if defined (HANDLE_MULTIBYTE)
            if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
              {
-               mbstate_t ps_back = ps1;
+               mbstate_t ps_back;
+               ps_back = ps1;
                if (!_rl_compare_chars (match_list[i], si, &ps1, match_list[i+1], si, &ps2))
                  break;
                else if ((v = _rl_get_char_len (&match_list[i][si], &ps_back)) > 1)
@@ -1896,7 +1897,6 @@ rl_filename_completion_function (text, state)
   static char *filename = (char *)NULL;
   static char *dirname = (char *)NULL;
   static char *users_dirname = (char *)NULL;
-  static char *orig_filename = (char *)NULL;
   static int filename_len;
   char *temp;
   int dirlen;
index d188a262cd69fbb0c78d83ac6971284b64e38e19..ad253b166c81984c6e596c6308fa0122dcb40950 100644 (file)
@@ -950,7 +950,7 @@ gen_completion_matches (text, start, end, our_func, found_quote, quote_char)
      rl_compentry_func_t *our_func;
      int found_quote, quote_char;
 {
-  char **matches, *temp;
+  char **matches;
 
   rl_completion_found_quote = found_quote;
   rl_completion_quote_character = quote_char;
@@ -969,28 +969,9 @@ gen_completion_matches (text, start, end, our_func, found_quote, quote_char)
        }
     }
 
-  /* Beware -- we're stripping the quotes here.  Do this only if we know
-     we are doing filename completion and the application has defined a
-     filename dequoting function. */
-  /* XXX -- can move this into rl_filename_completion_function and use
-     rl_completion_found_quote and rl_completion_quote_char.  Should be
-     after the directory rewriting hook and maybe the directory completion
-     hook.  Also need to change bash_directory_expansion in the same way
-     as rl_filename_completion_function. */
-  temp = (char *)NULL;
-
-#if 0
-  if (found_quote && our_func == rl_filename_completion_function &&
-      rl_filename_dequoting_function)
-    {
-      /* delete single and double quotes */
-      temp = (*rl_filename_dequoting_function) (text, quote_char);
-      text = temp;     /* not freeing text is not a memory leak */
-    }
-#endif
+  /* XXX -- filename dequoting moved into rl_filename_completion_function */
 
   matches = rl_completion_matches (text, our_func);
-  FREE (temp);
   return matches;  
 }
 
index 253cf65f8b38427d147edf7750ed0bba780f7276..288b37bb438a00365ff898ad18ced8463030664f 100644 (file)
@@ -2365,12 +2365,14 @@ _rl_col_width (str, start, end)
      int start, end;
 {
   wchar_t wc;
-  mbstate_t ps = {0};
+  mbstate_t ps;
   int tmp, point, width, max;
 
   if (end <= start)
     return 0;
 
+  memset (&ps, 0, sizeof (mbstate_t));
+
   point = 0;
   max = end;
 
index 5b48aab1926c6b3fc4cda728e85a60e9052faa30..253cf65f8b38427d147edf7750ed0bba780f7276 100644 (file)
@@ -1,6 +1,6 @@
 /* display.c -- readline redisplay facility. */
 
-/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2006 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.
 extern char *strchr (), *strrchr ();
 #endif /* !strchr && !__STDC__ */
 
-#if defined (HACK_TERMCAP_MOTION)
-extern char *_rl_term_forward_char;
-#endif
-
 static void update_line PARAMS((char *, char *, int, int, int, int));
 static void space_to_eol PARAMS((int));
 static void delete_chars PARAMS((int));
@@ -80,7 +76,8 @@ static int *inv_lbreaks, *vis_lbreaks;
 static int inv_lbsize, vis_lbsize;
 
 /* Heuristic used to decide whether it is faster to move from CUR to NEW
-   by backing up or outputting a carriage return and moving forward. */
+   by backing up or outputting a carriage return and moving forward.  CUR
+   and NEW are either both buffer positions or absolute screen positions. */
 #define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new)))
 
 /* _rl_last_c_pos is an absolute cursor position in multibyte locales and a
@@ -143,6 +140,7 @@ int _rl_last_c_pos = 0;
 int _rl_last_v_pos = 0;
 
 static int cpos_adjusted;
+static int cpos_buffer_position;
 
 /* Number of lines currently on screen minus 1. */
 int _rl_vis_botlin = 0;
@@ -460,7 +458,7 @@ rl_redisplay ()
 {
   register int in, out, c, linenum, cursor_linenum;
   register char *line;
-  int c_pos, inv_botlin, lb_botlin, lb_linenum, o_cpos;
+  int inv_botlin, lb_botlin, lb_linenum, o_cpos;
   int newlines, lpos, temp, modmark, n0, num;
   char *prompt_this_line;
 #if defined (HANDLE_MULTIBYTE)
@@ -484,7 +482,7 @@ rl_redisplay ()
     }
 
   /* Draw the line into the buffer. */
-  c_pos = -1;
+  cpos_buffer_position = -1;
 
   line = invisible_line;
   out = inv_botlin = 0;
@@ -666,7 +664,7 @@ rl_redisplay ()
   prompt_last_screen_line = newlines;
 
   /* Draw the rest of the line (after the prompt) into invisible_line, keeping
-     track of where the cursor is (c_pos), the number of the line containing
+     track of where the cursor is (cpos_buffer_position), the number of the line containing
      the cursor (lb_linenum), the last line number (lb_botlin and inv_botlin).
      It maintains an array of line breaks for display (inv_lbreaks).
      This handles expanding tabs for display and displaying meta characters. */
@@ -719,7 +717,7 @@ rl_redisplay ()
 
       if (in == rl_point)
        {
-         c_pos = out;
+         cpos_buffer_position = out;
          lb_linenum = newlines;
        }
 
@@ -813,7 +811,7 @@ rl_redisplay ()
                  }
              if (in == rl_point)
                {
-                 c_pos = out;
+                 cpos_buffer_position = out;
                  lb_linenum = newlines;
                }
              for (i = in; i < in+wc_bytes; i++)
@@ -844,9 +842,9 @@ rl_redisplay ()
 
     }
   line[out] = '\0';
-  if (c_pos < 0)
+  if (cpos_buffer_position < 0)
     {
-      c_pos = out;
+      cpos_buffer_position = out;
       lb_linenum = newlines;
     }
 
@@ -855,7 +853,7 @@ rl_redisplay ()
   inv_lbreaks[newlines+1] = out;
   cursor_linenum = lb_linenum;
 
-  /* C_POS == position in buffer where cursor should be placed.
+  /* CPOS_BUFFER_POSITION == position in buffer where cursor should be placed.
      CURSOR_LINENUM == line number where the cursor should be placed. */
 
   /* PWP: now is when things get a bit hairy.  The visible and invisible
@@ -1011,7 +1009,7 @@ rl_redisplay ()
          pos = inv_lbreaks[cursor_linenum];
          /* nleft == number of characters in the line buffer between the
             start of the line and the desired cursor position. */
-         nleft = c_pos - pos;
+         nleft = cpos_buffer_position - pos;
 
          /* NLEFT is now a number of characters in a buffer.  When in a
             multibyte locale, however, _rl_last_c_pos is an absolute cursor
@@ -1057,11 +1055,11 @@ rl_redisplay ()
         will be LMARGIN. */
 
       /* The number of characters that will be displayed before the cursor. */
-      ndisp = c_pos - wrap_offset;
+      ndisp = cpos_buffer_position - wrap_offset;
       nleft  = prompt_visible_length + wrap_offset;
       /* Where the new cursor position will be on the screen.  This can be
         longer than SCREENWIDTH; if it is, lmargin will be adjusted. */
-      phys_c_pos = c_pos - (last_lmargin ? last_lmargin : wrap_offset);
+      phys_c_pos = cpos_buffer_position - (last_lmargin ? last_lmargin : wrap_offset);
       t = _rl_screenwidth / 3;
 
       /* If the number of characters had already exceeded the screenwidth,
@@ -1072,7 +1070,7 @@ rl_redisplay ()
         two-thirds of the way across the screen. */
       if (phys_c_pos > _rl_screenwidth - 2)
        {
-         lmargin = c_pos - (2 * t);
+         lmargin = cpos_buffer_position - (2 * t);
          if (lmargin < 0)
            lmargin = 0;
          /* If the left margin would be in the middle of a prompt with
@@ -1086,7 +1084,7 @@ rl_redisplay ()
        {
          /* If we are moving back towards the beginning of the line and
             the last margin is no longer correct, compute a new one. */
-         lmargin = ((c_pos - 1) / t) * t;      /* XXX */
+         lmargin = ((cpos_buffer_position - 1) / t) * t;       /* XXX */
          if (wrap_offset && lmargin > 0 && lmargin < nleft)
            lmargin = nleft;
        }
@@ -1131,7 +1129,7 @@ rl_redisplay ()
          if (visible_first_line_len > _rl_screenwidth)
            visible_first_line_len = _rl_screenwidth;
 
-         _rl_move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]);
+         _rl_move_cursor_relative (cpos_buffer_position - lmargin, &invisible_line[lmargin]);
          last_lmargin = lmargin;
        }
     }
@@ -1724,13 +1722,12 @@ _rl_move_cursor_relative (new, data)
   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
     {
       dpos = _rl_col_width (data, 0, new);
-#if 0
-      if (dpos > woff)
-#else
-      if (dpos > prompt_last_invisible)
-#endif
+      if (dpos > prompt_last_invisible)                /* XXX - don't use woff here */
        {
          dpos -= woff;
+         /* Since this will be assigned to _rl_last_c_pos at the end (more
+            precisely, _rl_last_c_pos == dpos when this function returns),
+            let the caller know. */
          cpos_adjusted = 1;
        }
     }
@@ -1751,7 +1748,7 @@ _rl_move_cursor_relative (new, data)
   else
 #endif
   i = _rl_last_c_pos - woff;
-  if (new == 0 || CR_FASTER (new, _rl_last_c_pos) ||
+  if (dpos == 0 || CR_FASTER (dpos, _rl_last_c_pos) ||
       (_rl_term_autowrap && i == _rl_screenwidth))
     {
 #if defined (__MSDOS__)
@@ -1773,19 +1770,27 @@ _rl_move_cursor_relative (new, data)
         sequence telling the terminal to move forward one character.
         That kind of control is for people who don't know what the
         data is underneath the cursor. */
-#if defined (HACK_TERMCAP_MOTION)
-      if (_rl_term_forward_char)
-       {
-         for (i = cpos; i < dpos; i++)
-           tputs (_rl_term_forward_char, 1, _rl_output_character_function);
-       }
-      else
-#endif /* HACK_TERMCAP_MOTION */
+
+      /* However, we need a handle on where the current display position is
+        in the buffer for the immediately preceding comment to be true.
+        In multibyte locales, we don't currently have that info available.
+        Without it, we don't know where the data we have to display begins
+        in the buffer and we have to go back to the beginning of the screen
+        line.  In this case, we can use the terminal sequence to move forward
+        if it's available. */
       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
        {
-         tputs (_rl_term_cr, 1, _rl_output_character_function);
-         for (i = 0; i < new; i++)
-           putc (data[i], rl_outstream);
+         if (_rl_term_forward_char)
+           {
+             for (i = cpos; i < dpos; i++)
+               tputs (_rl_term_forward_char, 1, _rl_output_character_function);
+           }
+         else
+           {
+             tputs (_rl_term_cr, 1, _rl_output_character_function);
+             for (i = 0; i < new; i++)
+               putc (data[i], rl_outstream);
+           }
        }
       else
        for (i = cpos; i < new; i++)
@@ -2213,7 +2218,8 @@ _rl_update_final ()
       char *last_line;
 
       last_line = &visible_line[vis_lbreaks[_rl_vis_botlin]];
-      _rl_move_cursor_relative (_rl_screenwidth - 1, last_line);
+      cpos_buffer_position = -1;       /* don't know where we are in buffer */
+      _rl_move_cursor_relative (_rl_screenwidth - 1, last_line);       /* XXX */
       _rl_clear_to_eol (0);
       putc (last_line[_rl_screenwidth - 1], rl_outstream);
     }
index 684701469022f82140780eb1881c83cd0c45a149..f46c0b2a45d810c95e7578012b51e0d80a375364 100644 (file)
@@ -56,8 +56,6 @@
 
 typedef int _hist_search_func_t PARAMS((const char *, int));
 
-extern int rl_byte_oriented;   /* declared in mbutil.c */
-
 static char error_pointer;
 
 static char *subst_lhs;
@@ -564,12 +562,12 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
 #if defined (HANDLE_MULTIBYTE)
       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
        {
-         int c, l;
+         int ch, l;
          l = _rl_find_prev_mbchar (string, i, MB_FIND_ANY);
-         c = string[l];
+         ch = string[l];
          /* XXX - original patch had i - 1 ???  If i == 0 it would fail. */
-         if (i && (c == '\'' || c == '"'))
-           quoted_search_delimiter = c;
+         if (i && (ch == '\'' || ch == '"'))
+           quoted_search_delimiter = ch;
        }
       else
 #endif /* HANDLE_MULTIBYTE */    
@@ -1430,6 +1428,8 @@ history_tokenize_word (string, ind)
        {
          if (peek == '<' && string[i + 2] == '-')
            i++;
+         else if (peek == '<' && string[i + 2] == '<')
+           i++;
          i += 2;
          return i;
        }
diff --git a/lib/readline/histexpand.c~ b/lib/readline/histexpand.c~
new file mode 100644 (file)
index 0000000..dd98726
--- /dev/null
@@ -0,0 +1,1593 @@
+/* histexpand.c -- history expansion. */
+
+/* Copyright (C) 1989-2004 Free Software Foundation, Inc.
+
+   This file contains the GNU History Library (the Library), a set of
+   routines for managing the text of previously typed lines.
+
+   The Library is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   The Library is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   The GNU General Public License is often shipped with GNU software, and
+   is generally kept in a file called COPYING or LICENSE.  If you do not
+   have a copy of the license, write to the Free Software Foundation,
+   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+
+#if defined (HAVE_STDLIB_H)
+#  include <stdlib.h>
+#else
+#  include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#if defined (HAVE_UNISTD_H)
+#  ifndef _MINIX
+#    include <sys/types.h>
+#  endif
+#  include <unistd.h>
+#endif
+
+#include "rlmbutil.h"
+
+#include "history.h"
+#include "histlib.h"
+
+#include "rlshell.h"
+#include "xmalloc.h"
+
+#define HISTORY_WORD_DELIMITERS                " \t\n;&()|<>"
+#define HISTORY_QUOTE_CHARACTERS       "\"'`"
+
+#define slashify_in_quotes "\\`\"$"
+
+typedef int _hist_search_func_t PARAMS((const char *, int));
+
+static char error_pointer;
+
+static char *subst_lhs;
+static char *subst_rhs;
+static int subst_lhs_len;
+static int subst_rhs_len;
+
+static char *get_history_word_specifier PARAMS((char *, char *, int *));
+static char *history_find_word PARAMS((char *, int));
+static int history_tokenize_word PARAMS((const char *, int));
+static char *history_substring PARAMS((const char *, int, int));
+
+static char *quote_breaks PARAMS((char *));
+
+/* Variables exported by this file. */
+/* The character that represents the start of a history expansion
+   request.  This is usually `!'. */
+char history_expansion_char = '!';
+
+/* The character that invokes word substitution if found at the start of
+   a line.  This is usually `^'. */
+char history_subst_char = '^';
+
+/* During tokenization, if this character is seen as the first character
+   of a word, then it, and all subsequent characters upto a newline are
+   ignored.  For a Bourne shell, this should be '#'.  Bash special cases
+   the interactive comment character to not be a comment delimiter. */
+char history_comment_char = '\0';
+
+/* The list of characters which inhibit the expansion of text if found
+   immediately following history_expansion_char. */
+char *history_no_expand_chars = " \t\n\r=";
+
+/* If set to a non-zero value, single quotes inhibit history expansion.
+   The default is 0. */
+int history_quotes_inhibit_expansion = 0;
+
+/* Used to split words by history_tokenize_internal. */
+char *history_word_delimiters = HISTORY_WORD_DELIMITERS;
+
+/* If set, this points to a function that is called to verify that a
+   particular history expansion should be performed. */
+rl_linebuf_func_t *history_inhibit_expansion_function;
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     History Expansion                           */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Hairy history expansion on text, not tokens.  This is of general
+   use, and thus belongs in this library. */
+
+/* The last string searched for by a !?string? search. */
+static char *search_string;
+
+/* The last string matched by a !?string? search. */
+static char *search_match;
+
+/* Return the event specified at TEXT + OFFSET modifying OFFSET to
+   point to after the event specifier.  Just a pointer to the history
+   line is returned; NULL is returned in the event of a bad specifier.
+   You pass STRING with *INDEX equal to the history_expansion_char that
+   begins this specification.
+   DELIMITING_QUOTE is a character that is allowed to end the string
+   specification for what to search for in addition to the normal
+   characters `:', ` ', `\t', `\n', and sometimes `?'.
+   So you might call this function like:
+   line = get_history_event ("!echo:p", &index, 0);  */
+char *
+get_history_event (string, caller_index, delimiting_quote)
+     const char *string;
+     int *caller_index;
+     int delimiting_quote;
+{
+  register int i;
+  register char c;
+  HIST_ENTRY *entry;
+  int which, sign, local_index, substring_okay;
+  _hist_search_func_t *search_func;
+  char *temp;
+
+  /* The event can be specified in a number of ways.
+
+     !!   the previous command
+     !n   command line N
+     !-n  current command-line minus N
+     !str the most recent command starting with STR
+     !?str[?]
+         the most recent command containing STR
+
+     All values N are determined via HISTORY_BASE. */
+
+  i = *caller_index;
+
+  if (string[i] != history_expansion_char)
+    return ((char *)NULL);
+
+  /* Move on to the specification. */
+  i++;
+
+  sign = 1;
+  substring_okay = 0;
+
+#define RETURN_ENTRY(e, w) \
+       return ((e = history_get (w)) ? e->line : (char *)NULL)
+
+  /* Handle !! case. */
+  if (string[i] == history_expansion_char)
+    {
+      i++;
+      which = history_base + (history_length - 1);
+      *caller_index = i;
+      RETURN_ENTRY (entry, which);
+    }
+
+  /* Hack case of numeric line specification. */
+  if (string[i] == '-')
+    {
+      sign = -1;
+      i++;
+    }
+
+  if (_rl_digit_p (string[i]))
+    {
+      /* Get the extent of the digits and compute the value. */
+      for (which = 0; _rl_digit_p (string[i]); i++)
+       which = (which * 10) + _rl_digit_value (string[i]);
+
+      *caller_index = i;
+
+      if (sign < 0)
+       which = (history_length + history_base) - which;
+
+      RETURN_ENTRY (entry, which);
+    }
+
+  /* This must be something to search for.  If the spec begins with
+     a '?', then the string may be anywhere on the line.  Otherwise,
+     the string must be found at the start of a line. */
+  if (string[i] == '?')
+    {
+      substring_okay++;
+      i++;
+    }
+
+  /* Only a closing `?' or a newline delimit a substring search string. */
+  for (local_index = i; c = string[i]; i++)
+    {
+#if defined (HANDLE_MULTIBYTE)
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+       {
+         int v;
+         mbstate_t ps;
+
+         memset (&ps, 0, sizeof (mbstate_t));
+         /* These produce warnings because we're passing a const string to a
+            function that takes a non-const string. */
+         _rl_adjust_point ((char *)string, i, &ps);
+         if ((v = _rl_get_char_len ((char *)string + i, &ps)) > 1)
+           {
+             i += v - 1;
+             continue;
+           }
+        }
+
+#endif /* HANDLE_MULTIBYTE */
+      if ((!substring_okay && (whitespace (c) || c == ':' ||
+         (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||
+         string[i] == delimiting_quote)) ||
+         string[i] == '\n' ||
+         (substring_okay && string[i] == '?'))
+       break;
+    }
+
+  which = i - local_index;
+  temp = (char *)xmalloc (1 + which);
+  if (which)
+    strncpy (temp, string + local_index, which);
+  temp[which] = '\0';
+
+  if (substring_okay && string[i] == '?')
+    i++;
+
+  *caller_index = i;
+
+#define FAIL_SEARCH() \
+  do { \
+    history_offset = history_length; free (temp) ; return (char *)NULL; \
+  } while (0)
+
+  /* If there is no search string, try to use the previous search string,
+     if one exists.  If not, fail immediately. */
+  if (*temp == '\0' && substring_okay)
+    {
+      if (search_string)
+        {
+          free (temp);
+          temp = savestring (search_string);
+        }
+      else
+        FAIL_SEARCH ();
+    }
+
+  search_func = substring_okay ? history_search : history_search_prefix;
+  while (1)
+    {
+      local_index = (*search_func) (temp, -1);
+
+      if (local_index < 0)
+       FAIL_SEARCH ();
+
+      if (local_index == 0 || substring_okay)
+       {
+         entry = current_history ();
+         history_offset = history_length;
+       
+         /* If this was a substring search, then remember the
+            string that we matched for word substitution. */
+         if (substring_okay)
+           {
+             FREE (search_string);
+             search_string = temp;
+
+             FREE (search_match);
+             search_match = history_find_word (entry->line, local_index);
+           }
+         else
+           free (temp);
+
+         return (entry->line);
+       }
+
+      if (history_offset)
+       history_offset--;
+      else
+       FAIL_SEARCH ();
+    }
+#undef FAIL_SEARCH
+#undef RETURN_ENTRY
+}
+
+/* Function for extracting single-quoted strings.  Used for inhibiting
+   history expansion within single quotes. */
+
+/* Extract the contents of STRING as if it is enclosed in single quotes.
+   SINDEX, when passed in, is the offset of the character immediately
+   following the opening single quote; on exit, SINDEX is left pointing
+   to the closing single quote. */
+static void
+hist_string_extract_single_quoted (string, sindex)
+     char *string;
+     int *sindex;
+{
+  register int i;
+
+  for (i = *sindex; string[i] && string[i] != '\''; i++)
+    ;
+
+  *sindex = i;
+}
+
+static char *
+quote_breaks (s)
+     char *s;
+{
+  register char *p, *r;
+  char *ret;
+  int len = 3;
+
+  for (p = s; p && *p; p++, len++)
+    {
+      if (*p == '\'')
+       len += 3;
+      else if (whitespace (*p) || *p == '\n')
+       len += 2;
+    }
+
+  r = ret = (char *)xmalloc (len);
+  *r++ = '\'';
+  for (p = s; p && *p; )
+    {
+      if (*p == '\'')
+       {
+         *r++ = '\'';
+         *r++ = '\\';
+         *r++ = '\'';
+         *r++ = '\'';
+         p++;
+       }
+      else if (whitespace (*p) || *p == '\n')
+       {
+         *r++ = '\'';
+         *r++ = *p++;
+         *r++ = '\'';
+       }
+      else
+       *r++ = *p++;
+    }
+  *r++ = '\'';
+  *r = '\0';
+  return ret;
+}
+
+static char *
+hist_error(s, start, current, errtype)
+      char *s;
+      int start, current, errtype;
+{
+  char *temp;
+  const char *emsg;
+  int ll, elen;
+
+  ll = current - start;
+
+  switch (errtype)
+    {
+    case EVENT_NOT_FOUND:
+      emsg = "event not found";
+      elen = 15;
+      break;
+    case BAD_WORD_SPEC:
+      emsg = "bad word specifier";
+      elen = 18;
+      break;
+    case SUBST_FAILED:
+      emsg = "substitution failed";
+      elen = 19;
+      break;
+    case BAD_MODIFIER:
+      emsg = "unrecognized history modifier";
+      elen = 29;
+      break;
+    case NO_PREV_SUBST:
+      emsg = "no previous substitution";
+      elen = 24;
+      break;
+    default:
+      emsg = "unknown expansion error";
+      elen = 23;
+      break;
+    }
+
+  temp = (char *)xmalloc (ll + elen + 3);
+  strncpy (temp, s + start, ll);
+  temp[ll] = ':';
+  temp[ll + 1] = ' ';
+  strcpy (temp + ll + 2, emsg);
+  return (temp);
+}
+
+/* Get a history substitution string from STR starting at *IPTR
+   and return it.  The length is returned in LENPTR.
+
+   A backslash can quote the delimiter.  If the string is the
+   empty string, the previous pattern is used.  If there is
+   no previous pattern for the lhs, the last history search
+   string is used.
+
+   If IS_RHS is 1, we ignore empty strings and set the pattern
+   to "" anyway.  subst_lhs is not changed if the lhs is empty;
+   subst_rhs is allowed to be set to the empty string. */
+
+static char *
+get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr)
+     char *str;
+     int *iptr, delimiter, is_rhs, *lenptr;
+{
+  register int si, i, j, k;
+  char *s;
+#if defined (HANDLE_MULTIBYTE)
+  mbstate_t ps;
+#endif
+
+  s = (char *)NULL;
+  i = *iptr;
+
+#if defined (HANDLE_MULTIBYTE)
+  memset (&ps, 0, sizeof (mbstate_t));
+  _rl_adjust_point (str, i, &ps);
+#endif
+
+  for (si = i; str[si] && str[si] != delimiter; si++)
+#if defined (HANDLE_MULTIBYTE)
+    if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+      {
+       int v;
+       if ((v = _rl_get_char_len (str + si, &ps)) > 1)
+         si += v - 1;
+       else if (str[si] == '\\' && str[si + 1] == delimiter)
+         si++;
+      }
+    else
+#endif /* HANDLE_MULTIBYTE */
+      if (str[si] == '\\' && str[si + 1] == delimiter)
+       si++;
+
+  if (si > i || is_rhs)
+    {
+      s = (char *)xmalloc (si - i + 1);
+      for (j = 0, k = i; k < si; j++, k++)
+       {
+         /* Remove a backslash quoting the search string delimiter. */
+         if (str[k] == '\\' && str[k + 1] == delimiter)
+           k++;
+         s[j] = str[k];
+       }
+      s[j] = '\0';
+      if (lenptr)
+       *lenptr = j;
+    }
+
+  i = si;
+  if (str[i])
+    i++;
+  *iptr = i;
+
+  return s;
+}
+
+static void
+postproc_subst_rhs ()
+{
+  char *new;
+  int i, j, new_size;
+
+  new = (char *)xmalloc (new_size = subst_rhs_len + subst_lhs_len);
+  for (i = j = 0; i < subst_rhs_len; i++)
+    {
+      if (subst_rhs[i] == '&')
+       {
+         if (j + subst_lhs_len >= new_size)
+           new = (char *)xrealloc (new, (new_size = new_size * 2 + subst_lhs_len));
+         strcpy (new + j, subst_lhs);
+         j += subst_lhs_len;
+       }
+      else
+       {
+         /* a single backslash protects the `&' from lhs interpolation */
+         if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&')
+           i++;
+         if (j >= new_size)
+           new = (char *)xrealloc (new, new_size *= 2);
+         new[j++] = subst_rhs[i];
+       }
+    }
+  new[j] = '\0';
+  free (subst_rhs);
+  subst_rhs = new;
+  subst_rhs_len = j;
+}
+
+/* Expand the bulk of a history specifier starting at STRING[START].
+   Returns 0 if everything is OK, -1 if an error occurred, and 1
+   if the `p' modifier was supplied and the caller should just print
+   the returned string.  Returns the new index into string in
+   *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */
+static int
+history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
+     char *string;
+     int start, *end_index_ptr;
+     char **ret_string;
+     char *current_line;       /* for !# */
+{
+  int i, n, starting_index;
+  int substitute_globally, subst_bywords, want_quotes, print_only;
+  char *event, *temp, *result, *tstr, *t, c, *word_spec;
+  int result_len;
+#if defined (HANDLE_MULTIBYTE)
+  mbstate_t ps;
+
+  memset (&ps, 0, sizeof (mbstate_t));
+#endif
+
+  result = (char *)xmalloc (result_len = 128);
+
+  i = start;
+
+  /* If it is followed by something that starts a word specifier,
+     then !! is implied as the event specifier. */
+
+  if (member (string[i + 1], ":$*%^"))
+    {
+      char fake_s[3];
+      int fake_i = 0;
+      i++;
+      fake_s[0] = fake_s[1] = history_expansion_char;
+      fake_s[2] = '\0';
+      event = get_history_event (fake_s, &fake_i, 0);
+    }
+  else if (string[i + 1] == '#')
+    {
+      i += 2;
+      event = current_line;
+    }
+  else
+    {
+      int quoted_search_delimiter = 0;
+
+      /* If the character before this `!' is a double or single
+        quote, then this expansion takes place inside of the
+        quoted string.  If we have to search for some text ("!foo"),
+        allow the delimiter to end the search string. */
+#if defined (HANDLE_MULTIBYTE)
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+       {
+         int c, l;
+         l = _rl_find_prev_mbchar (string, i, MB_FIND_ANY);
+         c = string[l];
+         /* XXX - original patch had i - 1 ???  If i == 0 it would fail. */
+         if (i && (c == '\'' || c == '"'))
+           quoted_search_delimiter = c;
+       }
+      else
+#endif /* HANDLE_MULTIBYTE */    
+       if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
+         quoted_search_delimiter = string[i - 1];
+
+      event = get_history_event (string, &i, quoted_search_delimiter);
+    }
+         
+  if (event == 0)
+    {
+      *ret_string = hist_error (string, start, i, EVENT_NOT_FOUND);
+      free (result);
+      return (-1);
+    }
+
+  /* If a word specifier is found, then do what that requires. */
+  starting_index = i;
+  word_spec = get_history_word_specifier (string, event, &i);
+
+  /* There is no such thing as a `malformed word specifier'.  However,
+     it is possible for a specifier that has no match.  In that case,
+     we complain. */
+  if (word_spec == (char *)&error_pointer)
+    {
+      *ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC);
+      free (result);
+      return (-1);
+    }
+
+  /* If no word specifier, than the thing of interest was the event. */
+  temp = word_spec ? savestring (word_spec) : savestring (event);
+  FREE (word_spec);
+
+  /* Perhaps there are other modifiers involved.  Do what they say. */
+  want_quotes = substitute_globally = subst_bywords = print_only = 0;
+  starting_index = i;
+
+  while (string[i] == ':')
+    {
+      c = string[i + 1];
+
+      if (c == 'g' || c == 'a')
+       {
+         substitute_globally = 1;
+         i++;
+         c = string[i + 1];
+       }
+      else if (c == 'G')
+       {
+         subst_bywords = 1;
+         i++;
+         c = string[i + 1];
+       }
+
+      switch (c)
+       {
+       default:
+         *ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER);
+         free (result);
+         free (temp);
+         return -1;
+
+       case 'q':
+         want_quotes = 'q';
+         break;
+
+       case 'x':
+         want_quotes = 'x';
+         break;
+
+         /* :p means make this the last executed line.  So we
+            return an error state after adding this line to the
+            history. */
+       case 'p':
+         print_only++;
+         break;
+
+         /* :t discards all but the last part of the pathname. */
+       case 't':
+         tstr = strrchr (temp, '/');
+         if (tstr)
+           {
+             tstr++;
+             t = savestring (tstr);
+             free (temp);
+             temp = t;
+           }
+         break;
+
+         /* :h discards the last part of a pathname. */
+       case 'h':
+         tstr = strrchr (temp, '/');
+         if (tstr)
+           *tstr = '\0';
+         break;
+
+         /* :r discards the suffix. */
+       case 'r':
+         tstr = strrchr (temp, '.');
+         if (tstr)
+           *tstr = '\0';
+         break;
+
+         /* :e discards everything but the suffix. */
+       case 'e':
+         tstr = strrchr (temp, '.');
+         if (tstr)
+           {
+             t = savestring (tstr);
+             free (temp);
+             temp = t;
+           }
+         break;
+
+       /* :s/this/that substitutes `that' for the first
+          occurrence of `this'.  :gs/this/that substitutes `that'
+          for each occurrence of `this'.  :& repeats the last
+          substitution.  :g& repeats the last substitution
+          globally. */
+
+       case '&':
+       case 's':
+         {
+           char *new_event;
+           int delimiter, failed, si, l_temp, ws, we;
+
+           if (c == 's')
+             {
+               if (i + 2 < (int)strlen (string))
+                 {
+#if defined (HANDLE_MULTIBYTE)
+                   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+                     {
+                       _rl_adjust_point (string, i + 2, &ps);
+                       if (_rl_get_char_len (string + i + 2, &ps) > 1)
+                         delimiter = 0;
+                       else
+                         delimiter = string[i + 2];
+                     }
+                   else
+#endif /* HANDLE_MULTIBYTE */
+                     delimiter = string[i + 2];
+                 }
+               else
+                 break;        /* no search delimiter */
+
+               i += 3;
+
+               t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len);
+               /* An empty substitution lhs with no previous substitution
+                  uses the last search string as the lhs. */
+               if (t)
+                 {
+                   FREE (subst_lhs);
+                   subst_lhs = t;
+                 }
+               else if (!subst_lhs)
+                 {
+                   if (search_string && *search_string)
+                     {
+                       subst_lhs = savestring (search_string);
+                       subst_lhs_len = strlen (subst_lhs);
+                     }
+                   else
+                     {
+                       subst_lhs = (char *) NULL;
+                       subst_lhs_len = 0;
+                     }
+                 }
+
+               FREE (subst_rhs);
+               subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len);
+
+               /* If `&' appears in the rhs, it's supposed to be replaced
+                  with the lhs. */
+               if (member ('&', subst_rhs))
+                 postproc_subst_rhs ();
+             }
+           else
+             i += 2;
+
+           /* If there is no lhs, the substitution can't succeed. */
+           if (subst_lhs_len == 0)
+             {
+               *ret_string = hist_error (string, starting_index, i, NO_PREV_SUBST);
+               free (result);
+               free (temp);
+               return -1;
+             }
+
+           l_temp = strlen (temp);
+           /* Ignore impossible cases. */
+           if (subst_lhs_len > l_temp)
+             {
+               *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
+               free (result);
+               free (temp);
+               return (-1);
+             }
+
+           /* Find the first occurrence of THIS in TEMP. */
+           /* Substitute SUBST_RHS for SUBST_LHS in TEMP.  There are three
+              cases to consider:
+
+                1.  substitute_globally == subst_bywords == 0
+                2.  substitute_globally == 1 && subst_bywords == 0
+                3.  substitute_globally == 0 && subst_bywords == 1
+
+              In the first case, we substitute for the first occurrence only.
+              In the second case, we substitute for every occurrence.
+              In the third case, we tokenize into words and substitute the
+              first occurrence of each word. */
+
+           si = we = 0;
+           for (failed = 1; (si + subst_lhs_len) <= l_temp; si++)
+             {
+               /* First skip whitespace and find word boundaries if
+                  we're past the end of the word boundary we found
+                  the last time. */
+               if (subst_bywords && si > we)
+                 {
+                   for (; temp[si] && whitespace (temp[si]); si++)
+                     ;
+                   ws = si;
+                   we = history_tokenize_word (temp, si);
+                 }
+
+               if (STREQN (temp+si, subst_lhs, subst_lhs_len))
+                 {
+                   int len = subst_rhs_len - subst_lhs_len + l_temp;
+                   new_event = (char *)xmalloc (1 + len);
+                   strncpy (new_event, temp, si);
+                   strncpy (new_event + si, subst_rhs, subst_rhs_len);
+                   strncpy (new_event + si + subst_rhs_len,
+                            temp + si + subst_lhs_len,
+                            l_temp - (si + subst_lhs_len));
+                   new_event[len] = '\0';
+                   free (temp);
+                   temp = new_event;
+
+                   failed = 0;
+
+                   if (substitute_globally)
+                     {
+                       /* Reported to fix a bug that causes it to skip every
+                          other match when matching a single character.  Was
+                          si += subst_rhs_len previously. */
+                       si += subst_rhs_len - 1;
+                       l_temp = strlen (temp);
+                       substitute_globally++;
+                       continue;
+                     }
+                   else if (subst_bywords)
+                     {
+                       si = we;
+                       l_temp = strlen (temp);
+                       continue;
+                     }
+                   else
+                     break;
+                 }
+             }
+
+           if (substitute_globally > 1)
+             {
+               substitute_globally = 0;
+               continue;       /* don't want to increment i */
+             }
+
+           if (failed == 0)
+             continue;         /* don't want to increment i */
+
+           *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
+           free (result);
+           free (temp);
+           return (-1);
+         }
+       }
+      i += 2;
+    }
+  /* Done with modfiers. */
+  /* Believe it or not, we have to back the pointer up by one. */
+  --i;
+
+  if (want_quotes)
+    {
+      char *x;
+
+      if (want_quotes == 'q')
+       x = sh_single_quote (temp);
+      else if (want_quotes == 'x')
+       x = quote_breaks (temp);
+      else
+       x = savestring (temp);
+
+      free (temp);
+      temp = x;
+    }
+
+  n = strlen (temp);
+  if (n >= result_len)
+    result = (char *)xrealloc (result, n + 2);
+  strcpy (result, temp);
+  free (temp);
+
+  *end_index_ptr = i;
+  *ret_string = result;
+  return (print_only);
+}
+
+/* Expand the string STRING, placing the result into OUTPUT, a pointer
+   to a string.  Returns:
+
+  -1) If there was an error in expansion.
+   0) If no expansions took place (or, if the only change in
+      the text was the de-slashifying of the history expansion
+      character)
+   1) If expansions did take place
+   2) If the `p' modifier was given and the caller should print the result
+
+  If an error ocurred in expansion, then OUTPUT contains a descriptive
+  error message. */
+
+#define ADD_STRING(s) \
+       do \
+         { \
+           int sl = strlen (s); \
+           j += sl; \
+           if (j >= result_len) \
+             { \
+               while (j >= result_len) \
+                 result_len += 128; \
+               result = (char *)xrealloc (result, result_len); \
+             } \
+           strcpy (result + j - sl, s); \
+         } \
+       while (0)
+
+#define ADD_CHAR(c) \
+       do \
+         { \
+           if (j >= result_len - 1) \
+             result = (char *)xrealloc (result, result_len += 64); \
+           result[j++] = c; \
+           result[j] = '\0'; \
+         } \
+       while (0)
+
+int
+history_expand (hstring, output)
+     char *hstring;
+     char **output;
+{
+  register int j;
+  int i, r, l, passc, cc, modified, eindex, only_printing, dquote;
+  char *string;
+
+  /* The output string, and its length. */
+  int result_len;
+  char *result;
+
+#if defined (HANDLE_MULTIBYTE)
+  char mb[MB_LEN_MAX];
+  mbstate_t ps;
+#endif
+
+  /* Used when adding the string. */
+  char *temp;
+
+  if (output == 0)
+    return 0;
+
+  /* Setting the history expansion character to 0 inhibits all
+     history expansion. */
+  if (history_expansion_char == 0)
+    {
+      *output = savestring (hstring);
+      return (0);
+    }
+    
+  /* Prepare the buffer for printing error messages. */
+  result = (char *)xmalloc (result_len = 256);
+  result[0] = '\0';
+
+  only_printing = modified = 0;
+  l = strlen (hstring);
+
+  /* Grovel the string.  Only backslash and single quotes can quote the
+     history escape character.  We also handle arg specifiers. */
+
+  /* Before we grovel forever, see if the history_expansion_char appears
+     anywhere within the text. */
+
+  /* The quick substitution character is a history expansion all right.  That
+     is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
+     that is the substitution that we do. */
+  if (hstring[0] == history_subst_char)
+    {
+      string = (char *)xmalloc (l + 5);
+
+      string[0] = string[1] = history_expansion_char;
+      string[2] = ':';
+      string[3] = 's';
+      strcpy (string + 4, hstring);
+      l += 4;
+    }
+  else
+    {
+#if defined (HANDLE_MULTIBYTE)
+      memset (&ps, 0, sizeof (mbstate_t));
+#endif
+
+      string = hstring;
+      /* If not quick substitution, still maybe have to do expansion. */
+
+      /* `!' followed by one of the characters in history_no_expand_chars
+        is NOT an expansion. */
+      for (i = dquote = 0; string[i]; i++)
+       {
+#if defined (HANDLE_MULTIBYTE)
+         if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+           {
+             int v;
+             v = _rl_get_char_len (string + i, &ps);
+             if (v > 1)
+               {
+                 i += v - 1;
+                 continue;
+               }
+           }
+#endif /* HANDLE_MULTIBYTE */
+
+         cc = string[i + 1];
+         /* The history_comment_char, if set, appearing at the beginning
+            of a word signifies that the rest of the line should not have
+            history expansion performed on it.
+            Skip the rest of the line and break out of the loop. */
+         if (history_comment_char && string[i] == history_comment_char &&
+             (i == 0 || member (string[i - 1], history_word_delimiters)))
+           {
+             while (string[i])
+               i++;
+             break;
+           }
+         else if (string[i] == history_expansion_char)
+           {
+             if (!cc || member (cc, history_no_expand_chars))
+               continue;
+             /* If the calling application has set
+                history_inhibit_expansion_function to a function that checks
+                for special cases that should not be history expanded,
+                call the function and skip the expansion if it returns a
+                non-zero value. */
+             else if (history_inhibit_expansion_function &&
+                       (*history_inhibit_expansion_function) (string, i))
+               continue;
+             else
+               break;
+           }
+         /* Shell-like quoting: allow backslashes to quote double quotes
+            inside a double-quoted string. */
+         else if (dquote && string[i] == '\\' && cc == '"')
+           i++;
+         /* More shell-like quoting:  if we're paying attention to single
+            quotes and letting them quote the history expansion character,
+            then we need to pay attention to double quotes, because single
+            quotes are not special inside double-quoted strings. */
+         else if (history_quotes_inhibit_expansion && string[i] == '"')
+           {
+             dquote = 1 - dquote;
+           }
+         else if (dquote == 0 && history_quotes_inhibit_expansion && string[i] == '\'')
+           {
+             /* If this is bash, single quotes inhibit history expansion. */
+             i++;
+             hist_string_extract_single_quoted (string, &i);
+           }
+         else if (history_quotes_inhibit_expansion && string[i] == '\\')
+           {
+             /* If this is bash, allow backslashes to quote single
+                quotes and the history expansion character. */
+             if (cc == '\'' || cc == history_expansion_char)
+               i++;
+           }
+         
+       }
+         
+      if (string[i] != history_expansion_char)
+       {
+         free (result);
+         *output = savestring (string);
+         return (0);
+       }
+    }
+
+  /* Extract and perform the substitution. */
+  for (passc = dquote = i = j = 0; i < l; i++)
+    {
+      int tchar = string[i];
+
+      if (passc)
+       {
+         passc = 0;
+         ADD_CHAR (tchar);
+         continue;
+       }
+
+#if defined (HANDLE_MULTIBYTE)
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+       {
+         int k, c;
+
+         c = tchar;
+         memset (mb, 0, sizeof (mb));
+         for (k = 0; k < MB_LEN_MAX; k++)
+           {
+             mb[k] = (char)c;
+             memset (&ps, 0, sizeof (mbstate_t));
+             if (_rl_get_char_len (mb, &ps) == -2)
+               c = string[++i];
+             else
+               break;
+           }
+         if (strlen (mb) > 1)
+           {
+             ADD_STRING (mb);
+             break;
+           }
+       }
+#endif /* HANDLE_MULTIBYTE */
+
+      if (tchar == history_expansion_char)
+       tchar = -3;
+      else if (tchar == history_comment_char)
+       tchar = -2;
+
+      switch (tchar)
+       {
+       default:
+         ADD_CHAR (string[i]);
+         break;
+
+       case '\\':
+         passc++;
+         ADD_CHAR (tchar);
+         break;
+
+       case '"':
+         dquote = 1 - dquote;
+         ADD_CHAR (tchar);
+         break;
+         
+       case '\'':
+         {
+           /* If history_quotes_inhibit_expansion is set, single quotes
+              inhibit history expansion. */
+           if (dquote == 0 && history_quotes_inhibit_expansion)
+             {
+               int quote, slen;
+
+               quote = i++;
+               hist_string_extract_single_quoted (string, &i);
+
+               slen = i - quote + 2;
+               temp = (char *)xmalloc (slen);
+               strncpy (temp, string + quote, slen);
+               temp[slen - 1] = '\0';
+               ADD_STRING (temp);
+               free (temp);
+             }
+           else
+             ADD_CHAR (string[i]);
+           break;
+         }
+
+       case -2:                /* history_comment_char */
+         if (i == 0 || member (string[i - 1], history_word_delimiters))
+           {
+             temp = (char *)xmalloc (l - i + 1);
+             strcpy (temp, string + i);
+             ADD_STRING (temp);
+             free (temp);
+             i = l;
+           }
+         else
+           ADD_CHAR (string[i]);
+         break;
+
+       case -3:                /* history_expansion_char */
+         cc = string[i + 1];
+
+         /* If the history_expansion_char is followed by one of the
+            characters in history_no_expand_chars, then it is not a
+            candidate for expansion of any kind. */
+         if (member (cc, history_no_expand_chars))
+           {
+             ADD_CHAR (string[i]);
+             break;
+           }
+
+#if defined (NO_BANG_HASH_MODIFIERS)
+         /* There is something that is listed as a `word specifier' in csh
+            documentation which means `the expanded text to this point'.
+            That is not a word specifier, it is an event specifier.  If we
+            don't want to allow modifiers with `!#', just stick the current
+            output line in again. */
+         if (cc == '#')
+           {
+             if (result)
+               {
+                 temp = (char *)xmalloc (1 + strlen (result));
+                 strcpy (temp, result);
+                 ADD_STRING (temp);
+                 free (temp);
+               }
+             i++;
+             break;
+           }
+#endif
+
+         r = history_expand_internal (string, i, &eindex, &temp, result);
+         if (r < 0)
+           {
+             *output = temp;
+             free (result);
+             if (string != hstring)
+               free (string);
+             return -1;
+           }
+         else
+           {
+             if (temp)
+               {
+                 modified++;
+                 if (*temp)
+                   ADD_STRING (temp);
+                 free (temp);
+               }
+             only_printing = r == 1;
+             i = eindex;
+           }
+         break;
+       }
+    }
+
+  *output = result;
+  if (string != hstring)
+    free (string);
+
+  if (only_printing)
+    {
+#if 0
+      add_history (result);
+#endif
+      return (2);
+    }
+
+  return (modified != 0);
+}
+
+/* Return a consed string which is the word specified in SPEC, and found
+   in FROM.  NULL is returned if there is no spec.  The address of
+   ERROR_POINTER is returned if the word specified cannot be found.
+   CALLER_INDEX is the offset in SPEC to start looking; it is updated
+   to point to just after the last character parsed. */
+static char *
+get_history_word_specifier (spec, from, caller_index)
+     char *spec, *from;
+     int *caller_index;
+{
+  register int i = *caller_index;
+  int first, last;
+  int expecting_word_spec = 0;
+  char *result;
+
+  /* The range of words to return doesn't exist yet. */
+  first = last = 0;
+  result = (char *)NULL;
+
+  /* If we found a colon, then this *must* be a word specification.  If
+     it isn't, then it is an error. */
+  if (spec[i] == ':')
+    {
+      i++;
+      expecting_word_spec++;
+    }
+
+  /* Handle special cases first. */
+
+  /* `%' is the word last searched for. */
+  if (spec[i] == '%')
+    {
+      *caller_index = i + 1;
+      return (search_match ? savestring (search_match) : savestring (""));
+    }
+
+  /* `*' matches all of the arguments, but not the command. */
+  if (spec[i] == '*')
+    {
+      *caller_index = i + 1;
+      result = history_arg_extract (1, '$', from);
+      return (result ? result : savestring (""));
+    }
+
+  /* `$' is last arg. */
+  if (spec[i] == '$')
+    {
+      *caller_index = i + 1;
+      return (history_arg_extract ('$', '$', from));
+    }
+
+  /* Try to get FIRST and LAST figured out. */
+
+  if (spec[i] == '-')
+    first = 0;
+  else if (spec[i] == '^')
+    {
+      first = 1;
+      i++;
+    }
+  else if (_rl_digit_p (spec[i]) && expecting_word_spec)
+    {
+      for (first = 0; _rl_digit_p (spec[i]); i++)
+       first = (first * 10) + _rl_digit_value (spec[i]);
+    }
+  else
+    return ((char *)NULL);     /* no valid `first' for word specifier */
+
+  if (spec[i] == '^' || spec[i] == '*')
+    {
+      last = (spec[i] == '^') ? 1 : '$';       /* x* abbreviates x-$ */
+      i++;
+    }
+  else if (spec[i] != '-')
+    last = first;
+  else
+    {
+      i++;
+
+      if (_rl_digit_p (spec[i]))
+       {
+         for (last = 0; _rl_digit_p (spec[i]); i++)
+           last = (last * 10) + _rl_digit_value (spec[i]);
+       }
+      else if (spec[i] == '$')
+       {
+         i++;
+         last = '$';
+       }
+#if 0
+      else if (!spec[i] || spec[i] == ':')
+       /* check against `:' because there could be a modifier separator */
+#else
+      else
+       /* csh seems to allow anything to terminate the word spec here,
+          leaving it as an abbreviation. */
+#endif
+       last = -1;              /* x- abbreviates x-$ omitting word `$' */
+    }
+
+  *caller_index = i;
+
+  if (last >= first || last == '$' || last < 0)
+    result = history_arg_extract (first, last, from);
+
+  return (result ? result : (char *)&error_pointer);
+}
+
+/* Extract the args specified, starting at FIRST, and ending at LAST.
+   The args are taken from STRING.  If either FIRST or LAST is < 0,
+   then make that arg count from the right (subtract from the number of
+   tokens, so that FIRST = -1 means the next to last token on the line).
+   If LAST is `$' the last arg from STRING is used. */
+char *
+history_arg_extract (first, last, string)
+     int first, last;
+     const char *string;
+{
+  register int i, len;
+  char *result;
+  int size, offset;
+  char **list;
+
+  /* XXX - think about making history_tokenize return a struct array,
+     each struct in array being a string and a length to avoid the
+     calls to strlen below. */
+  if ((list = history_tokenize (string)) == NULL)
+    return ((char *)NULL);
+
+  for (len = 0; list[len]; len++)
+    ;
+
+  if (last < 0)
+    last = len + last - 1;
+
+  if (first < 0)
+    first = len + first - 1;
+
+  if (last == '$')
+    last = len - 1;
+
+  if (first == '$')
+    first = len - 1;
+
+  last++;
+
+  if (first >= len || last > len || first < 0 || last < 0 || first > last)
+    result = ((char *)NULL);
+  else
+    {
+      for (size = 0, i = first; i < last; i++)
+       size += strlen (list[i]) + 1;
+      result = (char *)xmalloc (size + 1);
+      result[0] = '\0';
+
+      for (i = first, offset = 0; i < last; i++)
+       {
+         strcpy (result + offset, list[i]);
+         offset += strlen (list[i]);
+         if (i + 1 < last)
+           {
+             result[offset++] = ' ';
+             result[offset] = 0;
+           }
+       }
+    }
+
+  for (i = 0; i < len; i++)
+    free (list[i]);
+  free (list);
+
+  return (result);
+}
+
+static int
+history_tokenize_word (string, ind)
+     const char *string;
+     int ind;
+{
+  register int i;
+  int delimiter;
+
+  i = ind;
+  delimiter = 0;
+
+  if (member (string[i], "()\n"))
+    {
+      i++;
+      return i;
+    }
+
+  if (member (string[i], "<>;&|$"))
+    {
+      int peek = string[i + 1];
+
+      if (peek == string[i] && peek != '$')
+       {
+         if (peek == '<' && string[i + 2] == '-')
+           i++;
+         else if (peek == '<' && string[i + 2] == '<')
+           i++;
+         i += 2;
+         return i;
+       }
+      else
+       {
+         if ((peek == '&' && (string[i] == '>' || string[i] == '<')) ||
+             (peek == '>' && string[i] == '&') ||
+             (peek == '(' && (string[i] == '>' || string[i] == '<')) || /* ) */
+             (peek == '(' && string[i] == '$')) /* ) */
+           {
+             i += 2;
+             return i;
+           }
+       }
+
+      if (string[i] != '$')
+       {
+         i++;
+         return i;
+       }
+    }
+
+  /* Get word from string + i; */
+
+  if (member (string[i], HISTORY_QUOTE_CHARACTERS))
+    delimiter = string[i++];
+
+  for (; string[i]; i++)
+    {
+      if (string[i] == '\\' && string[i + 1] == '\n')
+       {
+         i++;
+         continue;
+       }
+
+      if (string[i] == '\\' && delimiter != '\'' &&
+         (delimiter != '"' || member (string[i], slashify_in_quotes)))
+       {
+         i++;
+         continue;
+       }
+
+      if (delimiter && string[i] == delimiter)
+       {
+         delimiter = 0;
+         continue;
+       }
+
+      if (!delimiter && (member (string[i], history_word_delimiters)))
+       break;
+
+      if (!delimiter && member (string[i], HISTORY_QUOTE_CHARACTERS))
+       delimiter = string[i];
+    }
+
+  return i;
+}
+
+static char *
+history_substring (string, start, end)
+     const char *string;
+     int start, end;
+{
+  register int len;
+  register char *result;
+
+  len = end - start;
+  result = (char *)xmalloc (len + 1);
+  strncpy (result, string + start, len);
+  result[len] = '\0';
+  return result;
+}
+
+/* Parse STRING into tokens and return an array of strings.  If WIND is
+   not -1 and INDP is not null, we also want the word surrounding index
+   WIND.  The position in the returned array of strings is returned in
+   *INDP. */
+static char **
+history_tokenize_internal (string, wind, indp)
+     const char *string;
+     int wind, *indp;
+{
+  char **result;
+  register int i, start, result_index, size;
+
+  /* If we're searching for a string that's not part of a word (e.g., " "),
+     make sure we set *INDP to a reasonable value. */
+  if (indp && wind != -1)
+    *indp = -1;
+
+  /* Get a token, and stuff it into RESULT.  The tokens are split
+     exactly where the shell would split them. */
+  for (i = result_index = size = 0, result = (char **)NULL; string[i]; )
+    {
+      /* Skip leading whitespace. */
+      for (; string[i] && whitespace (string[i]); i++)
+       ;
+      if (string[i] == 0 || string[i] == history_comment_char)
+       return (result);
+
+      start = i;
+
+      i = history_tokenize_word (string, start);
+
+      /* If we have a non-whitespace delimiter character (which would not be
+        skipped by the loop above), use it and any adjacent delimiters to
+        make a separate field.  Any adjacent white space will be skipped the
+        next time through the loop. */
+      if (i == start && history_word_delimiters)
+       {
+         i++;
+         while (string[i] && member (string[i], history_word_delimiters))
+           i++;
+       }
+
+      /* If we are looking for the word in which the character at a
+        particular index falls, remember it. */
+      if (indp && wind != -1 && wind >= start && wind < i)
+        *indp = result_index;
+
+      if (result_index + 2 >= size)
+       result = (char **)xrealloc (result, ((size += 10) * sizeof (char *)));
+
+      result[result_index++] = history_substring (string, start, i);
+      result[result_index] = (char *)NULL;
+    }
+
+  return (result);
+}
+
+/* Return an array of tokens, much as the shell might.  The tokens are
+   parsed out of STRING. */
+char **
+history_tokenize (string)
+     const char *string;
+{
+  return (history_tokenize_internal (string, -1, (int *)NULL));
+}
+
+/* Find and return the word which contains the character at index IND
+   in the history line LINE.  Used to save the word matched by the
+   last history !?string? search. */
+static char *
+history_find_word (line, ind)
+     char *line;
+     int ind;
+{
+  char **words, *s;
+  int i, wind;
+
+  words = history_tokenize_internal (line, ind, &wind);
+  if (wind == -1 || words == 0)
+    return ((char *)NULL);
+  s = words[wind];
+  for (i = 0; i < wind; i++)
+    free (words[i]);
+  for (i = wind + 1; words[i]; i++)
+    free (words[i]);
+  free (words);
+  return s;
+}
index dcc86e1469e035f678aafe2615d00b5797264b90..f4de57b0476f4795ce45fdda703f1f380d95d40d 100644 (file)
@@ -550,21 +550,21 @@ _rl_read_mbchar (mbchar, size)
 }
 
 /* Read a multibyte-character string whose first character is FIRST into
-   the buffer MB of length MBLEN.  Returns the last character read, which
+   the buffer MB of length MLEN.  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)
+_rl_read_mbstring (first, mb, mlen)
      int first;
      char *mb;
-     int mblen;
+     int mlen;
 {
   int i, c;
   mbstate_t ps;
 
   c = first;
-  memset (mb, 0, mblen);
-  for (i = 0; i < mblen; i++)
+  memset (mb, 0, mlen);
+  for (i = 0; i < mlen; i++)
     {
       mb[i] = (char)c;
       memset (&ps, 0, sizeof (mbstate_t));
index 0ec507ec27c5c9aaef808a361d521eec2d7a8031..dcc86e1469e035f678aafe2615d00b5797264b90 100644 (file)
@@ -179,6 +179,7 @@ rl_gather_tyi ()
   struct timeval timeout;
 #endif
 
+  chars_avail = 0;
   tty = fileno (rl_instream);
 
 #if defined (HAVE_SELECT)
@@ -220,6 +221,13 @@ rl_gather_tyi ()
     }
 #endif /* O_NDELAY */
 
+#if defined (__MINGW32__)
+  /* Use getch/_kbhit to check for available console input, in the same way
+     that we read it normally. */
+   chars_avail = isatty (tty) ? _kbhit () : 0;
+   result = 0;
+#endif
+
   /* If there's nothing available, don't waste time trying to read
      something. */
   if (chars_avail <= 0)
@@ -263,7 +271,7 @@ rl_set_keyboard_input_timeout (u)
   int o;
 
   o = _keyboard_input_timeout;
-  if (u > 0)
+  if (u >= 0)
     _keyboard_input_timeout = u;
   return (o);
 }
@@ -303,6 +311,11 @@ _rl_input_available ()
     return (chars_avail);
 #endif
 
+#endif
+
+#if defined (__MINGW32__)
+  if (isatty (tty))
+    return (_kbhit ());
 #endif
 
   return 0;
index 6c969a881578172925e2e9e131b566aa532380ec..399a48c5f1e7a297069bf0ed8caa09523312650f 100644 (file)
@@ -1237,8 +1237,8 @@ rl_change_case (count, op)
 #if defined (HANDLE_MULTIBYTE)
   wchar_t wc, nwc;
   char mb[MB_LEN_MAX+1];
-  int mblen;
-  mbstate_t ps;
+  int mlen;
+  mbstate_t mps;
 #endif
 
   start = rl_point;
@@ -1255,7 +1255,7 @@ rl_change_case (count, op)
     SWAP (start, end);
 
 #if defined (HANDLE_MULTIBYTE)
-  memset (&ps, 0, sizeof (mbstate_t));
+  memset (&mps, 0, sizeof (mbstate_t));
 #endif
 
   /* We are going to modify some text, so let's prepare to undo it. */
@@ -1290,15 +1290,15 @@ rl_change_case (count, op)
 #if defined (HANDLE_MULTIBYTE)
       else
        {
-         mbrtowc (&wc, rl_line_buffer + start, end - start, &ps);
+         mbrtowc (&wc, rl_line_buffer + start, end - start, &mps);
          nwc = (nop == UpCase) ? _rl_to_wupper (wc) : _rl_to_wlower (wc);
          if  (nwc != wc)       /*  just skip unchanged characters */
            {
-             mblen = wcrtomb (mb, nwc, &ps);
-             if (mblen > 0)
-               mb[mblen] = '\0';
+             mlen = wcrtomb (mb, nwc, &mps);
+             if (mlen > 0)
+               mb[mlen] = '\0';
              /* Assume the same width */
-             strncpy (rl_line_buffer + start, mb, mblen);
+             strncpy (rl_line_buffer + start, mb, mlen);
            }
        }
 #endif
index f8d272cc90b3ea94e35b03bcbaff894443fcc4ab..d771de0deba1043795b7491183d5f7880db1976a 100644 (file)
@@ -1237,8 +1237,8 @@ rl_change_case (count, op)
 #if defined (HANDLE_MULTIBYTE)
   wchar_t wc, nwc;
   char mb[MB_LEN_MAX+1];
-  int mblen, p;
-  mbstate_t ps;
+  int mblen;
+  mbstate_t mps;
 #endif
 
   start = rl_point;
@@ -1255,7 +1255,7 @@ rl_change_case (count, op)
     SWAP (start, end);
 
 #if defined (HANDLE_MULTIBYTE)
-  memset (&ps, 0, sizeof (mbstate_t));
+  memset (&mps, 0, sizeof (mbstate_t));
 #endif
 
   /* We are going to modify some text, so let's prepare to undo it. */
@@ -1290,11 +1290,11 @@ rl_change_case (count, op)
 #if defined (HANDLE_MULTIBYTE)
       else
        {
-         mbrtowc (&wc, rl_line_buffer + start, end - start, &ps);
+         mbrtowc (&wc, rl_line_buffer + start, end - start, &mps);
          nwc = (nop == UpCase) ? _rl_to_wupper (wc) : _rl_to_wlower (wc);
          if  (nwc != wc)       /*  just skip unchanged characters */
            {
-             mblen = wcrtomb (mb, nwc, &ps);
+             mblen = wcrtomb (mb, nwc, &mps);
              if (mblen > 0)
                mb[mblen] = '\0';
              /* Assume the same width */
index dd0fa029aa2eeea39c16eef9fa31ec4e05e8020d..d0b7e330adc479191dcf6faa121aa2f681b405f3 100644 (file)
@@ -738,7 +738,7 @@ _rl_vi_change_mbchar_case (count)
 {
   wchar_t wc;
   char mb[MB_LEN_MAX+1];
-  int mblen, p;
+  int mlen, p;
   mbstate_t ps;
 
   memset (&ps, 0, sizeof (mbstate_t));
@@ -762,9 +762,9 @@ _rl_vi_change_mbchar_case (count)
       if (wc)
        {
          p = rl_point;
-         mblen = wcrtomb (mb, wc, &ps);
-         if (mblen >= 0)
-           mb[mblen] = '\0';
+         mlen = wcrtomb (mb, wc, &ps);
+         if (mlen >= 0)
+           mb[mlen] = '\0';
          rl_begin_undo_group ();
          rl_vi_delete (1, 0);
          if (rl_point < p)     /* Did we retreat at EOL? */
@@ -1457,9 +1457,9 @@ _rl_vi_change_char (count, c, mb)
 }
 
 static int
-_rl_vi_callback_getchar (mb, mblen)
+_rl_vi_callback_getchar (mb, mlen)
      char *mb;
-     int mblen;
+     int mlen;
 {
   int c;
 
@@ -1469,7 +1469,7 @@ _rl_vi_callback_getchar (mb, mblen)
 
 #if defined (HANDLE_MULTIBYTE)
   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
-    c = _rl_read_mbstring (c, mb, mblen);
+    c = _rl_read_mbstring (c, mb, mlen);
 #endif
 
   return c;
index fce05f1d113c793f51e8bc4407fca117db014984..7cb838b0dced95a7195724eb14a6746fe14e63f9 100644 (file)
@@ -653,7 +653,7 @@ _rl_vi_save_insert (up)
 {
   int len, start, end;
 
-  if (up == 0)
+  if (up == 0 || up->what != UNDO_INSERT)
     {
       if (vi_insert_buffer_size >= 1)
        vi_insert_buffer[0] = '\0';
@@ -1457,9 +1457,9 @@ _rl_vi_change_char (count, c, mb)
 }
 
 static int
-_rl_vi_callback_getchar (mb, mblen)
+_rl_vi_callback_getchar (mb, mlen)
      char *mb;
-     int mblen;
+     int mlen;
 {
   int c;
 
@@ -1469,7 +1469,7 @@ _rl_vi_callback_getchar (mb, mblen)
 
 #if defined (HANDLE_MULTIBYTE)
   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
-    c = _rl_read_mbstring (c, mb, mblen);
+    c = _rl_read_mbstring (c, mb, mlen);
 #endif
 
   return c;
index aaf0c4755697b24c6e01f9dc11d510de8fea481d..c30f4775003179d7576a9c86d4fa4741379bd1ec 100644 (file)
@@ -66,6 +66,16 @@ extern int errno;
 extern int inet_aton __P((const char *, struct in_addr *));
 #endif
 
+#ifndef HAVE_GETADDRINFO
+static int _getaddr __P((char *, struct in_addr));
+static int _getserv __P((char *, int, unsigned short));
+static int _netopen4 __P((char *, char *, int));
+#else /* HAVE_GETADDRINFO */
+static int _netopen6 __P((char *, char *, int));
+#endif
+
+static int _netopen __P((char *, char *, int));
+
 #ifndef HAVE_GETADDRINFO
 /* Stuff the internet address corresponding to HOST into AP, in network
    byte order.  Return 1 on success, 0 on failure. */
diff --git a/lib/sh/netopen.c~ b/lib/sh/netopen.c~
new file mode 100644 (file)
index 0000000..aaf0c47
--- /dev/null
@@ -0,0 +1,340 @@
+/*   
+ * netopen.c -- functions to make tcp/udp connections
+ *
+ * Chet Ramey
+ * chet@ins.CWRU.Edu
+ */
+
+/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   Bash is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   Bash is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with Bash; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#include <config.h>
+
+#if defined (HAVE_NETWORK)
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include <stdio.h> 
+#include <sys/types.h>
+
+#if defined (HAVE_SYS_SOCKET_H)
+#  include <sys/socket.h>
+#endif
+
+#if defined (HAVE_NETINET_IN_H)
+#  include <netinet/in.h>
+#endif
+
+#if defined (HAVE_NETDB_H)
+#  include <netdb.h>
+#endif
+
+#if defined (HAVE_ARPA_INET_H)
+#  include <arpa/inet.h>
+#endif
+
+#include <bashansi.h>
+#include <bashintl.h>
+
+#include <errno.h>
+
+#include <shell.h>
+#include <xmalloc.h>
+
+#ifndef errno
+extern int errno;
+#endif
+
+#if !defined (HAVE_INET_ATON)
+extern int inet_aton __P((const char *, struct in_addr *));
+#endif
+
+#ifndef HAVE_GETADDRINFO
+/* Stuff the internet address corresponding to HOST into AP, in network
+   byte order.  Return 1 on success, 0 on failure. */
+
+static int
+_getaddr (host, ap)
+     char *host;
+     struct in_addr *ap;
+{
+  struct hostent *h;
+  int r;
+
+  r = 0;
+  if (host[0] >= '0' && host[0] <= '9')
+    {
+      /* If the first character is a digit, guess that it's an
+        Internet address and return immediately if inet_aton succeeds. */
+      r = inet_aton (host, ap);
+      if (r)
+       return r;
+    }
+#if !defined (HAVE_GETHOSTBYNAME)
+  return 0;
+#else
+  h = gethostbyname (host);
+  if (h && h->h_addr)
+    {
+      bcopy(h->h_addr, (char *)ap, h->h_length);
+      return 1;
+    }
+#endif
+  return 0;
+  
+}
+
+/* Return 1 if SERV is a valid port number and stuff the converted value into
+   PP in network byte order. */   
+static int
+_getserv (serv, proto, pp)
+     char *serv;
+     int proto;
+     unsigned short *pp;
+{
+  intmax_t l;
+  unsigned short s;
+
+  if (legal_number (serv, &l))
+    {
+      s = (unsigned short)(l & 0xFFFF);
+      if (s != l)
+       return (0);
+      s = htons (s);
+      if (pp)
+       *pp = s;
+      return 1;
+    }
+  else
+#if defined (HAVE_GETSERVBYNAME)
+    {
+      struct servent *se;
+
+      se = getservbyname (serv, (proto == 't') ? "tcp" : "udp");
+      if (se == 0)
+       return 0;
+      if (pp)
+       *pp = se->s_port;       /* ports returned in network byte order */
+      return 1;
+    }
+#else /* !HAVE_GETSERVBYNAME */
+    return 0;
+#endif /* !HAVE_GETSERVBYNAME */
+}
+
+/*
+ * Open a TCP or UDP connection to HOST on port SERV.  Uses the
+ * traditional BSD mechanisms.  Returns the connected socket or -1 on error.
+ */
+static int 
+_netopen4(host, serv, typ)
+     char *host, *serv;
+     int typ;
+{
+  struct in_addr ina;
+  struct sockaddr_in sin;
+  unsigned short p;
+  int s, e;
+
+  if (_getaddr(host, &ina) == 0)
+    {
+      internal_error (_("%s: host unknown"), host);
+      errno = EINVAL;
+      return -1;
+    }
+
+  if (_getserv(serv, typ, &p) == 0)
+    {
+      internal_error(_("%s: invalid service"), serv);
+      errno = EINVAL;
+      return -1;
+    }
+       
+  memset ((char *)&sin, 0, sizeof(sin));
+  sin.sin_family = AF_INET;
+  sin.sin_port = p;
+  sin.sin_addr = ina;
+
+  s = socket(AF_INET, (typ == 't') ? SOCK_STREAM : SOCK_DGRAM, 0);
+  if (s < 0)
+    {
+      sys_error ("socket");
+      return (-1);
+    }
+
+  if (connect (s, (struct sockaddr *)&sin, sizeof (sin)) < 0)
+    {
+      e = errno;
+      sys_error("connect");
+      close(s);
+      errno = e;
+      return (-1);
+    }
+
+  return(s);
+}
+#endif /* ! HAVE_GETADDRINFO */
+
+#ifdef HAVE_GETADDRINFO
+/*
+ * Open a TCP or UDP connection to HOST on port SERV.  Uses getaddrinfo(3)
+ * which provides support for IPv6.  Returns the connected socket or -1
+ * on error.
+ */
+static int
+_netopen6 (host, serv, typ)
+     char *host, *serv;
+     int typ;
+{
+  int s, e;
+  struct addrinfo hints, *res, *res0;
+  int gerr;
+
+  memset ((char *)&hints, 0, sizeof (hints));
+  /* XXX -- if problems with IPv6, set to PF_INET for IPv4 only */
+#ifdef DEBUG   /* PF_INET is the one that works for me */
+  hints.ai_family = PF_INET;
+#else
+  hints.ai_family = PF_UNSPEC;
+#endif
+  hints.ai_socktype = (typ == 't') ? SOCK_STREAM : SOCK_DGRAM;
+
+  gerr = getaddrinfo (host, serv, &hints, &res0);
+  if (gerr)
+    {
+      if (gerr == EAI_SERVICE)
+       internal_error ("%s: %s", serv, gai_strerror (gerr));
+      else
+       internal_error ("%s: %s", host, gai_strerror (gerr));
+      errno = EINVAL;
+      return -1;
+    }
+
+  for (res = res0; res; res = res->ai_next)
+    {
+      if ((s = socket (res->ai_family, res->ai_socktype, res->ai_protocol)) < 0)
+       {
+         if (res->ai_next)
+           continue;
+         sys_error ("socket");
+         freeaddrinfo (res0);
+         return -1;
+       }
+      if (connect (s, res->ai_addr, res->ai_addrlen) < 0)
+       {
+         if (res->ai_next)
+           {
+             close (s);
+             continue;
+           }
+         e = errno;
+         sys_error ("connect");
+         close (s);
+         freeaddrinfo (res0);
+         errno = e;
+         return -1;
+       }
+      freeaddrinfo (res0);
+      break;
+    }
+  return s;
+}
+#endif /* HAVE_GETADDRINFO */
+
+/*
+ * Open a TCP or UDP connection to HOST on port SERV.  Uses getaddrinfo(3)
+ * if available, falling back to the traditional BSD mechanisms otherwise.
+ * Returns the connected socket or -1 on error.
+ */
+static int 
+_netopen(host, serv, typ)
+     char *host, *serv;
+     int typ;
+{
+#ifdef HAVE_GETADDRINFO
+  return (_netopen6 (host, serv, typ));
+#else
+  return (_netopen4 (host, serv, typ));
+#endif
+}
+
+/*
+ * Open a TCP or UDP connection given a path like `/dev/tcp/host/port' to
+ * host `host' on port `port' and return the connected socket.
+ */
+int
+netopen (path)
+     char *path;
+{
+  char *np, *s, *t;
+  int fd;
+
+  np = (char *)xmalloc (strlen (path) + 1);
+  strcpy (np, path);
+
+  s = np + 9;
+  t = strchr (s, '/');
+  if (t == 0)
+    {
+      internal_error (_("%s: bad network path specification"), path);
+      return -1;
+    }
+  *t++ = '\0';
+  fd = _netopen (s, t, path[5]);
+  free (np);
+
+  return fd;
+}
+
+#if 0
+/*
+ * Open a TCP connection to host `host' on the port defined for service
+ * `serv' and return the connected socket.
+ */
+int
+tcpopen (host, serv)
+     char *host, *serv;
+{
+  return (_netopen (host, serv, 't'));
+}
+
+/*
+ * Open a UDP connection to host `host' on the port defined for service
+ * `serv' and return the connected socket.
+ */
+int
+udpopen (host, serv)
+     char *host, *serv;
+{
+  return _netopen (host, serv, 'u');
+}
+#endif
+
+#else /* !HAVE_NETWORK */
+
+int
+netopen (path)
+     char *path;
+{
+  internal_error (_("network operations not supported"));
+  return -1;
+}
+
+#endif /* !HAVE_NETWORK */
index 4508ed020b666adee2409870c623b096baae08cc..f03a2ee52e31d2c33fac14c03590c49b044aeda7 100644 (file)
@@ -57,8 +57,7 @@ sh_regmatch (string, pattern, flags)
   char *subexp_str;
   int subexp_len;
 #endif
-  int result;  
-
+  int result;
 
 #if defined (ARRAY_VARS)
   rematch = (SHELL_VAR *)NULL;
diff --git a/lib/sh/shmatch.c~ b/lib/sh/shmatch.c~
new file mode 100644 (file)
index 0000000..4508ed0
--- /dev/null
@@ -0,0 +1,121 @@
+/* Copyright (C) 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. */
+
+/*
+ * shmatch.c -- shell interface to posix regular expression matching.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#if defined (HAVE_POSIX_REGEXP)
+
+#ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
+
+#include "bashansi.h"
+
+#include <stdio.h>
+#include <regex.h>
+
+#include "shell.h"
+#include "variables.h"
+#include "externs.h"
+
+extern int glob_ignore_case, match_ignore_case;
+
+int
+sh_regmatch (string, pattern, flags)
+     const char *string;
+     const char *pattern;
+     int flags;
+{
+  regex_t regex = { 0 };
+  regmatch_t *matches;
+  int rflags;
+#if defined (ARRAY_VARS)
+  SHELL_VAR *rematch;
+  ARRAY *amatch;
+  int subexp_ind;
+  char *subexp_str;
+  int subexp_len;
+#endif
+  int result;  
+
+
+#if defined (ARRAY_VARS)
+  rematch = (SHELL_VAR *)NULL;
+#endif
+  
+  rflags = REG_EXTENDED;
+  if (glob_ignore_case || match_ignore_case)
+    rflags |= REG_ICASE;
+#if !defined (ARRAY_VARS)
+  rflags |= REG_NOSUB;
+#endif
+
+  if (regcomp (&regex, pattern, rflags))
+    return 2;          /* flag for printing a warning here. */
+
+#if defined (ARRAY_VARS)
+  matches = (regmatch_t *)malloc (sizeof (regmatch_t) * (regex.re_nsub + 1));
+#else
+  matches = NULL;
+#endif
+
+  if (regexec (&regex, string, regex.re_nsub + 1, matches, 0))
+    result = EXECUTION_FAILURE;
+  else
+    result = EXECUTION_SUCCESS;                /* match */
+
+#if defined (ARRAY_VARS)
+  subexp_len = strlen (string) + 10;
+  subexp_str = malloc (subexp_len + 1);
+
+  /* Store the parenthesized subexpressions in the array BASH_REMATCH.
+     Element 0 is the portion that matched the entire regexp.  Element 1
+     is the part that matched the first subexpression, and so on. */
+  unbind_variable ("BASH_REMATCH");
+  rematch = make_new_array_variable ("BASH_REMATCH");
+  amatch = array_cell (rematch);
+
+  if ((flags & SHMAT_SUBEXP) && result == EXECUTION_SUCCESS && subexp_str)
+    {
+      for (subexp_ind = 0; subexp_ind <= regex.re_nsub; subexp_ind++)
+       {
+         memset (subexp_str, 0, subexp_len);
+         strncpy (subexp_str, string + matches[subexp_ind].rm_so,
+                    matches[subexp_ind].rm_eo - matches[subexp_ind].rm_so);
+         array_insert (amatch, subexp_ind, subexp_str);
+       }
+    }
+
+  VSETATTR (rematch, att_readonly);
+
+  free (subexp_str);
+  free (matches);
+#endif /* ARRAY_VARS */
+
+  regfree (&regex);
+
+  return result;
+}
+
+#endif /* HAVE_POSIX_REGEXP */
index 3f33d41b100cfb70ab7613d1028fbe2bec3749ca..1f0290e3d676a3d9cce19bf2fd3d995a31f0428e 100644 (file)
@@ -176,7 +176,7 @@ ansic_quote (str, flags, rlen)
      int flags, *rlen;
 {
   char *r, *ret, *s;
-  int l, rsize, t;
+  int l, rsize;
   unsigned char c;
 
   if (str == 0 || *str == 0)
index fb7b732dd682453f3303e1b7467ce3e27b9c5efb..5f2279d0e15bfec2e428903b31f47462954ead7b 100644 (file)
@@ -47,6 +47,9 @@ extern int errno;
 
 extern pid_t dollar_dollar_pid;
 
+static char *get_sys_tmpdir __P((void));
+static char *get_tmpdir __P((int));
+
 static char *sys_tmpdir = (char *)NULL;
 static int ntmpfiles;
 static int tmpnamelen = -1;
@@ -55,8 +58,6 @@ static unsigned long filenum = 1L;
 static char *
 get_sys_tmpdir ()
 {
-  struct stat sb;
-
   if (sys_tmpdir)
     return sys_tmpdir;
 
diff --git a/lib/sh/tmpfile.c~ b/lib/sh/tmpfile.c~
new file mode 100644 (file)
index 0000000..f6e04fd
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * tmpfile.c - functions to create and safely open temp files for the shell.
+ */
+
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   Bash is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   Bash is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with Bash; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#include <config.h>
+
+#include <bashtypes.h>
+#include <posixstat.h>
+#include <posixtime.h>
+#include <filecntl.h>
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+
+#include <shell.h>
+
+#ifndef errno
+extern int errno;
+#endif
+
+#define BASEOPENFLAGS  (O_CREAT | O_TRUNC | O_EXCL)
+
+#define DEFAULT_TMPDIR         "."     /* bogus default, should be changed */
+#define DEFAULT_NAMEROOT       "shtmp"
+
+extern pid_t dollar_dollar_pid;
+
+static char *sys_tmpdir = (char *)NULL;
+static int ntmpfiles;
+static int tmpnamelen = -1;
+static unsigned long filenum = 1L;
+
+static char *
+get_sys_tmpdir ()
+{
+  if (sys_tmpdir)
+    return sys_tmpdir;
+
+#ifdef P_tmpdir
+  sys_tmpdir = P_tmpdir;
+  if (file_iswdir (sys_tmpdir))
+    return sys_tmpdir;
+#endif
+
+  sys_tmpdir = "/tmp";
+  if (file_iswdir (sys_tmpdir))
+    return sys_tmpdir;
+
+  sys_tmpdir = "/var/tmp";
+  if (file_iswdir (sys_tmpdir))
+    return sys_tmpdir;
+
+  sys_tmpdir = "/usr/tmp";
+  if (file_iswdir (sys_tmpdir))
+    return sys_tmpdir;
+
+  sys_tmpdir = DEFAULT_TMPDIR;
+
+  return sys_tmpdir;
+}
+
+static char *
+get_tmpdir (flags)
+     int flags;
+{
+  char *tdir;
+
+  tdir = (flags & MT_USETMPDIR) ? get_string_value ("TMPDIR") : (char *)NULL;
+  if (tdir == 0)
+    tdir = get_sys_tmpdir ();
+
+#if defined (HAVE_PATHCONF) && defined (_PC_NAME_MAX)
+  if (tmpnamelen == -1)
+    tmpnamelen = pathconf (tdir, _PC_NAME_MAX);
+#else
+  tmpnamelen = 0;
+#endif
+
+  return tdir;
+}
+
+char *
+sh_mktmpname (nameroot, flags)
+     char *nameroot;
+     int flags;
+{
+  char *filename, *tdir, *lroot;
+  struct stat sb;
+  int r, tdlen;
+
+  filename = (char *)xmalloc (PATH_MAX + 1);
+  tdir = get_tmpdir (flags);
+  tdlen = strlen (tdir);
+
+  lroot = nameroot ? nameroot : DEFAULT_NAMEROOT;
+
+#ifdef USE_MKTEMP
+  sprintf (filename, "%s/%s.XXXXXX", tdir, lroot);
+  if (mktemp (filename) == 0)
+    {
+      free (filename);
+      filename = NULL;
+    }
+#else  /* !USE_MKTEMP */
+  while (1)
+    {
+      filenum = (filenum << 1) ^
+               (unsigned long) time ((time_t *)0) ^
+               (unsigned long) dollar_dollar_pid ^
+               (unsigned long) ((flags & MT_USERANDOM) ? get_random_number () : ntmpfiles++);
+      sprintf (filename, "%s/%s-%lu", tdir, lroot, filenum);
+      if (tmpnamelen > 0 && tmpnamelen < 32)
+       filename[tdlen + 1 + tmpnamelen] = '\0';
+#  ifdef HAVE_LSTAT
+      r = lstat (filename, &sb);
+#  else
+      r = stat (filename, &sb);
+#  endif
+      if (r < 0 && errno == ENOENT)
+       break;
+    }
+#endif /* !USE_MKTEMP */
+
+  return filename;
+}
+
+int
+sh_mktmpfd (nameroot, flags, namep)
+     char *nameroot;
+     int flags;
+     char **namep;
+{
+  char *filename, *tdir, *lroot;
+  int fd, tdlen;
+
+  filename = (char *)xmalloc (PATH_MAX + 1);
+  tdir = get_tmpdir (flags);
+  tdlen = strlen (tdir);
+
+  lroot = nameroot ? nameroot : DEFAULT_NAMEROOT;
+
+#ifdef USE_MKSTEMP
+  sprintf (filename, "%s/%s.XXXXXX", tdir, lroot);
+  fd = mkstemp (filename);
+  if (fd < 0 || namep == 0)
+    {
+      free (filename);
+      filename = NULL;
+    }
+  if (namep)
+    *namep = filename;
+  return fd;
+#else /* !USE_MKSTEMP */
+  do
+    {
+      filenum = (filenum << 1) ^
+               (unsigned long) time ((time_t *)0) ^
+               (unsigned long) dollar_dollar_pid ^
+               (unsigned long) ((flags & MT_USERANDOM) ? get_random_number () : ntmpfiles++);
+      sprintf (filename, "%s/%s-%lu", tdir, lroot, filenum);
+      if (tmpnamelen > 0 && tmpnamelen < 32)
+       filename[tdlen + 1 + tmpnamelen] = '\0';
+      fd = open (filename, BASEOPENFLAGS | ((flags & MT_READWRITE) ? O_RDWR : O_WRONLY), 0600);
+    }
+  while (fd < 0 && errno == EEXIST);
+
+  if (namep)
+    *namep = filename;
+  else
+    free (filename);
+
+  return fd;
+#endif /* !USE_MKSTEMP */
+}
+
+FILE *
+sh_mktmpfp (nameroot, flags, namep)
+     char *nameroot;
+     int flags;
+     char **namep;
+{
+  int fd;
+  FILE *fp;
+
+  fd = sh_mktmpfd (nameroot, flags, namep);
+  if (fd < 0)
+    return ((FILE *)NULL);
+  fp = fdopen (fd, (flags & MT_READWRITE) ? "w+" : "w");
+  if (fp == 0)
+    close (fd);
+  return fp;
+}
index 8b39c99e7fdf2ad5878ffb3ba5283eca51421c00..f4696de0a8805df9f8a3e81ab52aeb287e464f24 100644 (file)
@@ -55,6 +55,7 @@ extern int shell_tty;
 #if defined (READLINE)
 extern void rl_set_screen_size __P((int, int));
 #endif
+extern void sh_set_lines_and_columns __P((int, int));
 
 void
 get_new_window_size (from_sig, rp, cp)
diff --git a/lib/sh/winsize.c~ b/lib/sh/winsize.c~
new file mode 100644 (file)
index 0000000..8b39c99
--- /dev/null
@@ -0,0 +1,82 @@
+/* Handle window size changes and information. */
+
+/* Copyright (C) 2005 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"
+
+#include <stdc.h>
+
+#include "bashtypes.h"
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include <sys/ioctl.h>
+
+#if !defined (STRUCT_WINSIZE_IN_SYS_IOCTL)
+/* For struct winsize on SCO */
+/*   sys/ptem.h has winsize but needs mblk_t from sys/stream.h */
+#  if defined (HAVE_SYS_PTEM_H) && defined (TIOCGWINSZ) && defined (SIGWINCH)
+#    if defined (HAVE_SYS_STREAM_H)
+#      include <sys/stream.h>
+#    endif
+#    include <sys/ptem.h>
+#  endif /* HAVE_SYS_PTEM_H && TIOCGWINSZ && SIGWINCH */
+#endif /* !STRUCT_WINSIZE_IN_SYS_IOCTL */
+
+#include <stdio.h>
+
+/* Return the fd from which we are actually getting input. */
+#define input_tty() (shell_tty != -1) ? shell_tty : fileno (stderr)
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+extern int shell_tty;
+
+#if defined (READLINE)
+extern void rl_set_screen_size __P((int, int));
+#endif
+
+void
+get_new_window_size (from_sig, rp, cp)
+     int from_sig;
+     int *rp, *cp;
+{
+#if defined (TIOCGWINSZ)
+  struct winsize win;
+  int tty;
+
+  tty = input_tty ();
+  if (tty >= 0 && (ioctl (tty, TIOCGWINSZ, &win) == 0) &&
+      win.ws_row > 0 && win.ws_col > 0)
+    {
+      sh_set_lines_and_columns (win.ws_row, win.ws_col);
+#if defined (READLINE)
+      rl_set_screen_size (win.ws_row, win.ws_col);
+      if (rp)
+       *rp = win.ws_row;
+      if (cp)
+       *cp = win.ws_col;
+#endif
+    }
+#endif
+}
index 9eaa24ec2d7cbd656b4ab2675ad48cf30cfb279c..1a222dc46ce120c00928d4de4b83b833ed1618c1 100644 (file)
--- a/locale.c
+++ b/locale.c
@@ -78,7 +78,6 @@ void
 set_default_locale_vars ()
 {
   char *val;
-  int r;
 
 #if defined (HAVE_SETLOCALE)
 
index df20010566c5b8ced9b38b1f2b137a336a7b8110..82047ea525260a935765819c6ab76ac787fa5dd6 100644 (file)
@@ -750,7 +750,6 @@ make_function_def (name, command, lineno, lstart)
 #if defined (ARRAY_VARS)
   SHELL_VAR *bash_source_v;
   ARRAY *bash_source_a;
-  char *t;
 #endif
 
   temp = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF));
diff --git a/parse.y b/parse.y
index 87781e519d4b2d3791bf79c7fa03881b5179b01e..c7dd436f6d19aab7d13b8e960579e19e2fd58379 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -205,10 +205,6 @@ static void reset_readline_prompt __P((void));
 #endif
 static void print_prompt __P((void));
 
-#if defined (HISTORY)
-char *history_delimiting_chars __P((void));
-#endif
-
 #if defined (HANDLE_MULTIBYTE)
 static void set_line_mbstate __P((void));
 static char *shell_input_line_property = NULL;
@@ -1876,7 +1872,6 @@ shell_getc (remove_quoted_newline)
   register int i;
   int c;
   unsigned char uc;
-  static int mustpop = 0;
 
   QUIT;
 
@@ -2956,8 +2951,8 @@ static int
 parse_dparen (c)
      int c;
 {
-  int cmdtyp, len, sline;
-  char *wval, *wv2;
+  int cmdtyp, sline;
+  char *wval;
   WORD_DESC *wd;
 
 #if defined (ARITH_FOR_COMMAND)
@@ -4160,7 +4155,7 @@ decode_prompt_string (string)
            case 'W':
              {
                /* Use the value of PWD because it is much more efficient. */
-               char t_string[PATH_MAX], *t;
+               char t_string[PATH_MAX];
                int tlen;
 
                temp = get_string_value ("PWD");
@@ -4371,15 +4366,15 @@ yyerror (msg)
 }
 
 static char *
-error_token_from_token (token)
-     int token;
+error_token_from_token (tok)
+     int tok;
 {
   char *t;
 
-  if (t = find_token_in_alist (token, word_token_alist, 0))
+  if (t = find_token_in_alist (tok, word_token_alist, 0))
     return t;
 
-  if (t = find_token_in_alist (token, other_token_alist, 0))
+  if (t = find_token_in_alist (tok, other_token_alist, 0))
     return t;
 
   t = (char *)NULL;
index 1034c8040995dde5ac4493c535c0d545f14102d9..f654d1031f463670e726564b7e27514d55779bac 100644 (file)
--- a/parse.y~
+++ b/parse.y~
@@ -1876,7 +1876,6 @@ shell_getc (remove_quoted_newline)
   register int i;
   int c;
   unsigned char uc;
-  static int mustpop = 0;
 
   QUIT;
 
@@ -2563,7 +2562,7 @@ read_token (command)
 #endif /* ALIAS */
 
   /* Read a single word from input.  Start by skipping blanks. */
-  while ((character = shell_getc (1)) != EOF && whitespace (character))
+  while ((character = shell_getc (1)) != EOF && shellblank (character))
     ;
 
   if (character == EOF)
@@ -2956,8 +2955,8 @@ static int
 parse_dparen (c)
      int c;
 {
-  int cmdtyp, len, sline;
-  char *wval, *wv2;
+  int cmdtyp, sline;
+  char *wval;
   WORD_DESC *wd;
 
 #if defined (ARITH_FOR_COMMAND)
@@ -4160,7 +4159,7 @@ decode_prompt_string (string)
            case 'W':
              {
                /* Use the value of PWD because it is much more efficient. */
-               char t_string[PATH_MAX], *t;
+               char t_string[PATH_MAX];
                int tlen;
 
                temp = get_string_value ("PWD");
@@ -4371,15 +4370,15 @@ yyerror (msg)
 }
 
 static char *
-error_token_from_token (token)
-     int token;
+error_token_from_token (tok)
+     int tok;
 {
   char *t;
 
-  if (t = find_token_in_alist (token, word_token_alist, 0))
+  if (t = find_token_in_alist (tok, word_token_alist, 0))
     return t;
 
-  if (t = find_token_in_alist (token, other_token_alist, 0))
+  if (t = find_token_in_alist (tok, other_token_alist, 0))
     return t;
 
   t = (char *)NULL;
index ee462dc881c36e4482b10292e2f8e1969d5e080b..471fb54f95b5116f0442734f89bce94554413c29 100644 (file)
@@ -815,7 +815,7 @@ gen_wordlist_matches (cs, text)
 {
   WORD_LIST *l, *l2;
   STRINGLIST *sl;
-  int nw, tlen, qc;
+  int nw, tlen;
   char *ntxt;          /* dequoted TEXT to use in comparisons */
 
   if (cs->words == 0 || cs->words[0] == '\0')
diff --git a/subst.c b/subst.c
index 5f06dd5755d0c90dc5746fdb9f2cf5d9dd42363f..6a180aa775c7dd2e8ce86f78a69ecc2cdd02a6b8 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -1583,7 +1583,8 @@ split_at_delims (string, slen, delims, sentinel, nwp, cwp)
       while (delims[i])
        {
 #if defined (HANDLE_MULTIBYTE)
-         mbstate_t state_bak = state;
+         mbstate_t state_bak;
+         state_bak = state;
          mblength = MBRLEN (delims + i, slength, &state);
          if (MB_INVALIDCH (mblength))
            state = state_bak;
@@ -2035,7 +2036,7 @@ list_string (string, separators, quoted)
          sindex++;
          /* An IFS character that is not IFS white space, along with any
             adjacent IFS white space, shall delimit a field. (SUSv3) */
-         while (s[sindex] && spctabnl (s[sindex]) && isifs (s[sindex]))
+         while (string[sindex] && spctabnl (string[sindex]) && isifs (string[sindex]))
            sindex++;
        }
     }
@@ -2223,7 +2224,7 @@ do_compound_assignment (name, value, flags)
      int flags;
 {
   SHELL_VAR *v;
-  int off, mklocal;
+  int mklocal;
   WORD_LIST *list;
 
   mklocal = flags & ASS_MKLOCAL;
@@ -2254,7 +2255,7 @@ do_assignment_internal (word, expand)
      int expand;
 {
   int offset, tlen, appendop, assign_list, aflags;
-  char *name, *value, *ovalue, *nvalue;
+  char *name, *value;
   SHELL_VAR *entry;
 #if defined (ARRAY_VARS)
   char *t;
@@ -2286,11 +2287,7 @@ do_assignment_internal (word, expand)
       tlen = STRLEN (temp);
 
 #if defined (ARRAY_VARS)
-#  if 0
-      if (expand && temp[0] == LPAREN && temp[tlen-1] == RPAREN)
-#else
       if (expand && (word->flags & W_COMPASSIGN))
-#endif
        {
          assign_list = ni = 1;
          value = extract_array_assignment_list (temp, &ni);
@@ -3346,9 +3343,8 @@ remove_wpattern (wparam, wstrlen, wpattern, op)
      wchar_t *wpattern;
      int op;
 {
-  wchar_t wc;
-  int n, n1;
-  wchar_t *ret;
+  wchar_t wc, *ret;
+  int n;
 
   switch (op)
     {
@@ -3802,7 +3798,9 @@ getpattern (value, quoted, expandpat)
 {
   char *pat, *tword;
   WORD_LIST *l;
+#if 0
   int i;
+#endif
 
   /* There is a problem here:  how to handle single or double quotes in the
      pattern string when the whole expression is between double quotes?
@@ -5655,7 +5653,7 @@ pos_params_pat_subst (string, pat, rep, mflags)
 {
   WORD_LIST *save, *params;
   WORD_DESC *w;
-  char *ret, *tt;
+  char *ret;
 
   save = params = list_rest_of_args ();
   if (save == 0)
@@ -7576,9 +7574,6 @@ word_list_split (list)
   for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
     {
       tresult = word_split (t->word, ifs_value);
-#if 0
-      result = (WORD_LIST *) list_append (result, tresult);
-#else
       if (result == 0)
         result = e = tresult;
       else
@@ -7587,7 +7582,6 @@ word_list_split (list)
          while (e->next)
            e = e->next;
        }
-#endif
     }
   return (result);
 }
index cc1cfda8d3b54e851c4e951651adaba1a34caaa4..4a7d266e63ea2f2610fd21a643dc64ef09af2b9c 100644 (file)
--- a/subst.c~
+++ b/subst.c~
@@ -949,8 +949,8 @@ string_extract_verbatim (string, slen, sindex, charlist)
                  len = mbstowcs (wcharlist, charlist, 0);
                  if (len == -1)
                    len = 0;
-                 wcharlist = (wchar_t *)xmalloc ((sizeof (wchar_t) * len) + 1);
-                 mbstowcs (wcharlist, charlist, len);
+                 wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1));
+                 mbstowcs (wcharlist, charlist, len + 1);
                }
 
              if (wcschr (wcharlist, wc))
@@ -1583,7 +1583,8 @@ split_at_delims (string, slen, delims, sentinel, nwp, cwp)
       while (delims[i])
        {
 #if defined (HANDLE_MULTIBYTE)
-         mbstate_t state_bak = state;
+         mbstate_t state_bak;
+         state_bak = state;
          mblength = MBRLEN (delims + i, slength, &state);
          if (MB_INVALIDCH (mblength))
            state = state_bak;
@@ -2035,7 +2036,7 @@ list_string (string, separators, quoted)
          sindex++;
          /* An IFS character that is not IFS white space, along with any
             adjacent IFS white space, shall delimit a field. (SUSv3) */
-         while (s[sindex] && spctabnl (s[sindex]) && isifs (s[sindex]))
+         while (string[sindex] && spctabnl (string[sindex]) && isifs (string[sindex]))
            sindex++;
        }
     }
@@ -2223,7 +2224,7 @@ do_compound_assignment (name, value, flags)
      int flags;
 {
   SHELL_VAR *v;
-  int off, mklocal;
+  int mklocal;
   WORD_LIST *list;
 
   mklocal = flags & ASS_MKLOCAL;
@@ -2254,7 +2255,7 @@ do_assignment_internal (word, expand)
      int expand;
 {
   int offset, tlen, appendop, assign_list, aflags;
-  char *name, *value, *ovalue, *nvalue;
+  char *name, *value;
   SHELL_VAR *entry;
 #if defined (ARRAY_VARS)
   char *t;
@@ -2286,11 +2287,7 @@ do_assignment_internal (word, expand)
       tlen = STRLEN (temp);
 
 #if defined (ARRAY_VARS)
-#  if 0
-      if (expand && temp[0] == LPAREN && temp[tlen-1] == RPAREN)
-#else
       if (expand && (word->flags & W_COMPASSIGN))
-#endif
        {
          assign_list = ni = 1;
          value = extract_array_assignment_list (temp, &ni);
@@ -3346,9 +3343,8 @@ remove_wpattern (wparam, wstrlen, wpattern, op)
      wchar_t *wpattern;
      int op;
 {
-  wchar_t wc;
-  int n, n1;
-  wchar_t *ret;
+  wchar_t wc, *ret;
+  int n;
 
   switch (op)
     {
@@ -3802,7 +3798,9 @@ getpattern (value, quoted, expandpat)
 {
   char *pat, *tword;
   WORD_LIST *l;
+#if 0
   int i;
+#endif
 
   /* There is a problem here:  how to handle single or double quotes in the
      pattern string when the whole expression is between double quotes?
@@ -5655,7 +5653,7 @@ pos_params_pat_subst (string, pat, rep, mflags)
 {
   WORD_LIST *save, *params;
   WORD_DESC *w;
-  char *ret, *tt;
+  char *ret;
 
   save = params = list_rest_of_args ();
   if (save == 0)
diff --git a/trap.c b/trap.c
index 64cdbd0867cb0e78964baf056f217ff94576c439..2d5934f1a0c85272469ccee7cf3c7fd62cf91332 100644 (file)
--- a/trap.c
+++ b/trap.c
@@ -76,7 +76,6 @@ static void restore_signal __P((int));
 static void reset_or_restore_signal_handlers __P((sh_resetsig_func_t *));
 
 /* Variables used here but defined in other files. */
-extern int interrupt_immediately;
 extern int last_command_exit_value;
 extern int line_number;
 
diff --git a/trap.c~ b/trap.c~
index 9ada606d581f266d2ffa87855695a38c09ed4d5d..64cdbd0867cb0e78964baf056f217ff94576c439 100644 (file)
--- a/trap.c~
+++ b/trap.c~
@@ -888,18 +888,13 @@ reset_or_restore_signal_handlers (reset)
      `functrace' or `errtrace' options have been set, then let command
      substitutions inherit them.  Let command substitution inherit the
      RETURN trap if we're in the debugger and tracing functions. */
-#if defined (DEBUGGER)
-  if (debugging_mode == 0 && function_trace_mode == 0)
-#endif
-    sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED;
-#if defined (DEBUGGER)
-  if (debugging_mode == 0 && error_trace_mode == 0)
-#endif
+  if (function_trace_mode == 0)
+    {
+      sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED;
+      sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED;
+    }
+  if (error_trace_mode == 0)
     sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED;
-#if defined (DEBUGGER)
-  if (debugging_mode == 0 && function_trace_mode == 0)
-#endif
-    sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED;
 }
 
 /* Reset trapped signals to their original values, but don't free the
index 4bb7a78f010d92900811040f948e63bc7da3d64f..4fd194e8f8e6f1adf9ae2cdd3d96aedf1e5e1057 100644 (file)
@@ -73,8 +73,6 @@ typedef union uwp {
 } UNWIND_ELT;
 
 
-extern int interrupt_immediately;
-
 static void without_interrupts __P((VFunction *, char *, char *));
 static void unwind_frame_discard_internal __P((char *, char *));
 static void unwind_frame_run_internal __P((char *, char *));
diff --git a/unwind_prot.c~ b/unwind_prot.c~
new file mode 100644 (file)
index 0000000..4bb7a78
--- /dev/null
@@ -0,0 +1,320 @@
+/* I can't stand it anymore!  Please can't we just write the
+   whole Unix system in lisp or something? */
+
+/* Copyright (C) 1987-2002 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. */
+
+/* **************************************************************** */
+/*                                                                 */
+/*                   Unwind Protection Scheme for Bash             */
+/*                                                                 */
+/* **************************************************************** */
+#include "config.h"
+
+#include "bashtypes.h"
+#include "bashansi.h"
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#if STDC_HEADERS
+#  include <stddef.h>
+#endif
+
+#ifndef offsetof
+#  define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#include "command.h"
+#include "general.h"
+#include "unwind_prot.h"
+#include "quit.h"
+#include "sig.h"
+
+/* Structure describing a saved variable and the value to restore it to.  */
+typedef struct {
+  char *variable;
+  int size;
+  char desired_setting[1]; /* actual size is `size' */
+} SAVED_VAR;
+
+/* If HEAD.CLEANUP is null, then ARG.V contains a tag to throw back to.
+   If HEAD.CLEANUP is restore_variable, then SV.V contains the saved
+   variable.  Otherwise, call HEAD.CLEANUP (ARG.V) to clean up.  */
+typedef union uwp {
+  struct uwp_head {
+    union uwp *next;
+    Function *cleanup;
+  } head;
+  struct {
+    struct uwp_head uwp_head;
+    char *v;
+  } arg;
+  struct {
+    struct uwp_head uwp_head;
+    SAVED_VAR v;
+  } sv;
+} UNWIND_ELT;
+
+
+extern int interrupt_immediately;
+
+static void without_interrupts __P((VFunction *, char *, char *));
+static void unwind_frame_discard_internal __P((char *, char *));
+static void unwind_frame_run_internal __P((char *, char *));
+static void add_unwind_protect_internal __P((Function *, char *));
+static void remove_unwind_protect_internal __P((char *, char *));
+static void run_unwind_protects_internal __P((char *, char *));
+static void clear_unwind_protects_internal __P((char *, char *));
+static inline void restore_variable __P((SAVED_VAR *));
+static void unwind_protect_mem_internal __P((char *, char *));
+
+static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
+
+#define uwpalloc(elt)  (elt) = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT))
+#define uwpfree(elt)   free(elt)
+
+/* Run a function without interrupts.  This relies on the fact that the
+   FUNCTION cannot change the value of interrupt_immediately.  (I.e., does
+   not call QUIT (). */
+static void
+without_interrupts (function, arg1, arg2)
+     VFunction *function;
+     char *arg1, *arg2;
+{
+  int old_interrupt_immediately;
+
+  old_interrupt_immediately = interrupt_immediately;
+  interrupt_immediately = 0;
+
+  (*function)(arg1, arg2);
+
+  interrupt_immediately = old_interrupt_immediately;
+}
+
+/* Start the beginning of a region. */
+void
+begin_unwind_frame (tag)
+     char *tag;
+{
+  add_unwind_protect ((Function *)NULL, tag);
+}
+
+/* Discard the unwind protects back to TAG. */
+void
+discard_unwind_frame (tag)
+     char *tag;
+{
+  if (unwind_protect_list)
+    without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
+}
+
+/* Run the unwind protects back to TAG. */
+void
+run_unwind_frame (tag)
+     char *tag;
+{
+  if (unwind_protect_list)
+    without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
+}
+
+/* Add the function CLEANUP with ARG to the list of unwindable things. */
+void
+add_unwind_protect (cleanup, arg)
+     Function *cleanup;
+     char *arg;
+{
+  without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
+}
+
+/* Remove the top unwind protect from the list. */
+void
+remove_unwind_protect ()
+{
+  if (unwind_protect_list)
+    without_interrupts
+      (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
+}
+
+/* Run the list of cleanup functions in unwind_protect_list. */
+void
+run_unwind_protects ()
+{
+  if (unwind_protect_list)
+    without_interrupts
+      (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
+}
+
+/* Erase the unwind-protect list.  If flags is 1, free the elements. */
+void
+clear_unwind_protect_list (flags)
+     int flags;
+{
+  char *flag;
+
+  if (unwind_protect_list)
+    {
+      flag = flags ? "" : (char *)NULL;
+      without_interrupts
+        (clear_unwind_protects_internal, flag, (char *)NULL);
+    }
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     The Actual Functions                        */
+/*                                                                 */
+/* **************************************************************** */
+
+static void
+add_unwind_protect_internal (cleanup, arg)
+     Function *cleanup;
+     char *arg;
+{
+  UNWIND_ELT *elt;
+
+  uwpalloc (elt);
+  elt->head.next = unwind_protect_list;
+  elt->head.cleanup = cleanup;
+  elt->arg.v = arg;
+  unwind_protect_list = elt;
+}
+
+static void
+remove_unwind_protect_internal (ignore1, ignore2)
+     char *ignore1, *ignore2;
+{
+  UNWIND_ELT *elt;
+
+  elt = unwind_protect_list;
+  if (elt)
+    {
+      unwind_protect_list = unwind_protect_list->head.next;
+      uwpfree (elt);
+    }
+}
+
+static void
+run_unwind_protects_internal (ignore1, ignore2)
+     char *ignore1, *ignore2;
+{
+  unwind_frame_run_internal ((char *) NULL, (char *) NULL);
+}
+
+static void
+clear_unwind_protects_internal (flag, ignore)
+     char *flag, *ignore;
+{
+  if (flag)
+    {
+      while (unwind_protect_list)
+       remove_unwind_protect_internal ((char *)NULL, (char *)NULL);
+    }
+  unwind_protect_list = (UNWIND_ELT *)NULL;
+}
+
+static void
+unwind_frame_discard_internal (tag, ignore)
+     char *tag, *ignore;
+{
+  UNWIND_ELT *elt;
+
+  while (elt = unwind_protect_list)
+    {
+      unwind_protect_list = unwind_protect_list->head.next;
+      if (elt->head.cleanup == 0 && (STREQ (elt->arg.v, tag)))
+       {
+         uwpfree (elt);
+         break;
+       }
+      else
+       uwpfree (elt);
+    }
+}
+
+/* Restore the value of a variable, based on the contents of SV.
+   sv->desired_setting is a block of memory SIZE bytes long holding the
+   value itself.  This block of memory is copied back into the variable. */
+static inline void
+restore_variable (sv)
+     SAVED_VAR *sv;
+{
+  FASTCOPY (sv->desired_setting, sv->variable, sv->size);
+}
+
+static void
+unwind_frame_run_internal (tag, ignore)
+     char *tag, *ignore;
+{
+  UNWIND_ELT *elt;
+
+  while (elt = unwind_protect_list)
+    {
+      unwind_protect_list = elt->head.next;
+
+      /* If tag, then compare. */
+      if (!elt->head.cleanup)
+       {
+         if (tag && STREQ (elt->arg.v, tag))
+           {
+             uwpfree (elt);
+             break;
+           }
+       }
+      else
+       {
+         if (elt->head.cleanup == (Function *) restore_variable)
+           restore_variable (&elt->sv.v);
+         else
+           (*(elt->head.cleanup)) (elt->arg.v);
+       }
+
+      uwpfree (elt);
+    }
+}
+
+static void
+unwind_protect_mem_internal (var, psize)
+     char *var;
+     char *psize;
+{
+  int size, allocated;
+  UNWIND_ELT *elt;
+
+  size = *(int *) psize;
+  allocated = size + offsetof (UNWIND_ELT, sv.v.desired_setting[0]);
+  elt = (UNWIND_ELT *)xmalloc (allocated);
+  elt->head.next = unwind_protect_list;
+  elt->head.cleanup = (Function *) restore_variable;
+  elt->sv.v.variable = var;
+  elt->sv.v.size = size;
+  FASTCOPY (var, elt->sv.v.desired_setting, size);
+  unwind_protect_list = elt;
+}
+
+/* Save the value of a variable so it will be restored when unwind-protects
+   are run.  VAR is a pointer to the variable.  SIZE is the size in
+   bytes of VAR.  */
+void
+unwind_protect_mem (var, size)
+     char *var;
+     int size;
+{
+  without_interrupts (unwind_protect_mem_internal, var, (char *) &size);
+}
index f9b9de79e31a82dab3044bcd410140bef7743cf8..fd228b5ee51818f2a52af2499a245d02ff864e55 100644 (file)
@@ -1306,20 +1306,11 @@ static SHELL_VAR *
 get_comp_wordbreaks (var)
      SHELL_VAR *var;
 {
-  char *p;
-
   /* If we don't have anything yet, assign a default value. */
   if (rl_completer_word_break_characters == 0 && bash_readline_initialized == 0)
     enable_hostname_completion (perform_hostname_completion);
 
-#if 0
-  FREE (value_cell (var));
-  p = savestring (rl_completer_word_break_characters);
-  
-  var_setvalue (var, p);
-#else
   var_setvalue (var, rl_completer_word_break_characters);
-#endif
 
   return (var);
 }
@@ -2033,16 +2024,11 @@ bind_int_variable (lhs, rhs)
      char *lhs, *rhs;
 {
   register SHELL_VAR *v;
-  char *t;
   int isint, isarr;
 
   isint = isarr = 0;
 #if defined (ARRAY_VARS)
-#  if 0
-  if (t = xstrchr (lhs, '['))  /*]*/
-#  else
   if (valid_array_reference (lhs))
-#  endif
     {
       isarr = 1;
       v = array_variable_part (lhs, (char **)0, (int *)0);
index eec26c31abfcdbf1bce825ffdfd65113c727c847..00e6ca27287e710f88fd00f297df68571bd71a7a 100644 (file)
@@ -330,7 +330,6 @@ extern int get_random_number __P((void));
 extern void sv_ifs __P((char *));
 extern void sv_path __P((char *));
 extern void sv_mail __P((char *));
-extern void sv_comp_wordbreaks __P((char *));
 extern void sv_globignore __P((char *));
 extern void sv_ignoreeof __P((char *));
 extern void sv_strict_posix __P((char *));