]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20080501 snapshot
authorChet Ramey <chet.ramey@case.edu>
Wed, 7 Dec 2011 14:23:10 +0000 (09:23 -0500)
committerChet Ramey <chet.ramey@case.edu>
Wed, 7 Dec 2011 14:23:10 +0000 (09:23 -0500)
71 files changed:
CWRU/CWRU.chlog
CWRU/CWRU.chlog~
MANIFEST
MANIFEST~
Makefile.in
Makefile.in~
array.c
array.c~
array.h
array.h~
arrayfunc.c
arrayfunc.c~
assoc.c [new file with mode: 0644]
assoc.c~ [new file with mode: 0644]
assoc.h [new file with mode: 0644]
assoc.h~ [new file with mode: 0644]
autom4te.cache/output.0
autom4te.cache/requests
autom4te.cache/traces.0
bashline.c
bashline.c~
builtins/fc.def
builtins/fc.def~
builtins/read.def
builtins/read.def~
builtins/shopt.def
builtins/shopt.def~
config.h.in
config.h.in~
configure
configure.in
configure.in~
doc/bash.1
doc/bash.1~
doc/bashref.texi
doc/bashref.texi~
doc/version.texi
doc/version.texi~
general.c
general.c~
general.h
general.h~
hashcmd.h
hashcmd.h~ [new file with mode: 0644]
jobs.c
jobs.c~
lib/glob/glob.c
lib/glob/glob.c~ [new file with mode: 0644]
lib/glob/glob.h
lib/readline/bind.c
lib/readline/bind.c~
lib/readline/complete.c
lib/readline/complete.c~
lib/readline/menucomp [new file with mode: 0644]
lib/readline/readline.h
lib/readline/readline.h~
parse.y
parse.y~
parser.h
parser.h~ [new file with mode: 0644]
pathexp.c
pathexp.c~ [new file with mode: 0644]
pathexp.h
pathexp.h~ [new file with mode: 0644]
tests/RUN-ONE-TEST
tests/new-exp.right
tests/new-exp.tests
tests/new-exp.tests~ [new file with mode: 0644]
tests/new-exp7.sub [new file with mode: 0644]
tests/shopt.right
variables.c

index 9e378f30b50ab6c48c286b9f6f26ffcd7af2ba5b..5e5fa761cac6f0ed27e35d5a13666cfdf3e7f2e6 100644 (file)
@@ -15613,3 +15613,125 @@ doc/{bash.1,bashref.texi}
 
 configure.in
        - change default version to bash-4.0-devel
+
+                                  4/28
+                                  ----
+variables.c
+       - change push_func_var and push_exported_var to call
+         stupidly_hack_special_variables if the temporary variable is going
+         to be disposed.  This undoes any internal changes caused by a local
+         variable assignment in the environment or in a shell function.  Bug
+         reported by Morita Sho <morita-pub-en-debian@inz.sakura.ne.jp> in
+         http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=478096
+
+                                   5/3
+                                   ---
+builtins/fc.def
+       - fixed a problem caused by change of 1/21 to use remember_on_history,
+         since it's turned off by parse_and_execute(), but can cause the
+         last command in history to be deleted and leave last_hist pointing
+         beyond the end of the history list.  edit_and_execute_command can
+         do this.
+
+bashline.c
+       - new define, RL_BOOLEAN_VAR_VALUE, to take a readline boolean variable
+         and get its value as 0 or 1 (consider making readline global)
+       - put tty back into canonical mode before calling parse_and_execute in
+         edit_and_execute_command and then back into raw mode after it
+         returns.  Fixes problem identified by <koersen@gmail.com>.
+
+                                   5/4
+                                   ---
+lib/glob/glob.c
+       - code to support `globstar' option: GX_GLOBSTAR and two internal
+         flags.  Changes to skipname, glob_vector, mbskipname, glob_filename.
+         New function finddirs().
+
+lib/glob/glob.h
+       - new defines to support globstar code
+
+builtins/shopt.def
+       - new shell option, `globstar', enables special handling of `**' in
+         glob patterns -- matches all directories recursively
+
+pathexp.h
+       - extern declaration for glob_star
+
+pathexp.c
+       - break inline code out of quote_globbing_chars into a separate
+         function to decide whether a character is a globbing char:
+         glob_char_p
+       - change shell_glob_filename to call glob_filename with the
+         GX_GLOBSTAR flag if glob_star is set
+
+doc/{bash.1,bashref.texi}
+       - document new `globstar' shell option
+
+arrayfunc.c
+       - new function, broken out of quote_array_assignment_chars:
+         quote_assign; extended from old code to make sure that globbing
+         chars and chars in $IFS are quoted when displaying assignment
+         statements, especially in compound array assignments
+
+                                   5/5
+                                   ---
+bashline.c
+       - new variable, dircomplete_spelling, controls spelling correction
+         of directory names when doing filename completion
+       - change bash_directory_completion_hook to incorporate spelling
+         correction if initial canonicalization of directory name fails
+
+builtins/shopt.def
+       - new shell option, `dirspell', enables and disables spelling
+         correction of directory names during word completion
+
+builtins/read.def
+       - support for fractional timeout values (ival.uval); uses uconvert
+         and falarm/setitimer
+
+config.h.in
+       - new `HAVE_SETITIMER' define
+
+configure.in
+       - look for setitimer(2), define HAVE_SETITIMER if found
+
+doc/{bash.1,bashref.texi}
+       - document new `dirspell' shopt option
+       - document new fractional values to `read -t timeout'
+
+                                   5/6
+                                   ---
+assoc.[ch]
+       - new files, basic support for associative array implementation
+
+general.h
+       - new extern declarations for sh_openpipe, sh_closepipe, trim_pathname
+
+general.c
+        - new functions: sh_openpipe to create a pipe and move the file
+          descriptors to a high range; sh_closepipe, to close pipe fds and
+          clean up, and trim_pathname, to replace portions of a pathname
+          with `...' (for prompting)
+
+jobs.c
+       - don't set last_asynchronous_pid in child shell (messes up $!, among
+         other things)
+
+parse.y,parser.h
+       - moved definitions of parser flags to parser.h
+
+array.c
+       - imported array_modcase (case-changing operations on arrays) from
+         4.0-devel branch
+
+array.h
+       - new extern declaration for array_modcase
+
+lib/readline/complete.c
+       - new variable, rl_menu_completion_entry_function, generator for
+         rl_menu_complete
+       - new menu completion `browsing' implementation, with several
+         improvements over the old code.  Inspired by Sami
+
+lib/readline/readline.h
+       - extern declaration for rl_menu_completion_entry_function
index c38001fe1a7c04bb37af3a7a2b2752f67352a2ab..ae2498e98721a7deabd224bcfc235b15f1fabe5d 100644 (file)
@@ -15331,7 +15331,7 @@ lib/readline/rltty.c
                                    3/6
                                    ---
 {MANIFEST,Makefile.in},lib/sh/{casemod,uconvert,ufuncs}.c
-       - new library sources from bash-4.0-devel triee
+       - new library sources from bash-4.0-devel tree
 
 lib/sh/spell.c
        - moved cdspell() here from builtins/cd.def, renamed dirspell()
@@ -15613,3 +15613,123 @@ doc/{bash.1,bashref.texi}
 
 configure.in
        - change default version to bash-4.0-devel
+
+                                  4/28
+                                  ----
+variables.c
+       - change push_func_var and push_exported_var to call
+         stupidly_hack_special_variables if the temporary variable is going
+         to be disposed.  This undoes any internal changes caused by a local
+         variable assignment in the environment or in a shell function.  Bug
+         reported by Morita Sho <morita-pub-en-debian@inz.sakura.ne.jp> in
+         http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=478096
+
+                                   5/3
+                                   ---
+builtins/fc.def
+       - fixed a problem caused by change of 1/21 to use remember_on_history,
+         since it's turned off by parse_and_execute(), but can cause the
+         last command in history to be deleted and leave last_hist pointing
+         beyond the end of the history list.  edit_and_execute_command can
+         do this.
+
+bashline.c
+       - new define, RL_BOOLEAN_VAR_VALUE, to take a readline boolean variable
+         and get its value as 0 or 1 (consider making readline global)
+       - put tty back into canonical mode before calling parse_and_execute in
+         edit_and_execute_command and then back into raw mode after it
+         returns.  Fixes problem identified by <koersen@gmail.com>.
+
+                                   5/4
+                                   ---
+lib/glob/glob.c
+       - code to support `globstar' option: GX_GLOBSTAR and two internal
+         flags.  Changes to skipname, glob_vector, mbskipname, glob_filename.
+         New function finddirs().
+
+lib/glob/glob.h
+       - new defines to support globstar code
+
+builtins/shopt.def
+       - new shell option, `globstar', enables special handling of `**' in
+         glob patterns -- matches all directories recursively
+
+pathexp.h
+       - extern declaration for glob_star
+
+pathexp.c
+       - break inline code out of quote_globbing_chars into a separate
+         function to decide whether a character is a globbing char:
+         glob_char_p
+       - change shell_glob_filename to call glob_filename with the
+         GX_GLOBSTAR flag if glob_star is set
+
+doc/{bash.1,bashref.texi}
+       - document new `globstar' shell option
+
+arrayfunc.c
+       - new function, broken out of quote_array_assignment_chars:
+         quote_assign; extended from old code to make sure that globbing
+         chars and chars in $IFS are quoted when displaying assignment
+         statements, especially in compound array assignments
+
+                                   5/5
+                                   ---
+bashline.c
+       - new variable, dircomplete_spelling, controls spelling correction
+         of directory names when doing filename completion
+       - change bash_directory_completion_hook to incorporate spelling
+         correction if initial canonicalization of directory name fails
+
+builtins/shopt.def
+       - new shell option, `dirspell', enables and disables spelling
+         correction of directory names during word completion
+
+builtins/read.def
+       - support for fractional timeout values (ival.uval); uses uconvert
+         and falarm/setitimer
+
+config.h.in
+       - new `HAVE_SETITIMER' define
+
+configure.in
+       - look for setitimer(2), define HAVE_SETITIMER if found
+
+doc/{bash.1,bashref.texi}
+       - document new `dirspell' shopt option
+       - document new fractional values to `read -t timeout'
+
+                                   5/6
+                                   ---
+assoc.[ch]
+       - new files, basic support for associative array implementation
+
+general.h
+       - new extern declarations for sh_openpipe, sh_closepipe, trim_pathname
+
+general.c
+        - new functions: sh_openpipe to create a pipe and move the file
+          descriptors to a high range; sh_closepipe, to close pipe fds and
+          clean up, and trim_pathname, to replace portions of a pathname
+          with `...' (for prompting)
+
+jobs.c
+       - don't set last_asynchronous_pid in child shell (messes up $!, among
+         other things)
+
+parse.y,parser.h
+       - moved definitions of parser flags to parser.h
+
+array.c
+       - imported array_modcase (case-changing operations on arrays) from
+         4.0-devel branch
+
+array.h
+       - new extern declaration for array_modcase
+
+lib/readline/complete.c
+       - new variable, rl_menu_completion_entry_function, generator for
+         rl_menu_complete
+
+lib/readline/readline.h
+       - extern declaration for rl_menu_completion_entry_function
index c87be75c46faac880d7aa72ad1bd0e434ff5c02c..afed7617eea32d76866e6c4ee1123110f2a3ee2e 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -60,6 +60,7 @@ config.h.in   f
 aclocal.m4     f
 array.c                f
 arrayfunc.c    f
+assoc.c                f
 eval.c         f
 print_cmd.c    f
 general.c      f
@@ -110,6 +111,7 @@ patchlevel.h        f
 variables.h    f
 array.h                f
 arrayfunc.h    f
+assoc.h                f
 jobs.h         f
 findcmd.h      f
 hashlib.h      f
@@ -857,6 +859,7 @@ tests/new-exp3.sub  f
 tests/new-exp4.sub     f
 tests/new-exp5.sub     f
 tests/new-exp6.sub     f
+tests/new-exp7.sub     f
 tests/new-exp.right    f
 tests/nquote.tests     f
 tests/nquote.right     f
index 470ff111947c0a64f5ebae1273cf6c8df41076b2..1d8de95bebe227ecffb1600433772607bbcd9143 100644 (file)
--- a/MANIFEST~
+++ b/MANIFEST~
@@ -60,6 +60,7 @@ config.h.in   f
 aclocal.m4     f
 array.c                f
 arrayfunc.c    f
+assoc.c                f
 eval.c         f
 print_cmd.c    f
 general.c      f
@@ -110,6 +111,7 @@ patchlevel.h        f
 variables.h    f
 array.h                f
 arrayfunc.h    f
+assoc.h                f
 jobs.h         f
 findcmd.h      f
 hashlib.h      f
@@ -176,6 +178,7 @@ builtins/let.def    f
 builtins/history.def   f
 builtins/jobs.def      f
 builtins/kill.def      f
+builtins/mapfile.def   f
 builtins/mkbuiltins.c  f
 builtins/printf.def    f
 builtins/pushd.def     f
@@ -464,24 +467,55 @@ po/LINGUAS                f
 po/Makefile.in.in      f
 po/Makevars            f
 po/POTFILES.in         f
+po/README              f
 po/Rules-builtins      f
 po/Rules-quot          f
 po/bash.pot            f
 po/boldquot.sed                f
-po/en@quot.header      f
+po/en@boldquot.gmo     f
 po/en@boldquot.header  f
-po/en@quot.po          f
 po/en@boldquot.po      f
 po/en@quot.gmo         f
-po/en@boldquot.gmo     f
-po/bg.po               f
+po/en@quot.header      f
+po/en@quot.po          f
+po/af.gmo              f
+po/af.po               f
 po/bg.gmo              f
-po/ru.po               f
+po/bg.po               f
+po/ca.gmo              f
+po/ca.po               f
+po/de.gmo              f
+po/de.po               f
+po/eo.gmo              f
+po/eo.po               f
+po/es.gmo              f
+po/es.po               f
+po/et.gmo              f
+po/et.po               f
+po/fr.gmo              f
+po/fr.po               f
+po/hu.gmo              f
+po/hu.po               f
+po/ja.gmo              f
+po/ja.po               f
+po/nl.gmo              f
+po/nl.po               f
+po/pl.gmo              f
+po/pl.po               f
+po/pt_BR.gmo           f
+po/pt_BR.po            f
+po/ro.gmo              f
+po/ro.po               f
 po/ru.gmo              f
-po/sk.po               f
+po/ru.po               f
 po/sk.gmo              f
-po/sv.po               f
+po/sk.po               f
 po/sv.gmo              f
+po/sv.po               f
+po/tr.gmo              f
+po/tr.po               f
+po/vi.gmo              f
+po/vi.po               f
 po/insert-header.sin   f
 po/quot.sed            f
 po/remove-potcdate.sin f
@@ -772,6 +806,7 @@ tests/func.right    f
 tests/func1.sub                f
 tests/func2.sub                f
 tests/func3.sub                f
+tests/func4.sub                f
 tests/getopts.tests    f
 tests/getopts.right    f
 tests/getopts1.sub     f
@@ -813,6 +848,9 @@ tests/jobs2.sub             f
 tests/jobs3.sub                f
 tests/jobs4.sub                f
 tests/jobs.right       f
+tests/mapfile.data     f
+tests/mapfile.right    f
+tests/mapfile.tests    f
 tests/more-exp.tests   f
 tests/more-exp.right   f
 tests/new-exp.tests    f
@@ -906,6 +944,7 @@ tests/run-intl              f
 tests/run-iquote       f
 tests/run-invert       f
 tests/run-jobs         f
+tests/run-mapfile      f
 tests/run-more-exp     f
 tests/run-new-exp      f
 tests/run-nquote       f
index 5688375a5ca66597fa8bf295456960f35ae94a75..e6b0aa3d8304e5fab4a305d87ce8747ad07d9c38 100644 (file)
@@ -411,7 +411,7 @@ CSOURCES = shell.c eval.c parse.y general.c make_cmd.c print_cmd.c y.tab.c \
           dispose_cmd.c execute_cmd.c variables.c $(GLOBC) version.c \
           expr.c copy_cmd.c flags.c subst.c hashcmd.c hashlib.c mailcheck.c \
           test.c trap.c alias.c jobs.c nojobs.c $(ALLOC_FILES) braces.c \
-          input.c bashhist.c array.c arrayfunc.c sig.c pathexp.c \
+          input.c bashhist.c array.c arrayfunc.c assoc.c sig.c pathexp.c \
           unwind_prot.c siglist.c bashline.c bracecomp.c error.c \
           list.c stringlib.c locale.c findcmd.c redir.c \
           pcomplete.c pcomplib.c syntax.c xmalloc.c
@@ -422,7 +422,7 @@ HSOURCES = shell.h flags.h trap.h hashcmd.h hashlib.h jobs.h builtins.h \
           command.h input.h error.h bashansi.h dispose_cmd.h make_cmd.h \
           subst.h externs.h siglist.h bashhist.h bashline.h bashtypes.h \
           array.h arrayfunc.h sig.h mailcheck.h bashintl.h bashjmp.h \
-          execute_cmd.h parser.h pathexp.h pathnames.h pcomplete.h \
+          execute_cmd.h parser.h pathexp.h pathnames.h pcomplete.h assoc.h \
           $(BASHINCFILES)
 
 SOURCES         = $(CSOURCES) $(HSOURCES) $(BUILTIN_DEFS)
@@ -440,7 +440,7 @@ OBJECTS      = shell.o eval.o y.tab.o general.o make_cmd.o print_cmd.o $(GLOBO) \
           dispose_cmd.o execute_cmd.o variables.o copy_cmd.o error.o \
           expr.o flags.o $(JOBS_O) subst.o hashcmd.o hashlib.o mailcheck.o \
           trap.o input.o unwind_prot.o pathexp.o sig.o test.o version.o \
-          alias.o array.o arrayfunc.o braces.o bracecomp.o bashhist.o \
+          alias.o array.o arrayfunc.o assoc.o braces.o bracecomp.o bashhist.o \
           bashline.o $(SIGLIST_O) list.o stringlib.o locale.o findcmd.o redir.o \
           pcomplete.o pcomplib.o syntax.o xmalloc.o $(SIGNAMES_O)
 
@@ -1076,6 +1076,14 @@ arrayfunc.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h
 arrayfunc.o: make_cmd.h subst.h sig.h pathnames.h externs.h 
 arrayfunc.o: $(DEFSRC)/common.h
 arrayfunc.o: ${BASHINCDIR}/shmbutil.h
+assoc.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h
+assoc.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h
+assoc.o: command.h ${BASHINCDIR}/stdc.h error.h
+assoc.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h
+assoc.o: assoc.h hashlib.h
+assoc.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h
+assoc.o: make_cmd.h subst.h sig.h pathnames.h externs.h 
+assoc.o: $(DEFSRC)/common.h
 braces.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h
 braces.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h
 braces.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h
index c20cbd22576ce601b4e404730edafe9dbfecf280..6dc595c9a8b80f1def53cd90ef36287bd525bc5e 100644 (file)
@@ -1,6 +1,6 @@
-# Makefile for bash-3.1, version 2.159
+# Makefile for bash-4.0, version 3.4
 #
-# Copyright (C) 1996-2005 Free Software Foundation, Inc.
+# Copyright (C) 1996-2008 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -411,7 +411,7 @@ CSOURCES = shell.c eval.c parse.y general.c make_cmd.c print_cmd.c y.tab.c \
           dispose_cmd.c execute_cmd.c variables.c $(GLOBC) version.c \
           expr.c copy_cmd.c flags.c subst.c hashcmd.c hashlib.c mailcheck.c \
           test.c trap.c alias.c jobs.c nojobs.c $(ALLOC_FILES) braces.c \
-          input.c bashhist.c array.c arrayfunc.c sig.c pathexp.c \
+          input.c bashhist.c array.c arrayfunc.c assoc.c sig.c pathexp.c \
           unwind_prot.c siglist.c bashline.c bracecomp.c error.c \
           list.c stringlib.c locale.c findcmd.c redir.c \
           pcomplete.c pcomplib.c syntax.c xmalloc.c
@@ -422,7 +422,7 @@ HSOURCES = shell.h flags.h trap.h hashcmd.h hashlib.h jobs.h builtins.h \
           command.h input.h error.h bashansi.h dispose_cmd.h make_cmd.h \
           subst.h externs.h siglist.h bashhist.h bashline.h bashtypes.h \
           array.h arrayfunc.h sig.h mailcheck.h bashintl.h bashjmp.h \
-          execute_cmd.h parser.h pathexp.h pathnames.h pcomplete.h \
+          execute_cmd.h parser.h pathexp.h pathnames.h pcomplete.h assoc.h \
           $(BASHINCFILES)
 
 SOURCES         = $(CSOURCES) $(HSOURCES) $(BUILTIN_DEFS)
@@ -440,7 +440,7 @@ OBJECTS      = shell.o eval.o y.tab.o general.o make_cmd.o print_cmd.o $(GLOBO) \
           dispose_cmd.o execute_cmd.o variables.o copy_cmd.o error.o \
           expr.o flags.o $(JOBS_O) subst.o hashcmd.o hashlib.o mailcheck.o \
           trap.o input.o unwind_prot.o pathexp.o sig.o test.o version.o \
-          alias.o array.o arrayfunc.o braces.o bracecomp.o bashhist.o \
+          alias.o array.o arrayfunc.o assoc.o braces.o bracecomp.o bashhist.o \
           bashline.o $(SIGLIST_O) list.o stringlib.o locale.o findcmd.o redir.o \
           pcomplete.o pcomplib.o syntax.o xmalloc.o $(SIGNAMES_O)
 
@@ -465,7 +465,8 @@ BUILTIN_DEFS = $(DEFSRC)/alias.def $(DEFSRC)/bind.def $(DEFSRC)/break.def \
               $(DEFSRC)/times.def $(DEFSRC)/trap.def $(DEFSRC)/type.def \
               $(DEFSRC)/ulimit.def $(DEFSRC)/umask.def $(DEFSRC)/wait.def \
               $(DEFSRC)/getopts.def $(DEFSRC)/reserved.def \
-              $(DEFSRC)/pushd.def $(DEFSRC)/shopt.def $(DEFSRC)/printf.def
+              $(DEFSRC)/pushd.def $(DEFSRC)/shopt.def $(DEFSRC)/printf.def \
+              $(DEFSRC)/mapfile.def
 BUILTIN_C_SRC  = $(DEFSRC)/mkbuiltins.c $(DEFSRC)/common.c \
                 $(DEFSRC)/evalstring.c $(DEFSRC)/evalfile.c \
                 $(DEFSRC)/bashgetopt.c $(GETOPT_SOURCE)
@@ -484,7 +485,7 @@ BUILTIN_OBJS = $(DEFDIR)/alias.o $(DEFDIR)/bind.o $(DEFDIR)/break.o \
               $(DEFDIR)/source.o $(DEFDIR)/suspend.o $(DEFDIR)/test.o \
               $(DEFDIR)/times.o $(DEFDIR)/trap.o $(DEFDIR)/type.o \
               $(DEFDIR)/ulimit.o $(DEFDIR)/umask.o $(DEFDIR)/wait.o \
-              $(DEFDIR)/getopts.o $(BUILTIN_C_OBJ)
+              $(DEFDIR)/getopts.o $(DEFDIR)/mapfile.o $(BUILTIN_C_OBJ)
 GETOPT_SOURCE   = $(DEFSRC)/getopt.c $(DEFSRC)/getopt.h
 PSIZE_SOURCE   = $(DEFSRC)/psize.sh $(DEFSRC)/psize.c
 
@@ -1383,6 +1384,9 @@ builtins/complete.o: bashtypes.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h
 builtins/complete.o: builtins.h 
 builtins/complete.o: pcomplete.h
 builtins/complete.o: ${DEFSRC}/common.h ${DEFSRC}/bashgetopt.h
+builtins/mapfile.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h
+builtins/mapfile.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h
+builtins/mapfile.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h 
 
 # libintl dependencies
 builtins/bind.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
@@ -1406,6 +1410,7 @@ builtins/inlib.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
 builtins/jobs.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
 builtins/kill.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
 builtins/let.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
+builtins/mapfile.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
 builtins/mkbuiltins.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
 builtins/printf.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
 builtins/pushd.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
@@ -1457,6 +1462,7 @@ builtins/inlib.o: $(DEFSRC)/inlib.def
 builtins/jobs.o: $(DEFSRC)/jobs.def
 builtins/kill.o: $(DEFSRC)/kill.def
 builtins/let.o: $(DEFSRC)/let.def
+builtins/mapfile.o: $(DEFSRC)/mapfile.def
 builtins/pushd.o: $(DEFSRC)/pushd.def
 builtins/read.o: $(DEFSRC)/read.def
 builtins/reserved.o: $(DEFSRC)/reserved.def
diff --git a/array.c b/array.c
index 72d7725883be131aee115bf7c854e832c47e9c74..f045d3430c5435c90d5c9dae69c2f1134d0c5778 100644 (file)
--- a/array.c
+++ b/array.c
@@ -9,7 +9,7 @@
  * chet@ins.cwru.edu
  */
 
-/* Copyright (C) 1997-2004 Free Software Foundation, Inc.
+/* Copyright (C) 1997-2008 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -418,6 +418,41 @@ int        mflags;
        return t;
 }
 
+char *
+array_modcase (a, pat, modop, mflags)
+ARRAY  *a;
+char   *pat;
+int    modop;
+int    mflags;
+{
+       ARRAY           *a2;
+       ARRAY_ELEMENT   *e;
+       char    *t, *sifs;
+
+       if (a == 0 || array_head(a) == 0 || array_empty(a))
+               return ((char *)NULL);
+
+       a2 = array_copy(a);
+       for (e = element_forw(a2->head); e != a2->head; e = element_forw(e)) {
+               t = sh_modcase(element_value(e), pat, modop);
+               FREE(element_value(e));
+               e->value = t;
+       }
+
+       if (mflags & MATCH_QUOTED)
+               array_quote(a2);
+       else
+               array_quote_escapes(a2);
+       if (mflags & MATCH_STARSUB) {
+               sifs = ifs_firstchar((int *)NULL);
+               t = array_to_string (a2, sifs, 0);
+               free(sifs);
+       } else
+               t = array_to_string (a2, " ", 0);
+       array_dispose (a2);
+
+       return t;
+}
 /*
  * Allocate and return a new array element with index INDEX and value
  * VALUE.
index ee7562c5d523318febf1bde70760fad9eb981677..f4201295732d8fc79a85354adf9b63bc7d614fea 100644 (file)
--- a/array.c~
+++ b/array.c~
@@ -9,7 +9,7 @@
  * chet@ins.cwru.edu
  */
 
-/* Copyright (C) 1997-2004 Free Software Foundation, Inc.
+/* Copyright (C) 1997-2008 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -418,6 +418,41 @@ int        mflags;
        return t;
 }
 
+char *
+array_modcase (a, pat, modop, mflags)
+ARRAY  *a;
+char   *pat;
+int    modop;
+int    mflags;
+{
+       ARRAY           *a2;
+       ARRAY_ELEMENT   *e;
+       char    *t, *ifs, sifs[2];
+
+       if (a == 0 || array_head(a) == 0 || array_empty(a))
+               return ((char *)NULL);
+
+       a2 = array_copy(a);
+       for (e = element_forw(a2->head); e != a2->head; e = element_forw(e)) {
+               t = sh_modcase(element_value(e), pat, modop);
+               FREE(element_value(e));
+               e->value = t;
+       }
+
+       if (mflags & MATCH_QUOTED)
+               array_quote(a2);
+       else
+               array_quote_escapes(a2);
+       if (mflags & MATCH_STARSUB) {
+               sifs = ifs_firstchar((int *)NULL);
+               t = array_to_string (a2, sifs, 0);
+               free(sifs);
+       } else
+               t = array_to_string (a2, " ", 0);
+       array_dispose (a2);
+
+       return t;
+}
 /*
  * Allocate and return a new array element with index INDEX and value
  * VALUE.
@@ -693,7 +728,7 @@ int quoted;
                is = inttostr (element_index(ae), indstr, sizeof(indstr));
                valstr = element_value (ae) ? sh_double_quote (element_value(ae))
                                            : (char *)NULL;
-               elen = STRLEN (indstr) + 8 + STRLEN (valstr);
+               elen = STRLEN (is) + 8 + STRLEN (valstr);
                RESIZE_MALLOCED_BUFFER (result, rlen, (elen + 1), rsize, rsize);
 
                result[rlen++] = '[';
diff --git a/array.h b/array.h
index b9632b42e0a9b64b1f4676506022212254db7239..6b928c949d9386f2a4b4cbf0a7865c14c346270b 100644 (file)
--- a/array.h
+++ b/array.h
@@ -1,7 +1,7 @@
 /* array.h -- definitions for the interface exported by array.c that allows
    the rest of the shell to manipulate array variables. */
 
-/* Copyright (C) 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1997-2008 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -59,6 +59,7 @@ extern ARRAY  *array_quote_escapes __P((ARRAY *));
 
 extern char    *array_subrange __P((ARRAY *, arrayind_t, arrayind_t, int, int));
 extern char    *array_patsub __P((ARRAY *, char *, char *, int));
+extern char    *array_modcase __P((ARRAY *, char *, int, int));
 
 /* Basic operations on array elements. */
 extern ARRAY_ELEMENT *array_create_element __P((arrayind_t, char *));
index 8c671b79e6c75f48b16a69fc419a97ef6cbf4c20..687bd3c9bfbf0757d3a9c0b4d7a8541a77bf28d4 100644 (file)
--- a/array.h~
+++ b/array.h~
@@ -55,9 +55,11 @@ extern int   array_rshift __P((ARRAY *, int, char *));
 extern ARRAY_ELEMENT *array_unshift_element __P((ARRAY *));
 extern int     array_shift_element __P((ARRAY *, char *));
 extern ARRAY   *array_quote __P((ARRAY *));
+extern ARRAY   *array_quote_escapes __P((ARRAY *));
 
 extern char    *array_subrange __P((ARRAY *, arrayind_t, arrayind_t, int, int));
 extern char    *array_patsub __P((ARRAY *, char *, char *, int));
+extern char    *array_modcase __P((ARRAY *, char *, int, int));
 
 /* Basic operations on array elements. */
 extern ARRAY_ELEMENT *array_create_element __P((arrayind_t, char *));
index 6c3e15783eccc3bcf7b5fbeaae0f977ad3a2e0a1..17c27327ed0f0d6b00a774ac51e3ffc377eb99e9 100644 (file)
@@ -41,6 +41,7 @@ extern int array_needs_making;
 
 static SHELL_VAR *bind_array_var_internal __P((SHELL_VAR *, arrayind_t, char *, int));
 
+static char *quote_assign __P((const char *));
 static void quote_array_assignment_chars __P((WORD_LIST *));
 static char *array_value_internal __P((char *, int, int, int *));
 
@@ -423,6 +424,34 @@ assign_array_var_from_string (var, value, flags)
   return (var);
 }
 
+static char *
+quote_assign (string)
+     const char *string;
+{
+  size_t slen;
+  int saw_eq;
+  char *temp, *t;
+  const char *s, *send;
+  DECLARE_MBSTATE;
+
+  slen = strlen (string);
+  send = string + slen;
+
+  t = temp = (char *)xmalloc (slen * 2 + 1);
+  saw_eq = 0;
+  for (s = string; *s; )
+    {
+      if (*s == '=')
+       saw_eq = 1;
+      if (saw_eq == 0 && (glob_char_p (s) || isifs (*s)))
+       *t++ = '\\';
+
+      COPY_CHAR_P (t, s, send);
+    }
+  *t = '\0';
+  return temp;
+}
+
 /* For each word in a compound array assignment, if the word looks like
    [ind]=value, quote the `[' and `]' before the `=' to protect them from
    unwanted filename expansion. */
@@ -430,8 +459,7 @@ static void
 quote_array_assignment_chars (list)
      WORD_LIST *list;
 {
-  char *s, *t, *nword;
-  int saw_eq;
+  char *nword;
   WORD_LIST *l;
 
   for (l = list; l; l = l->next)
@@ -441,17 +469,7 @@ quote_array_assignment_chars (list)
       /* Don't bother if it doesn't look like [ind]=value */
       if (l->word->word[0] != '[' || xstrchr (l->word->word, '=') == 0) /* ] */
        continue;
-      s = nword = (char *)xmalloc (strlen (l->word->word) * 2 + 1);
-      saw_eq = 0;
-      for (t = l->word->word; *t; )
-       {
-         if (*t == '=')
-           saw_eq = 1;
-         if (saw_eq == 0 && (*t == '[' || *t == ']'))
-           *s++ = '\\';
-         *s++ = *t++;
-       }
-      *s = '\0';
+      nword = quote_assign (l->word->word);
       free (l->word->word);
       l->word->word = nword;
     }
index 98208bafe773a3f6d438855e6bf477f77c43130f..6c3e15783eccc3bcf7b5fbeaae0f977ad3a2e0a1 100644 (file)
@@ -160,6 +160,16 @@ bind_array_variable (name, ind, value, flags)
   return (bind_array_var_internal (entry, ind, value, flags));
 }
 
+SHELL_VAR *
+bind_array_element (entry, ind, value, flags)
+     SHELL_VAR *entry;
+     arrayind_t ind;
+     char *value;
+     int flags;
+{
+  return (bind_array_var_internal (entry, ind, value, flags));
+}
+                    
 /* Parse NAME, a lhs of an assignment statement of the form v[s], and
    assign VALUE to that array element by calling bind_array_variable(). */
 SHELL_VAR *
diff --git a/assoc.c b/assoc.c
new file mode 100644 (file)
index 0000000..8d01936
--- /dev/null
+++ b/assoc.c
@@ -0,0 +1,378 @@
+/*
+ * assoc.c - functions to manipulate associative arrays
+ *
+ * Associative arrays are standard shell hash tables.
+ *
+ * Chet Ramey
+ * chet@ins.cwru.edu
+ */
+
+/* Copyright (C) 2007 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 (ARRAY_VARS)
+
+#if defined (HAVE_UNISTD_H)
+#  ifdef _MINIX
+#    include <sys/types.h>
+#  endif
+#  include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include "bashansi.h"
+
+#include "shell.h"
+#include "array.h"
+#include "assoc.h"
+#include "builtins/common.h"
+
+static WORD_LIST *assoc_to_word_list_internal __P((HASH_TABLE *, int));
+
+/* assoc_create == hash_create */
+
+void
+assoc_dispose (hash)
+     HASH_TABLE *hash;
+{
+  if (hash)
+    {
+      hash_flush (hash, 0);
+      hash_dispose (hash);
+    }
+}
+
+void
+assoc_flush (hash)
+     HASH_TABLE *hash;
+{
+  hash_flush (hash, 0);
+}
+     
+int
+assoc_insert (hash, key, value)
+     HASH_TABLE *hash;
+     char *key;
+     char *value;
+{
+  BUCKET_CONTENTS *b;
+
+  b = hash_search (key, hash, HASH_CREATE);
+  if (b == 0)
+    return -1;
+  FREE (b->data);
+  b->data = value ? savestring (value) : (char *)0;
+  return (0);
+}
+
+void
+assoc_remove (hash, string)
+     HASH_TABLE *hash;
+     char *string;
+{
+  BUCKET_CONTENTS *b;
+
+  b = hash_remove (string, hash, 0);
+  if (b)
+    {
+      free ((char *)b->data);
+      free (b->key);
+      free (b);
+    }
+}
+
+char *
+assoc_reference (hash, string)
+     HASH_TABLE *hash;
+     char *string;
+{
+  BUCKET_CONTENTS *b;
+
+  if (hash == 0)
+    return (char *)0;
+
+  b = hash_search (string, hash, 0);
+  return (b ? (char *)b->data : 0);
+}
+
+/* Quote the data associated with each element of the hash table ASSOC,
+   using quote_string */
+HASH_TABLE *
+assoc_quote (h)
+     HASH_TABLE *h;
+{
+  int i;
+  BUCKET_CONTENTS *tlist;
+  char *t;
+
+  if (h == 0 || assoc_empty (h))
+    return ((HASH_TABLE *)NULL);
+  
+  for (i = 0; i < h->nbuckets; i++)
+    for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
+      {
+       t = quote_string ((char *)tlist->data);
+       FREE (tlist->data);
+       tlist->data = t;
+      }
+
+  return h;
+}
+
+/* Quote escape characters in the data associated with each element
+   of the hash table ASSOC, using quote_escapes */
+HASH_TABLE *
+assoc_quote_escapes (h)
+     HASH_TABLE *h;
+{
+  int i;
+  BUCKET_CONTENTS *tlist;
+  char *t;
+
+  if (h == 0 || assoc_empty (h))
+    return ((HASH_TABLE *)NULL);
+  
+  for (i = 0; i < h->nbuckets; i++)
+    for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
+      {
+       t = quote_escapes ((char *)tlist->data);
+       FREE (tlist->data);
+       tlist->data = t;
+      }
+
+  return h;
+}
+
+char *
+assoc_patsub (h, pat, rep, mflags)
+     HASH_TABLE *h;
+     char *pat, *rep;
+     int mflags;
+{
+  BUCKET_CONTENTS *tlist;
+  int i;
+  HASH_TABLE *h2;
+  char *t, *sifs;
+
+  if (h == 0 || assoc_empty (h))
+    return ((char *)NULL);
+
+  h2 = assoc_copy (h);
+  for (i = 0; i < h2->nbuckets; i++)
+    for (tlist = hash_items (i, h2); tlist; tlist = tlist->next)
+      {
+       t = pat_subst ((char *)tlist->data, pat, rep, mflags);
+       FREE (tlist->data);
+       tlist->data = t;
+      }
+
+  if (mflags & MATCH_QUOTED)
+    assoc_quote (h2);
+  else
+    assoc_quote_escapes (h2);
+
+  if (mflags & MATCH_STARSUB)
+    {
+      sifs = ifs_firstchar ((int *)NULL);
+      t = assoc_to_string (h2, sifs, 0);
+      free (sifs);
+    }
+  else
+    t = assoc_to_string (h2, " ", 0);
+
+  assoc_dispose (h2);
+
+  return t;
+}
+
+char *
+assoc_modcase (h, pat, modop, mflags)
+     HASH_TABLE *h;
+     char *pat;
+     int modop;
+     int mflags;
+{
+  BUCKET_CONTENTS *tlist;
+  int i;
+  HASH_TABLE *h2;
+  char *t, *sifs;
+
+  if (h == 0 || assoc_empty (h))
+    return ((char *)NULL);
+
+  h2 = assoc_copy (h);
+  for (i = 0; i < h2->nbuckets; i++)
+    for (tlist = hash_items (i, h2); tlist; tlist = tlist->next)
+      {
+       t = sh_modcase ((char *)tlist->data, pat, modop);
+       FREE (tlist->data);
+       tlist->data = t;
+      }
+
+  if (mflags & MATCH_QUOTED)
+    assoc_quote (h2);
+  else
+    assoc_quote_escapes (h2);
+
+  if (mflags & MATCH_STARSUB)
+    {
+      sifs = ifs_firstchar ((int *)NULL);
+      t = assoc_to_string (h2, sifs, 0);
+      free (sifs);
+    }
+  else
+    t = assoc_to_string (h2, " ", 0);
+
+  assoc_dispose (h2);
+
+  return t;
+}
+
+char *
+assoc_to_assign (hash, quoted)
+     HASH_TABLE *hash;
+     int quoted;
+{
+  char *ret;
+  char *istr, *vstr;
+  int i, rsize, rlen, elen;
+  BUCKET_CONTENTS *tlist;
+
+  if (hash == 0 || assoc_empty (hash))
+    return (char *)0;
+
+  ret = xmalloc (rsize = 128);
+  ret[0] = '(';
+  rlen = 1;
+
+  for (i = 0; i < hash->nbuckets; i++)
+    for (tlist = hash_items (i, hash); tlist; tlist = tlist->next)
+      {
+       istr = tlist->key;
+       vstr = tlist->data ? sh_double_quote ((char *)tlist->data) : (char *)0;
+
+       elen = STRLEN (istr) + 8 + STRLEN (vstr);
+       RESIZE_MALLOCED_BUFFER (ret, rlen, (elen+1), rsize, rsize);
+
+       ret[rlen++] = '[';
+       strcpy (ret+rlen, istr);
+       rlen += STRLEN (istr);
+       ret[rlen++] = ']';
+       ret[rlen++] = '=';
+       if (vstr)
+         {
+           strcpy (ret + rlen, vstr);
+           rlen += STRLEN (vstr);
+         }
+       ret[rlen++] = ' ';
+
+       FREE (vstr);
+    }
+
+  RESIZE_MALLOCED_BUFFER (ret, rlen, 1, rsize, 8);
+  ret[rlen++] = ')';
+  ret[rlen] = '\0';
+
+  if (quoted)
+    {
+      vstr = sh_single_quote (ret);
+      free (ret);
+      ret = vstr;
+    }
+
+  return ret;
+}
+
+static WORD_LIST *
+assoc_to_word_list_internal (h, t)
+     HASH_TABLE *h;
+     int t;
+{
+  WORD_LIST *list;
+  int i;
+  BUCKET_CONTENTS *tlist;
+  char *w;
+
+  if (h == 0 || assoc_empty (h))
+    return((WORD_LIST *)NULL);
+  list = (WORD_LIST *)NULL;
+  
+  for (i = 0; i < h->nbuckets; i++)
+    for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
+      {
+       w = (t == 0) ? (char *)tlist->data : (char *)tlist->key;
+       list = make_word_list (make_bare_word(w), list);
+      }
+  return (REVERSE_LIST(list, WORD_LIST *));
+}
+
+WORD_LIST *
+assoc_to_word_list (h)
+     HASH_TABLE *h;
+{
+  return (assoc_to_word_list_internal (h, 0));
+}
+
+WORD_LIST *
+assoc_keys_to_word_list (h)
+     HASH_TABLE *h;
+{
+  return (assoc_to_word_list_internal (h, 1));
+}
+
+char *
+assoc_to_string (h, sep, quoted)
+     HASH_TABLE *h;
+     char *sep;
+     int quoted;
+{
+  BUCKET_CONTENTS *tlist;
+  int i;
+  char *result, *t, *w;
+  WORD_LIST *list, *l;
+
+  if (h == 0)
+    return ((char *)NULL);
+  if (assoc_empty (h))
+    return (savestring (""));
+
+  result = NULL;
+  list = NULL;
+  /* This might be better implemented directly, but it's simple to implement
+     by converting to a word list first, possibly quoting the data, then
+     using list_string */
+  for (i = 0; i < h->nbuckets; i++)
+    for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
+      {
+       w = (char *)tlist->data;
+       if (w == 0)
+         continue;
+       t = quoted ? quote_string (w) : savestring (w);
+       list = make_word_list (make_bare_word(t), list);
+       FREE (t);
+      }
+
+  l = REVERSE_LIST(list, WORD_LIST *);
+
+  result = l ? string_list_internal (l, sep) : savestring ("");
+  return result;
+}
+
+#endif /* ARRAY_VARS */
diff --git a/assoc.c~ b/assoc.c~
new file mode 100644 (file)
index 0000000..b74f04c
--- /dev/null
+++ b/assoc.c~
@@ -0,0 +1,370 @@
+/*
+ * assoc.c - functions to manipulate associative arrays
+ *
+ * Associative arrays are standard shell hash tables.
+ *
+ * Chet Ramey
+ * chet@ins.cwru.edu
+ */
+
+/* Copyright (C) 2007 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 (ARRAY_VARS)
+
+#if defined (HAVE_UNISTD_H)
+#  ifdef _MINIX
+#    include <sys/types.h>
+#  endif
+#  include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include "bashansi.h"
+
+#include "shell.h"
+#include "array.h"
+#include "assoc.h"
+#include "builtins/common.h"
+
+static WORD_LIST *assoc_to_word_list_internal __P((HASH_TABLE *, int));
+
+/* assoc_create == hash_create */
+
+void
+assoc_dispose (hash)
+     HASH_TABLE *hash;
+{
+  if (hash)
+    {
+      hash_flush (hash, 0);
+      hash_dispose (hash);
+    }
+}
+
+void
+assoc_flush (hash)
+     HASH_TABLE *hash;
+{
+  hash_flush (hash, 0);
+}
+     
+int
+assoc_insert (hash, key, value)
+     HASH_TABLE *hash;
+     char *key;
+     char *value;
+{
+  BUCKET_CONTENTS *b;
+
+  b = hash_search (key, hash, HASH_CREATE);
+  if (b == 0)
+    return -1;
+  FREE (b->data);
+  b->data = value ? savestring (value) : (char *)0;
+  return (0);
+}
+
+void
+assoc_remove (hash, string)
+     HASH_TABLE *hash;
+     char *string;
+{
+  BUCKET_CONTENTS *b;
+
+  b = hash_remove (string, hash, 0);
+  if (b)
+    {
+      free ((char *)b->data);
+      free (b->key);
+      free (b);
+    }
+}
+
+char *
+assoc_reference (hash, string)
+     HASH_TABLE *hash;
+     char *string;
+{
+  BUCKET_CONTENTS *b;
+
+  if (hash == 0)
+    return (char *)0;
+
+  b = hash_search (string, hash, 0);
+  return (b ? (char *)b->data : 0);
+}
+
+/* Quote the data associated with each element of the hash table ASSOC,
+   using quote_string */
+HASH_TABLE *
+assoc_quote (h)
+     HASH_TABLE *h;
+{
+  int i;
+  BUCKET_CONTENTS *tlist;
+  char *t;
+
+  if (h == 0 || assoc_empty (h))
+    return ((HASH_TABLE *)NULL);
+  
+  for (i = 0; i < h->nbuckets; i++)
+    for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
+      {
+       t = quote_string ((char *)tlist->data);
+       FREE (tlist->data);
+       tlist->data = t;
+      }
+
+  return h;
+}
+
+/* Quote escape characters in the data associated with each element
+   of the hash table ASSOC, using quote_escapes */
+HASH_TABLE *
+assoc_quote_escapes (h)
+     HASH_TABLE *h;
+{
+  int i;
+  BUCKET_CONTENTS *tlist;
+  char *t;
+
+  if (h == 0 || assoc_empty (h))
+    return ((HASH_TABLE *)NULL);
+  
+  for (i = 0; i < h->nbuckets; i++)
+    for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
+      {
+       t = quote_escapes ((char *)tlist->data);
+       FREE (tlist->data);
+       tlist->data = t;
+      }
+
+  return h;
+}
+
+char *
+assoc_patsub (h, pat, rep, mflags)
+     HASH_TABLE *h;
+     char *pat, *rep;
+     int mflags;
+{
+  BUCKET_CONTENTS *tlist;
+  int i;
+  HASH_TABLE *h2;
+  char *t, *ifs, sifs[2];
+
+  if (h == 0 || assoc_empty (h))
+    return ((char *)NULL);
+
+  h2 = assoc_copy (h);
+  for (i = 0; i < h2->nbuckets; i++)
+    for (tlist = hash_items (i, h2); tlist; tlist = tlist->next)
+      {
+       t = pat_subst ((char *)tlist->data, pat, rep, mflags);
+       FREE (tlist->data);
+       tlist->data = t;
+      }
+
+  if (mflags & MATCH_STARSUB)
+    {
+      ifs = getifs();
+      sifs[0] = ifs ? *ifs : '\0';
+      sifs[1] = '\0';
+      t = assoc_to_string (h2, sifs, (mflags & MATCH_QUOTED));
+    }
+  else
+    t = assoc_to_string (h2, " ", (mflags & MATCH_QUOTED));
+
+  assoc_dispose (h2);
+
+  return t;
+}
+
+char *
+assoc_modcase (h, pat, modop, mflags)
+     HASH_TABLE *h;
+     char *pat;
+     int modop;
+     int mflags;
+{
+  BUCKET_CONTENTS *tlist;
+  int i;
+  HASH_TABLE *h2;
+  char *t, *ifs, sifs[2];
+
+  if (h == 0 || assoc_empty (h))
+    return ((char *)NULL);
+
+  h2 = assoc_copy (h);
+  for (i = 0; i < h2->nbuckets; i++)
+    for (tlist = hash_items (i, h2); tlist; tlist = tlist->next)
+      {
+       t = sh_modcase ((char *)tlist->data, pat, modop);
+       FREE (tlist->data);
+       tlist->data = t;
+      }
+
+  if (mflags & MATCH_STARSUB)
+    {
+      ifs = getifs();
+      sifs[0] = ifs ? *ifs : '\0';
+      sifs[1] = '\0';
+      t = assoc_to_string (h2, sifs, (mflags & MATCH_QUOTED));
+    }
+  else
+    t = assoc_to_string (h2, " ", (mflags & MATCH_QUOTED));
+
+  assoc_dispose (h2);
+
+  return t;
+}
+
+char *
+assoc_to_assign (hash, quoted)
+     HASH_TABLE *hash;
+     int quoted;
+{
+  char *ret;
+  char *istr, *vstr;
+  int i, rsize, rlen, elen;
+  BUCKET_CONTENTS *tlist;
+
+  if (hash == 0 || assoc_empty (hash))
+    return (char *)0;
+
+  ret = xmalloc (rsize = 128);
+  ret[0] = '(';
+  rlen = 1;
+
+  for (i = 0; i < hash->nbuckets; i++)
+    for (tlist = hash_items (i, hash); tlist; tlist = tlist->next)
+      {
+       istr = tlist->key;
+       vstr = tlist->data ? sh_double_quote ((char *)tlist->data) : (char *)0;
+
+       elen = STRLEN (istr) + 8 + STRLEN (vstr);
+       RESIZE_MALLOCED_BUFFER (ret, rlen, (elen+1), rsize, rsize);
+
+       ret[rlen++] = '[';
+       strcpy (ret+rlen, istr);
+       rlen += STRLEN (istr);
+       ret[rlen++] = ']';
+       ret[rlen++] = '=';
+       if (vstr)
+         {
+           strcpy (ret + rlen, vstr);
+           rlen += STRLEN (vstr);
+         }
+       ret[rlen++] = ' ';
+
+       FREE (vstr);
+    }
+
+  RESIZE_MALLOCED_BUFFER (ret, rlen, 1, rsize, 8);
+  ret[rlen++] = ')';
+  ret[rlen] = '\0';
+
+  if (quoted)
+    {
+      vstr = sh_single_quote (ret);
+      free (ret);
+      ret = vstr;
+    }
+
+  return ret;
+}
+
+static WORD_LIST *
+assoc_to_word_list_internal (h, t)
+     HASH_TABLE *h;
+     int t;
+{
+  WORD_LIST *list;
+  int i;
+  BUCKET_CONTENTS *tlist;
+  char *w;
+
+  if (h == 0 || assoc_empty (h))
+    return((WORD_LIST *)NULL);
+  list = (WORD_LIST *)NULL;
+  
+  for (i = 0; i < h->nbuckets; i++)
+    for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
+      {
+       w = (t == 0) ? (char *)tlist->data : (char *)tlist->key;
+       list = make_word_list (make_bare_word(w), list);
+      }
+  return (REVERSE_LIST(list, WORD_LIST *));
+}
+
+WORD_LIST *
+assoc_to_word_list (h)
+     HASH_TABLE *h;
+{
+  return (assoc_to_word_list_internal (h, 0));
+}
+
+WORD_LIST *
+assoc_keys_to_word_list (h)
+     HASH_TABLE *h;
+{
+  return (assoc_to_word_list_internal (h, 1));
+}
+
+char *
+assoc_to_string (h, sep, quoted)
+     HASH_TABLE *h;
+     char *sep;
+     int quoted;
+{
+  BUCKET_CONTENTS *tlist;
+  int i;
+  char *result, *t, *w;
+  WORD_LIST *list, *l;
+
+  if (h == 0)
+    return ((char *)NULL);
+  if (assoc_empty (h))
+    return (savestring (""));
+
+  result = NULL;
+  list = NULL;
+  /* This might be better implemented directly, but it's simple to implement
+     by converting to a word list first, possibly quoting the data, then
+     using list_string */
+  for (i = 0; i < h->nbuckets; i++)
+    for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
+      {
+       w = (char *)tlist->data;
+       if (w == 0)
+         continue;
+       t = quoted ? quote_string (w) : savestring (w);
+       list = make_word_list (make_bare_word(t), list);
+       FREE (t);
+      }
+
+  l = REVERSE_LIST(list, WORD_LIST *);
+
+  result = l ? string_list_internal (l, sep) : savestring ("");
+  return result;
+}
+
+#endif /* ARRAY_VARS */
diff --git a/assoc.h b/assoc.h
new file mode 100644 (file)
index 0000000..f6a480a
--- /dev/null
+++ b/assoc.h
@@ -0,0 +1,57 @@
+/* assoc.h -- definitions for the interface exported by assoc.c that allows
+   the rest of the shell to manipulate associative array variables. */
+
+/* Copyright (C) 2008 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. */
+
+#ifndef _ASSOC_H_
+#define _ASSOC_H_
+
+#include "stdc.h"
+#include "hashlib.h"
+
+#define assoc_empty(h)         ((h)->nentries == 0)
+#define assoc_num_elements(h)  ((h)->nentries)
+
+#define assoc_create(n)                (hash_create((n)))
+
+#define assoc_copy(h)          (hash_copy((h), 0))
+
+#define assoc_walk(h, f)       (hash_walk((h), (f))
+
+extern void assoc_dispose __P((HASH_TABLE *));
+extern void assoc_flush __P((HASH_TABLE *));
+
+extern int assoc_insert __P((HASH_TABLE *, char *, char *));
+extern void assoc_remove __P((HASH_TABLE *, char *));
+
+extern char *assoc_reference __P((HASH_TABLE *, char *));
+
+extern char *assoc_patsub __P((HASH_TABLE *, char *, char *, int));
+extern char *assoc_modcase __P((HASH_TABLE *, char *, int, int));
+
+extern HASH_TABLE *assoc_quote __P((HASH_TABLE *));
+extern HASH_TABLE *assoc_quote_escapes __P((HASH_TABLE *));
+
+extern char *assoc_to_assign __P((HASH_TABLE *, int));
+
+extern WORD_LIST *assoc_to_word_list __P((HASH_TABLE *));
+extern WORD_LIST *assoc_keys_to_word_list __P((HASH_TABLE *));
+
+extern char *assoc_to_string __P((HASH_TABLE *, char *, int));
+#endif /* _ASSOC_H_ */
diff --git a/assoc.h~ b/assoc.h~
new file mode 100644 (file)
index 0000000..82ac45d
--- /dev/null
+++ b/assoc.h~
@@ -0,0 +1,54 @@
+/* assoc.h -- definitions for the interface exported by assoc.c that allows
+   the rest of the shell to manipulate associative array variables. */
+
+/* Copyright (C) 2008 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. */
+
+#ifndef _ASSOC_H_
+#define _ASSOC_H_
+
+#include "stdc.h"
+#include "hashlib.h"
+
+#define assoc_empty(h)         ((h)->nentries == 0)
+#define assoc_num_elements(h)  ((h)->nentries)
+
+#define assoc_create(n)                (hash_create((n)))
+
+#define assoc_copy(h)          (hash_copy((h), 0))
+
+extern void assoc_dispose __P((HASH_TABLE *));
+extern void assoc_flush __P((HASH_TABLE *));
+
+extern int assoc_insert __P((HASH_TABLE *, char *, char *));
+extern void assoc_remove __P((HASH_TABLE *, char *));
+
+extern char *assoc_reference __P((HASH_TABLE *, char *));
+
+extern char *assoc_patsub __P((HASH_TABLE *, char *, char *, int));
+extern char *assoc_modcase __P((HASH_TABLE *, char *, int, int));
+
+extern HASH_TABLE *assoc_quote __P((HASH_TABLE *));
+
+extern char *assoc_to_assign __P((HASH_TABLE *, int));
+
+extern WORD_LIST *assoc_to_word_list __P((HASH_TABLE *));
+extern WORD_LIST *assoc_keys_to_word_list __P((HASH_TABLE *));
+
+extern char *assoc_to_string __P((HASH_TABLE *, char *, int));
+#endif /* _ASSOC_H_ */
index 92e1313aab45a7e50df635ade9a1885e50cc5015..72cc5e6cace9598811a1862110f6df8845b7df07 100644 (file)
 
 
 
+
 
 
 for ac_func in dup2 eaccess fcntl getdtablesize getgroups gethostname \
                getpagesize getpeername getrlimit getrusage gettimeofday \
                kill killpg lstat readlink sbrk select setdtablesize \
-               tcgetpgrp uname ulimit waitpid
+               setitimer tcgetpgrp uname ulimit waitpid
 do
 as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
 { echo "$as_me:$LINENO: checking for $ac_func" >&5
index 4e90b52bae67d69c584102604f0863adf3c01c91..b0d19f21fd3b7a2bcaeb6838ec1e5534f9721e35 100644 (file)
                         'configure.in'
                       ],
                       {
-                        'AM_PROG_F77_C_O' => 1,
                         '_LT_AC_TAGCONFIG' => 1,
+                        'AM_PROG_F77_C_O' => 1,
                         'm4_pattern_forbid' => 1,
                         'AC_CANONICAL_TARGET' => 1,
                         'AC_CONFIG_LIBOBJ_DIR' => 1,
-                        'AC_C_VOLATILE' => 1,
                         'AC_TYPE_OFF_T' => 1,
+                        'AC_C_VOLATILE' => 1,
                         'AC_FUNC_CLOSEDIR_VOID' => 1,
                         'AC_REPLACE_FNMATCH' => 1,
                         'AC_PROG_LIBTOOL' => 1,
                         'AC_FUNC_STAT' => 1,
-                        'AC_FUNC_WAIT3' => 1,
                         'AC_HEADER_TIME' => 1,
-                        'AC_FUNC_LSTAT' => 1,
+                        'AC_FUNC_WAIT3' => 1,
                         'AC_STRUCT_TM' => 1,
+                        'AC_FUNC_LSTAT' => 1,
                         'AM_AUTOMAKE_VERSION' => 1,
-                        'AC_FUNC_GETMNTENT' => 1,
                         'AC_TYPE_MODE_T' => 1,
-                        'AC_CHECK_HEADERS' => 1,
+                        'AC_FUNC_GETMNTENT' => 1,
                         'AC_FUNC_STRTOD' => 1,
+                        'AC_CHECK_HEADERS' => 1,
                         'LT_CONFIG_LTDL_DIR' => 1,
                         'AC_FUNC_STRNLEN' => 1,
                         'm4_sinclude' => 1,
                         'AC_FUNC_MBRTOWC' => 1,
                         'AC_STRUCT_ST_BLOCKS' => 1,
                         'AC_TYPE_SIGNAL' => 1,
-                        'AC_CANONICAL_BUILD' => 1,
                         'AM_PROG_FC_C_O' => 1,
+                        'AC_CANONICAL_BUILD' => 1,
                         'AC_TYPE_UID_T' => 1,
                         'AC_PROG_MAKE_SET' => 1,
-                        'AC_CONFIG_AUX_DIR' => 1,
                         '_AM_SUBST_NOTMAKE' => 1,
-                        'm4_pattern_allow' => 1,
-                        'sinclude' => 1,
-                        'AC_DEFINE_TRACE_LITERAL' => 1,
-                        'AC_FUNC_STRERROR_R' => 1,
-                        'AC_PROG_CC' => 1,
-                        'AC_DECL_SYS_SIGLIST' => 1,
-                        'AC_FUNC_FORK' => 1,
-                        'AC_FUNC_STRCOLL' => 1,
-                        'AC_FUNC_VPRINTF' => 1,
-                        'AC_PROG_YACC' => 1,
-                        'AC_SUBST_TRACE' => 1,
-                        'AC_INIT' => 1,
-                        'AC_STRUCT_TIMEZONE' => 1,
-                        'AC_FUNC_CHOWN' => 1,
-                        'AC_SUBST' => 1,
-                        'AC_FUNC_ALLOCA' => 1,
-                        'AC_FC_SRCEXT' => 1,
-                        'AC_CANONICAL_HOST' => 1,
-                        'AC_FUNC_GETPGRP' => 1,
-                        'AC_PROG_RANLIB' => 1,
-                        'AM_INIT_AUTOMAKE' => 1,
-                        'AC_FUNC_SETPGRP' => 1,
-                        'AC_CONFIG_SUBDIRS' => 1,
-                        'AC_FUNC_MMAP' => 1,
-                        'AC_FUNC_REALLOC' => 1,
-                        'AC_TYPE_SIZE_T' => 1,
-                        'AC_CHECK_TYPES' => 1,
-                        'AC_CONFIG_LINKS' => 1,
-                        'AC_REQUIRE_AUX_FILE' => 1,
-                        'LT_SUPPORTED_TAG' => 1,
-                        'AC_CHECK_MEMBERS' => 1,
-                        'AM_MAINTAINER_MODE' => 1,
-                        'AC_FUNC_UTIME_NULL' => 1,
-                        'AC_FUNC_SELECT_ARGTYPES' => 1,
-                        'AC_HEADER_STAT' => 1,
-                        'AC_FUNC_STRFTIME' => 1,
-                        'AC_PROG_CPP' => 1,
-                        'AC_C_INLINE' => 1,
-                        'AC_PROG_LEX' => 1,
-                        'AC_C_CONST' => 1,
-                        'AC_TYPE_PID_T' => 1,
-                        'AC_CONFIG_FILES' => 1,
-                        'include' => 1,
-                        'AC_FUNC_SETVBUF_REVERSED' => 1,
-                        'AC_PROG_INSTALL' => 1,
-                        'AM_GNU_GETTEXT' => 1,
-                        'AC_CHECK_LIB' => 1,
-                        'AC_FUNC_OBSTACK' => 1,
-                        'AC_FUNC_MALLOC' => 1,
-                        'AC_FUNC_GETGROUPS' => 1,
-                        'AC_FUNC_GETLOADAVG' => 1,
-                        'AC_FC_FREEFORM' => 1,
-                        'AH_OUTPUT' => 1,
-                        'AC_FUNC_FSEEKO' => 1,
-                        'AM_PROG_CC_C_O' => 1,
-                        'AC_FUNC_MKTIME' => 1,
-                        'AC_CANONICAL_SYSTEM' => 1,
-                        'AM_CONDITIONAL' => 1,
-                        'AC_CONFIG_HEADERS' => 1,
-                        'AC_HEADER_SYS_WAIT' => 1,
-                        'AC_PROG_LN_S' => 1,
-                        'AC_FUNC_MEMCMP' => 1,
-                        'm4_include' => 1,
-                        'AC_HEADER_DIRENT' => 1,
-                        'AC_CHECK_FUNCS' => 1
-                      }
-                    ], 'Autom4te::Request' ),
-             bless( [
-                      '1',
-                      1,
-                      [
-                        '/usr/local/share/autoconf'
-                      ],
-                      [
-                        '/usr/local/share/autoconf/autoconf/autoconf.m4f',
-                        'aclocal.m4',
-                        'configure.in'
-                      ],
-                      {
-                        'm4_pattern_forbid' => 1,
-                        'AC_CONFIG_LIBOBJ_DIR' => 1,
-                        'AC_C_VOLATILE' => 1,
-                        'AC_TYPE_OFF_T' => 1,
-                        'AC_FUNC_CLOSEDIR_VOID' => 1,
-                        'AC_REPLACE_FNMATCH' => 1,
-                        'AC_PROG_LIBTOOL' => 1,
-                        'AC_FUNC_STAT' => 1,
-                        'AC_FUNC_WAIT3' => 1,
-                        'AC_HEADER_TIME' => 1,
-                        'AC_FUNC_LSTAT' => 1,
-                        'AC_STRUCT_TM' => 1,
-                        'AM_AUTOMAKE_VERSION' => 1,
-                        'AC_FUNC_GETMNTENT' => 1,
-                        'AC_TYPE_MODE_T' => 1,
-                        'AC_FUNC_STRTOD' => 1,
-                        'AC_CHECK_HEADERS' => 1,
-                        'AC_FUNC_STRNLEN' => 1,
-                        'm4_sinclude' => 1,
-                        'AC_PROG_CXX' => 1,
-                        'AC_PATH_X' => 1,
-                        'AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK' => 1,
-                        'AC_PROG_AWK' => 1,
-                        '_m4_warn' => 1,
-                        'AC_HEADER_STDC' => 1,
-                        'AC_HEADER_MAJOR' => 1,
-                        'AC_FUNC_ERROR_AT_LINE' => 1,
-                        'AC_PROG_GCC_TRADITIONAL' => 1,
-                        'AC_LIBSOURCE' => 1,
-                        'AC_FUNC_MBRTOWC' => 1,
-                        'AC_STRUCT_ST_BLOCKS' => 1,
-                        'AC_TYPE_SIGNAL' => 1,
-                        'AC_TYPE_UID_T' => 1,
-                        'AC_PROG_MAKE_SET' => 1,
                         'AC_CONFIG_AUX_DIR' => 1,
-                        'm4_pattern_allow' => 1,
                         'sinclude' => 1,
+                        'm4_pattern_allow' => 1,
                         'AC_DEFINE_TRACE_LITERAL' => 1,
                         'AC_FUNC_STRERROR_R' => 1,
                         'AC_PROG_CC' => 1,
                         'AC_FUNC_FORK' => 1,
                         'AC_DECL_SYS_SIGLIST' => 1,
-                        'AC_FUNC_STRCOLL' => 1,
                         'AC_FUNC_VPRINTF' => 1,
+                        'AC_FUNC_STRCOLL' => 1,
                         'AC_PROG_YACC' => 1,
-                        'AC_INIT' => 1,
+                        'AC_SUBST_TRACE' => 1,
                         'AC_STRUCT_TIMEZONE' => 1,
+                        'AC_INIT' => 1,
                         'AC_FUNC_CHOWN' => 1,
                         'AC_SUBST' => 1,
                         'AC_FUNC_ALLOCA' => 1,
                         'AC_CANONICAL_HOST' => 1,
+                        'AC_FC_SRCEXT' => 1,
                         'AC_FUNC_GETPGRP' => 1,
                         'AC_PROG_RANLIB' => 1,
-                        'AM_INIT_AUTOMAKE' => 1,
                         'AC_FUNC_SETPGRP' => 1,
+                        'AM_INIT_AUTOMAKE' => 1,
                         'AC_CONFIG_SUBDIRS' => 1,
                         'AC_FUNC_MMAP' => 1,
                         'AC_FUNC_REALLOC' => 1,
                         'AC_TYPE_SIZE_T' => 1,
                         'AC_CONFIG_LINKS' => 1,
+                        'AC_REQUIRE_AUX_FILE' => 1,
                         'AC_CHECK_TYPES' => 1,
+                        'LT_SUPPORTED_TAG' => 1,
                         'AC_CHECK_MEMBERS' => 1,
                         'AM_MAINTAINER_MODE' => 1,
                         'AC_FUNC_UTIME_NULL' => 1,
                         'AC_FUNC_SELECT_ARGTYPES' => 1,
+                        'AM_GNU_GETTEXT_INTL_SUBDIR' => 1,
                         'AC_HEADER_STAT' => 1,
                         'AC_FUNC_STRFTIME' => 1,
                         'AC_PROG_CPP' => 1,
                         'AC_C_INLINE' => 1,
                         'AC_TYPE_PID_T' => 1,
                         'AC_PROG_LEX' => 1,
+                        'AM_ENABLE_MULTILIB' => 1,
                         'AC_C_CONST' => 1,
                         'AC_CONFIG_FILES' => 1,
                         'include' => 1,
                         'AC_FUNC_SETVBUF_REVERSED' => 1,
                         'AC_PROG_INSTALL' => 1,
                         'AM_GNU_GETTEXT' => 1,
-                        'AC_CHECK_LIB' => 1,
                         'AC_FUNC_OBSTACK' => 1,
+                        'AC_CHECK_LIB' => 1,
                         'AC_FUNC_MALLOC' => 1,
                         'AC_FUNC_GETGROUPS' => 1,
+                        'AC_FC_FREEFORM' => 1,
                         'AC_FUNC_GETLOADAVG' => 1,
                         'AH_OUTPUT' => 1,
                         'AC_FUNC_FSEEKO' => 1,
                         'AM_PROG_CC_C_O' => 1,
                         'AC_FUNC_MKTIME' => 1,
-                        'AC_CANONICAL_SYSTEM' => 1,
                         'AM_CONDITIONAL' => 1,
+                        'AC_CANONICAL_SYSTEM' => 1,
                         'AC_CONFIG_HEADERS' => 1,
                         'AC_HEADER_SYS_WAIT' => 1,
                         'AC_PROG_LN_S' => 1,
index c793fe50ea20b4a0ead9c8f1c284914fdf27d080..4e634da886908a729eae04e5ba4cd145b2bfe2b6 100644 (file)
@@ -1264,7 +1264,7 @@ m4trace:configure.in:695: -2- m4_pattern_allow([^MKFIFO_MISSING$])
 m4trace:configure.in:701: -1- AC_CHECK_FUNCS([dup2 eaccess fcntl getdtablesize getgroups gethostname \
                getpagesize getpeername getrlimit getrusage gettimeofday \
                kill killpg lstat readlink sbrk select setdtablesize \
-               tcgetpgrp uname ulimit waitpid])
+               setitimer tcgetpgrp uname ulimit waitpid])
 m4trace:configure.in:701: -1- AH_OUTPUT([HAVE_DUP2], [/* Define to 1 if you have the `dup2\' function. */
 #undef HAVE_DUP2])
 m4trace:configure.in:701: -1- AH_OUTPUT([HAVE_EACCESS], [/* Define to 1 if you have the `eaccess\' function. */
@@ -1301,6 +1301,8 @@ m4trace:configure.in:701: -1- AH_OUTPUT([HAVE_SELECT], [/* Define to 1 if you ha
 #undef HAVE_SELECT])
 m4trace:configure.in:701: -1- AH_OUTPUT([HAVE_SETDTABLESIZE], [/* Define to 1 if you have the `setdtablesize\' function. */
 #undef HAVE_SETDTABLESIZE])
+m4trace:configure.in:701: -1- AH_OUTPUT([HAVE_SETITIMER], [/* Define to 1 if you have the `setitimer\' function. */
+#undef HAVE_SETITIMER])
 m4trace:configure.in:701: -1- AH_OUTPUT([HAVE_TCGETPGRP], [/* Define to 1 if you have the `tcgetpgrp\' function. */
 #undef HAVE_TCGETPGRP])
 m4trace:configure.in:701: -1- AH_OUTPUT([HAVE_UNAME], [/* Define to 1 if you have the `uname\' function. */
index 9c0ec21c6be3c5b1565abc7a372ecc4bdd2d0789..9e529cc2fe2a4f2977131f2ddb1d235cd2cb7299 100644 (file)
@@ -73,6 +73,8 @@
 #  define VI_EDITING_MODE       0
 #endif
 
+#define RL_BOOLEAN_VARIABLE_VALUE(s)   ((s)[0] == 'o' && (s)[1] == 'n' && (s)[2] == '\0')
+
 #if defined (BRACE_COMPLETION)
 extern int bash_brace_completion __P((int, int));
 #endif /* BRACE_COMPLETION */
@@ -222,6 +224,9 @@ int no_empty_command_completion;
    are the only possible matches, even if FIGNORE says to. */
 int force_fignore = 1;
 
+/* Perform spelling correction on directory names during word completion */
+int dircomplete_spelling = 0;
+
 static char *bash_completer_word_break_characters = " \t\n\"'@><=;|&(:";
 static char *bash_nohostname_word_break_characters = " \t\n\"'><=;|&(:";
 /* )) */
@@ -814,8 +819,8 @@ edit_and_execute_command (count, c, editing_mode, edit_command)
      int count, c, editing_mode;
      char *edit_command;
 {
-  char *command;
-  int r, cclc, rrs;
+  char *command, *metaval;
+  int r, cclc, rrs, metaflag;
 
   rrs = rl_readline_state;
   cclc = current_command_line_count;
@@ -842,10 +847,17 @@ edit_and_execute_command (count, c, editing_mode, edit_command)
       command = savestring (edit_command);
     }
 
+  metaval = rl_variable_value ("input-meta");
+  metaflag = RL_BOOLEAN_VARIABLE_VALUE (metaval);
+  
   /* Now, POSIX.1-2001 and SUSv3 say that the commands executed from the
      temporary file should be placed into the history.  We don't do that
      yet. */
+  if (rl_deprep_term_function)
+    (*rl_deprep_term_function) ();
   r = parse_and_execute (command, (editing_mode == VI_EDITING_MODE) ? "v" : "C-xC-e", SEVAL_NOHIST);
+  if (rl_prep_term_function)
+    (*rl_prep_term_function) (metaflag);
 
   current_command_line_count = cclc;
 
@@ -1260,7 +1272,7 @@ command_word_completion_function (hint_text, state)
       val = (char *)NULL;
 
       temp = rl_variable_value ("completion-ignore-case");
-      igncase = strcmp (temp, "on") == 0;
+      igncase = RL_BOOLEAN_VARIABLE_VALUE (temp);
 
       if (glob_matches)
        {
@@ -2481,6 +2493,19 @@ bash_directory_completion_hook (dirname)
       temp1 = make_absolute (local_dirname, t);
       free (t);
       temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
+
+      /* Try spelling correction if initial canonicalization fails. */
+      if (temp2 == 0 && dircomplete_spelling)
+       {
+         temp2 = dirspell (temp1);
+         if (temp2)
+           {
+             free (temp1);
+             temp1 = temp2;
+             temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
+             return_value = temp2 != 0;
+           }
+       }
       /* If we can't canonicalize, bail. */
       if (temp2 == 0)
        {
index 6ae7f622cbe3df2e2a51c2bd94286157ff3c4c8d..84f5f3df3eb1965a054c41626c2530ce84639817 100644 (file)
@@ -73,6 +73,8 @@
 #  define VI_EDITING_MODE       0
 #endif
 
+#define RL_BOOLEAN_VARIABLE_VALUE(s)   ((s)[0] == 'o' && (s)[1] == 'n' && (s)[2] == '\0')
+
 #if defined (BRACE_COMPLETION)
 extern int bash_brace_completion __P((int, int));
 #endif /* BRACE_COMPLETION */
@@ -222,6 +224,9 @@ int no_empty_command_completion;
    are the only possible matches, even if FIGNORE says to. */
 int force_fignore = 1;
 
+/* Perform spelling correction on directory names during word completion */
+int dircomplete_spelling = 1;
+
 static char *bash_completer_word_break_characters = " \t\n\"'@><=;|&(:";
 static char *bash_nohostname_word_break_characters = " \t\n\"'><=;|&(:";
 /* )) */
@@ -814,8 +819,8 @@ edit_and_execute_command (count, c, editing_mode, edit_command)
      int count, c, editing_mode;
      char *edit_command;
 {
-  char *command;
-  int r, cclc, rrs;
+  char *command, *metaval;
+  int r, cclc, rrs, metaflag;
 
   rrs = rl_readline_state;
   cclc = current_command_line_count;
@@ -842,10 +847,17 @@ edit_and_execute_command (count, c, editing_mode, edit_command)
       command = savestring (edit_command);
     }
 
+  metaval = rl_variable_value ("input-meta");
+  metaflag = RL_BOOLEAN_VARIABLE_VALUE (metaval);
+  
   /* Now, POSIX.1-2001 and SUSv3 say that the commands executed from the
      temporary file should be placed into the history.  We don't do that
      yet. */
+  if (rl_deprep_term_function)
+    (*rl_deprep_term_function) ();
   r = parse_and_execute (command, (editing_mode == VI_EDITING_MODE) ? "v" : "C-xC-e", SEVAL_NOHIST);
+  if (rl_prep_term_function)
+    (*rl_prep_term_function) (metaflag);
 
   current_command_line_count = cclc;
 
@@ -1260,7 +1272,7 @@ command_word_completion_function (hint_text, state)
       val = (char *)NULL;
 
       temp = rl_variable_value ("completion-ignore-case");
-      igncase = strcmp (temp, "on") == 0;
+      igncase = RL_BOOLEAN_VARIABLE_VALUE (temp);
 
       if (glob_matches)
        {
@@ -1546,43 +1558,7 @@ globword:
          /* If we performed tilde expansion, restore the original
             filename. */
          if (*hint_text == '~')
-           {
-             int l, vl, dl2, xl;
-             char *dh2, *expdir;
-
-             vl = strlen (val);
-
-#if 0
-             /* XXX -- don't need this or RD or DL */
-             rd = savestring (filename_hint);
-             bash_directory_expansion (&rd);
-             dl = strlen (rd);
-             free (rd);
-#endif
-
-             dh2 = directory_part ? bash_dequote_filename (directory_part, 0) : 0;
-             bash_directory_expansion (&dh2);
-             dl2 = strlen (dh2);
-
-             expdir = bash_tilde_expand (directory_part, 0);
-             xl = strlen (expdir);
-             free (expdir);
-
-             /*
-                dh2 = unexpanded but dequoted tilde-prefix
-                dl2 = length of tilde-prefix
-                expdir = tilde-expanded tilde-prefix
-                xl = length of expanded tilde-prefix
-                l = length of remainder after tilde-prefix
-             */
-             l = (vl - xl) + 1;
-
-             temp = (char *)xmalloc (dl2 + 2 + l);
-             strcpy (temp, dh2);
-             strcpy (temp + dl2, val + xl);
-
-             free (dh2);
-           }
+           temp = restore_tilde (val, directory_part);
          else
            temp = savestring (val);
          freetemp = 1;
@@ -2517,6 +2493,19 @@ bash_directory_completion_hook (dirname)
       temp1 = make_absolute (local_dirname, t);
       free (t);
       temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
+
+      /* Try spelling correction if initial canonicalization fails. */
+      if (temp2 == 0 && dircomplete_spelling)
+       {
+         temp2 = dirspell (temp1);
+         if (temp2)
+           {
+             free (temp1);
+             temp1 = temp2;
+             temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
+             return_value = temp2 != 0;
+           }
+       }
       /* If we can't canonicalize, bail. */
       if (temp2 == 0)
        {
index 26c9dd64280426f243d801d6f15bdb929d169938..32cd57acb5ef3dc4a80036923489406bab353291 100644 (file)
@@ -325,7 +325,17 @@ fc_builtin (list)
   /* "When not listing, the fc command that caused the editing shall not be
      entered into the history list." */
   if (listing == 0 && hist_last_line_added)
-    delete_last_history ();
+    {
+      delete_last_history ();
+      /* If we're editing a single command -- the last command in the
+        history -- and we just removed the dummy command added by
+        edit_and_execute_command (), we need to check whether or not we
+        just removed the last command in the history and need to back
+        the pointer up.  remember_on_history is off because we're running
+        in parse_and_execute(). */
+      if (histbeg == histend && histend == last_hist && hlist[last_hist] == 0)
+       last_hist = histbeg = --histend;
+    }
 
   /* We print error messages for line specifications out of range. */
   if ((histbeg < 0) || (histend < 0))
index 08abb317fd23703dab247b84c94e0a6213b20cb9..078e24106e6db1d79a637cf5897a8e4c7c6bbb7e 100644 (file)
@@ -45,6 +45,9 @@ 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.
+
+Exit Status:
+Returns success or status of executed command; non-zero if an error occurs.
 $END
 
 #include <config.h>
@@ -322,7 +325,19 @@ fc_builtin (list)
   /* "When not listing, the fc command that caused the editing shall not be
      entered into the history list." */
   if (listing == 0 && hist_last_line_added)
-    delete_last_history ();
+    {
+      delete_last_history ();
+      /* If we're editing a single command -- the last command in the
+        history -- and we just removed the dummy command added by
+        edit_and_execute_command (), we need to check whether or not we
+        just removed the last command in the history and need to back
+        the pointer up.  remember_on_history is off because we're running
+        in parse_and_execute(). */
+      if (histbeg == histend && histend == last_hist && hlist[last_hist] == 0)
+       last_hist = histbeg = --histend;
+    }
+
+itrace ("fc: last_hist = %d histbeg = %d histend = %d", last_hist, histbeg, histend);
 
   /* We print error messages for line specifications out of range. */
   if ((histbeg < 0) || (histend < 0))
index 0f0ecf9146920b99ac249f40bb071b35e0a54efa..d7a43202a9617ddf9efa735c83d0192fe5002810 100644 (file)
@@ -50,7 +50,8 @@ Options:
   -s           do not echo input coming from a terminal
   -t timeout   time out and return failure if a complete line of input is
                not read withint TIMEOUT seconds.  The value of the TMOUT
-               variable is the default timeout.
+               variable is the default timeout.  TIMEOUT may be a
+               fractional number.
   -u fd                read from file descriptor FD instead of the standard input
 
 Exit Status:
@@ -135,7 +136,7 @@ static void
 reset_alarm ()
 {
   set_signal_handler (SIGALRM, old_alrm);
-  alarm (0);
+  falarm (0, 0);
 }
 
 /* Read the value of the shell variables whose names follow.
@@ -152,7 +153,8 @@ read_builtin (list)
   int size, i, nr, pass_next, saw_escape, eof, opt, retval, code, print_ps2;
   int input_is_tty, input_is_pipe, unbuffered_read, skip_ctlesc, skip_ctlnul;
   int raw, edit, nchars, silent, have_timeout, fd;
-  unsigned int tmout;
+  unsigned int tmsec, tmusec;
+  long ival, uval;
   intmax_t intval;
   char c;
   char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname;
@@ -177,7 +179,8 @@ read_builtin (list)
   USE_VAR(input_is_pipe);
 /*  USE_VAR(raw); */
   USE_VAR(edit);
-  USE_VAR(tmout);
+  USE_VAR(tmsec);
+  USE_VAR(tmusec);
   USE_VAR(nchars);
   USE_VAR(silent);
   USE_VAR(ifs_chars);
@@ -202,7 +205,7 @@ read_builtin (list)
   rlind = 0;
 #endif
 
-  tmout = 0;           /* no timeout */
+  tmsec = tmusec = 0;          /* no timeout */
   nr = nchars = input_is_tty = input_is_pipe = unbuffered_read = have_timeout = 0;
   delim = '\n';                /* read until newline */
 
@@ -236,8 +239,8 @@ read_builtin (list)
          break;
 #endif
        case 't':
-         code = legal_number (list_optarg, &intval);
-         if (code == 0 || intval < 0 || intval != (unsigned int)intval)
+         code = uconvert (list_optarg, &ival, &uval);
+         if (code == 0 || ival < 0 || uval < 0)
            {
              builtin_error (_("%s: invalid timeout specification"), list_optarg);
              return (EXECUTION_FAILURE);
@@ -245,7 +248,8 @@ read_builtin (list)
          else
            {
              have_timeout = 1;
-             tmout = intval;
+             tmsec = ival;
+             tmusec = uval;
            }
          break;
        case 'n':
@@ -286,7 +290,7 @@ read_builtin (list)
   /* `read -t 0 var' returns failure immediately.  XXX - should it test
      whether input is available with select/FIONREAD, and fail if those
      are unavailable? */
-  if (have_timeout && tmout == 0)
+  if (have_timeout && tmsec == 0 && tmusec == 0)
     return (EXECUTION_FAILURE);
 
   /* IF IFS is unset, we use the default of " \t\n". */
@@ -302,11 +306,14 @@ read_builtin (list)
   /* $TMOUT, if set, is the default timeout for read. */
   if (have_timeout == 0 && (e = get_string_value ("TMOUT")))
     {
-      code = legal_number (e, &intval);
-      if (code == 0 || intval < 0 || intval != (unsigned int)intval)
-       tmout = 0;
+      code = uconvert (e, &ival, &uval);
+      if (code == 0 || ival < 0 || uval < 0)
+       tmsec = tmusec = 0;
       else
-       tmout = intval;
+       {
+         tmsec = ival;
+         tmusec = uval;
+       }
     }
 
   begin_unwind_frame ("read_builtin");
@@ -349,15 +356,15 @@ read_builtin (list)
   pass_next = 0;       /* Non-zero signifies last char was backslash. */
   saw_escape = 0;      /* Non-zero signifies that we saw an escape char */
 
-  if (tmout > 0)
+  if (tmsec > 0 || tmusec > 0)
     {
       /* Turn off the timeout if stdin is a regular file (e.g. from
         input redirection). */
       if ((fstat (fd, &tsb) < 0) || S_ISREG (tsb.st_mode))
-       tmout = 0;
+       tmsec = tmusec = 0;
     }
 
-  if (tmout > 0)
+  if (tmsec > 0 || tmusec > 0)
     {
       code = setjmp (alrmbuf);
       if (code)
@@ -377,7 +384,7 @@ read_builtin (list)
       if (edit)
        add_unwind_protect (reset_attempted_completion_function, (char *)NULL);
 #endif
-      alarm (tmout);
+      falarm (tmsec, tmusec);
     }
 
   /* If we've been asked to read only NCHARS chars, or we're using some
@@ -563,7 +570,7 @@ add_char:
     }
 #endif
 
-  if (tmout > 0)
+  if (tmsec > 0 || tmusec > 0)
     reset_alarm ();
 
   if (nchars > 0 || delim != '\n')
index 20bec10e5a3cd314acb3f48c3b39744dd2fca522..bf1e030044e83e5b952a55615498ae8ff0a4a3d6 100644 (file)
@@ -50,9 +50,11 @@ Options:
   -s           do not echo input coming from a terminal
   -t timeout   time out and return failure if a complete line of input is
                not read withint TIMEOUT seconds.  The value of the TMOUT
-               variable is the default timeout.
+               variable is the default timeout.  TIMEOUT may be a
+               fractional number.
   -u fd                read from file descriptor FD instead of the standard input
 
+Exit Status:
 The return code is zero, unless end-of-file is encountered, read times out,
 or an invalid file descriptor is supplied as the argument to -u.
 $END
@@ -134,7 +136,7 @@ static void
 reset_alarm ()
 {
   set_signal_handler (SIGALRM, old_alrm);
-  alarm (0);
+  falarm (0, 0);
 }
 
 /* Read the value of the shell variables whose names follow.
@@ -151,7 +153,8 @@ read_builtin (list)
   int size, i, nr, pass_next, saw_escape, eof, opt, retval, code, print_ps2;
   int input_is_tty, input_is_pipe, unbuffered_read, skip_ctlesc, skip_ctlnul;
   int raw, edit, nchars, silent, have_timeout, fd;
-  unsigned int tmout;
+  unsigned int tmsec, tmusec;
+  long ival, uval;
   intmax_t intval;
   char c;
   char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname;
@@ -176,7 +179,8 @@ read_builtin (list)
   USE_VAR(input_is_pipe);
 /*  USE_VAR(raw); */
   USE_VAR(edit);
-  USE_VAR(tmout);
+  USE_VAR(tmsec);
+  USE_VAR(tmusec);
   USE_VAR(nchars);
   USE_VAR(silent);
   USE_VAR(ifs_chars);
@@ -201,7 +205,7 @@ read_builtin (list)
   rlind = 0;
 #endif
 
-  tmout = 0;           /* no timeout */
+  tmsec = tmusec = 0;          /* no timeout */
   nr = nchars = input_is_tty = input_is_pipe = unbuffered_read = have_timeout = 0;
   delim = '\n';                /* read until newline */
 
@@ -235,8 +239,8 @@ read_builtin (list)
          break;
 #endif
        case 't':
-         code = legal_number (list_optarg, &intval);
-         if (code == 0 || intval < 0 || intval != (unsigned int)intval)
+         code = uconvert (list_optarg, &ival, &uval);
+         if (code == 0 || ival < 0 || uval < 0)
            {
              builtin_error (_("%s: invalid timeout specification"), list_optarg);
              return (EXECUTION_FAILURE);
@@ -244,7 +248,8 @@ read_builtin (list)
          else
            {
              have_timeout = 1;
-             tmout = intval;
+             tmsec = ival;
+             tmusec = uval;
            }
          break;
        case 'n':
@@ -285,7 +290,7 @@ read_builtin (list)
   /* `read -t 0 var' returns failure immediately.  XXX - should it test
      whether input is available with select/FIONREAD, and fail if those
      are unavailable? */
-  if (have_timeout && tmout == 0)
+  if (have_timeout && tmsec == 0 && tmusec == 0)
     return (EXECUTION_FAILURE);
 
   /* IF IFS is unset, we use the default of " \t\n". */
@@ -301,11 +306,14 @@ read_builtin (list)
   /* $TMOUT, if set, is the default timeout for read. */
   if (have_timeout == 0 && (e = get_string_value ("TMOUT")))
     {
-      code = legal_number (e, &intval);
-      if (code == 0 || intval < 0 || intval != (unsigned int)intval)
-       tmout = 0;
+      code = uconvert (e, &ival, &uval);
+      if (code == 0 || ival < 0 || uval < 0)
+       tmsec = tmusec = 0;
       else
-       tmout = intval;
+       {
+         tmsec = ival;
+         tmusec = uval;
+       }
     }
 
   begin_unwind_frame ("read_builtin");
@@ -348,15 +356,15 @@ read_builtin (list)
   pass_next = 0;       /* Non-zero signifies last char was backslash. */
   saw_escape = 0;      /* Non-zero signifies that we saw an escape char */
 
-  if (tmout > 0)
+  if (tmsec > 0 || tmusec > 0)
     {
       /* Turn off the timeout if stdin is a regular file (e.g. from
         input redirection). */
       if ((fstat (fd, &tsb) < 0) || S_ISREG (tsb.st_mode))
-       tmout = 0;
+       tmsec = tmusec = 0;
     }
 
-  if (tmout > 0)
+  if (tmsec > 0 || tmusec > 0)
     {
       code = setjmp (alrmbuf);
       if (code)
@@ -376,7 +384,7 @@ read_builtin (list)
       if (edit)
        add_unwind_protect (reset_attempted_completion_function, (char *)NULL);
 #endif
-      alarm (tmout);
+      falarm (tmsec, tmusec);
     }
 
   /* If we've been asked to read only NCHARS chars, or we're using some
@@ -562,10 +570,10 @@ add_char:
     }
 #endif
 
-  if (tmout > 0)
+  if (tmsec > 0 || tmusec > 0)
     reset_alarm ();
 
-  if (nchars > 0 || delim != '\n')
+<  if (nchars > 0 || delim != '\n')
     {
 #if defined (READLINE)
       if (edit)
index b2522974dc3950c02223c98816e3d26143d93157..523242964df57fd78926896a7722debbd84ca6e8 100644 (file)
@@ -71,7 +71,7 @@ extern int allow_null_glob_expansion, fail_glob_expansion, glob_dot_filenames;
 extern int cdable_vars, mail_warning, source_uses_path;
 extern int no_exit_on_failed_exec, print_shift_error;
 extern int check_hashed_filenames, promptvars;
-extern int cdspelling, expand_aliases;
+extern int cdspelling, dircomplete_spelling, expand_aliases;
 extern int extended_quote;
 extern int check_window_size;
 extern int glob_ignore_case, match_ignore_case;
@@ -80,6 +80,7 @@ extern int xpg_echo;
 extern int gnu_error_format;
 extern int check_jobs_at_exit;
 extern int autocd;
+extern int glob_star;
 
 #if defined (EXTENDED_GLOB)
 extern int extended_glob;
@@ -142,6 +143,7 @@ static struct {
   { "cmdhist", &command_oriented_history, (shopt_set_func_t *)NULL },
 #endif
   { "compat31", &shopt_compat31, set_compatibility_level },
+  { "dirspell", &dircomplete_spelling, (shopt_set_func_t *)NULL },
   { "dotglob", &glob_dot_filenames, (shopt_set_func_t *)NULL },
   { "execfail", &no_exit_on_failed_exec, (shopt_set_func_t *)NULL },
   { "expand_aliases", &expand_aliases, (shopt_set_func_t *)NULL },
@@ -156,6 +158,7 @@ static struct {
 #if defined (READLINE)
   { "force_fignore", &force_fignore, (shopt_set_func_t *)NULL },
 #endif
+  { "globstar", &glob_star, (shopt_set_func_t *)NULL },
   { "gnu_errfmt", &gnu_error_format, (shopt_set_func_t *)NULL },
 #if defined (HISTORY)
   { "histappend", &force_append_history, (shopt_set_func_t *)NULL },
index 9cc63b6dbe7c3081e31d5f0832a2796d50e089b2..8061a3f2961d767ce0e2ea4634f83e2015885c48 100644 (file)
@@ -71,7 +71,7 @@ extern int allow_null_glob_expansion, fail_glob_expansion, glob_dot_filenames;
 extern int cdable_vars, mail_warning, source_uses_path;
 extern int no_exit_on_failed_exec, print_shift_error;
 extern int check_hashed_filenames, promptvars;
-extern int cdspelling, expand_aliases;
+extern int cdspelling, dircomplete_spelling, expand_aliases;
 extern int extended_quote;
 extern int check_window_size;
 extern int glob_ignore_case, match_ignore_case;
@@ -80,6 +80,7 @@ extern int xpg_echo;
 extern int gnu_error_format;
 extern int check_jobs_at_exit;
 extern int autocd;
+extern int glob_star;
 
 #if defined (EXTENDED_GLOB)
 extern int extended_glob;
@@ -134,7 +135,9 @@ static struct {
   { "cdable_vars", &cdable_vars, (shopt_set_func_t *)NULL },
   { "cdspell", &cdspelling, (shopt_set_func_t *)NULL },
   { "checkhash", &check_hashed_filenames, (shopt_set_func_t *)NULL },
+#if defined (JOB_CONTROL)
   { "checkjobs", &check_jobs_at_exit, (shopt_set_func_t *)NULL },
+#endif
   { "checkwinsize", &check_window_size, (shopt_set_func_t *)NULL },
 #if defined (HISTORY)
   { "cmdhist", &command_oriented_history, (shopt_set_func_t *)NULL },
@@ -154,6 +157,7 @@ static struct {
 #if defined (READLINE)
   { "force_fignore", &force_fignore, (shopt_set_func_t *)NULL },
 #endif
+  { "globstar", &glob_star, (shopt_set_func_t *)NULL },
   { "gnu_errfmt", &gnu_error_format, (shopt_set_func_t *)NULL },
 #if defined (HISTORY)
   { "histappend", &force_append_history, (shopt_set_func_t *)NULL },
index a6ea2a978470dc34e2239782a60e806966eb0ba8..4fdb91eb0daebc6317af76012bc9427137494785 100644 (file)
 /* Define if you have the setenv function.  */
 #undef HAVE_SETENV
 
+/* Define if you have the setitimer function.  */
+#undef HAVE_SETITIMER
+
 /* Define if you have the setlinebuf function.  */
 #undef HAVE_SETLINEBUF
 
index 9bf4394f26cf1e4f21d04065a17a2ecf2162c598..a6ea2a978470dc34e2239782a60e806966eb0ba8 100644 (file)
 /* Define if you have the mbrtowc function. */
 #undef HAVE_MBRTOWC
 
+/* Define if you have the mbscmp function. */
+#undef HAVE_MBSCMP
+
 /* Define if you have the mbsrtowcs function. */
 #undef HAVE_MBSRTOWCS
 
index 5f8e1a54788d3e6a3c9125360af4c9773321ff34..e6327be8d5c63163ffbc49e65125bd8888a7c87a 100755 (executable)
--- a/configure
+++ b/configure
 
 
 
+
 
 
 for ac_func in dup2 eaccess fcntl getdtablesize getgroups gethostname \
                getpagesize getpeername getrlimit getrusage gettimeofday \
                kill killpg lstat readlink sbrk select setdtablesize \
-               tcgetpgrp uname ulimit waitpid
+               setitimer tcgetpgrp uname ulimit waitpid
 do
 as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
 { echo "$as_me:$LINENO: checking for $ac_func" >&5
index 397cbfc70e76c556e3eba27e765808d33f014e79..6e2fd77322deec75dedf50b3d4de11bd9a59b718 100644 (file)
@@ -698,7 +698,7 @@ dnl checks for system calls
 AC_CHECK_FUNCS(dup2 eaccess fcntl getdtablesize getgroups gethostname \
                getpagesize getpeername getrlimit getrusage gettimeofday \
                kill killpg lstat readlink sbrk select setdtablesize \
-               tcgetpgrp uname ulimit waitpid)
+               setitimer tcgetpgrp uname ulimit waitpid)
 AC_REPLACE_FUNCS(rename)
 
 dnl checks for c library functions
index d6a2d79acd0a4fb658d9e75272bc5e7dc2f78bd3..397cbfc70e76c556e3eba27e765808d33f014e79 100644 (file)
@@ -1,11 +1,11 @@
 dnl
-dnl Configure script for bash-3.2
+dnl Configure script for bash-4.0
 dnl
 dnl report bugs to chet@po.cwru.edu
 dnl
 dnl Process this file with autoconf to produce a configure script.
 
-# Copyright (C) 1987-2007 Free Software Foundation, Inc.
+# Copyright (C) 1987-2008 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -22,10 +22,10 @@ dnl Process this file with autoconf to produce a configure script.
 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 # 02111-1307, USA.
 
-AC_REVISION([for Bash 3.2, version 3.197])dnl
+AC_REVISION([for Bash 4.0, version 4.001])dnl
 
-define(bashvers, 3.2)
-define(relstatus, maint)
+define(bashvers, 4.0)
+define(relstatus, devel)
 
 AC_INIT([bash], bashvers-relstatus, [bug-bash@gnu.org])
 
index 1dd9cfa04fded071f2fe80f5566f21de09e896e0..8e576265d721357f57d53dbfa8b4c11a378393f8 100644 (file)
@@ -5,12 +5,12 @@
 .\"    Case Western Reserve University
 .\"    chet@po.cwru.edu
 .\"
-.\"    Last Change: Fri Apr 25 12:26:57 EDT 2008
+.\"    Last Change: Sun May  4 22:27:45 EDT 2008
 .\"
 .\" bash_builtins, strip all but Built-Ins section
 .if \n(zZ=1 .ig zZ
 .if \n(zY=1 .ig zY
-.TH BASH 1 "2008 April 25" "GNU Bash-4.0"
+.TH BASH 1 "2008 May 4" "GNU Bash-4.0"
 .\"
 .\" There's some problem with having a `@'
 .\" in a tagged paragraph with the BSD man macros.
@@ -2872,6 +2872,12 @@ The special pattern characters have the following meanings:
 .TP
 .B *
 Matches any string, including the null string.
+When the \fBglobstar\fP shell option is enabled, and \fB*\fP is used in
+a filename expansion context, two adjacent \fB*\fPs used as a single
+pattern will match all files and zero or more directories and
+subdirectories.
+If followed by a \fB/\fP, two adjacent \fB*\fPs will match only directories
+and subdirectories.
 .TP
 .B ?
 Matches any single character.
@@ -7670,6 +7676,8 @@ not echoed.
 .B \-t \fItimeout\fP
 Cause \fBread\fP to time out and return failure if a complete line of
 input is not read within \fItimeout\fP seconds.
+\fItimeout\fP may be a decimal number with a fractional portion following
+the decimal point.
 This option has no effect if \fBread\fP is not reading input from the
 terminal or a pipe.
 .TP
@@ -8205,6 +8213,12 @@ If set,
 changes its behavior to that of version 3.1 with respect to quoted
 arguments to the conditional command's =~ operator.
 .TP 8
+.B dirspell
+If set,
+.B bash
+attempts spelling correction on directory names during word completion
+if the directory name initially supplied does not exist.
+.TP 8
 .B dotglob
 If set, 
 .B bash
@@ -8282,6 +8296,12 @@ See
 above for a description of \fBFIGNORE\fP.
 This option is enabled by default.
 .TP 8
+.B globstar
+If set, the pattern \fB**\fP used in a filename expansion context will
+match a files and zero or more directories and subdirectories.
+If the pattern is followed by a \fB/\fP, only directories and
+subdirectories match.
+.TP 8
 .B gnu_errfmt
 If set, shell error messages are written in the standard GNU error
 message format.
index 6879596481d4554b6878a47e14be1e70fbf96287..dfce742967a82145e49e7032cf03f72bd502a18c 100644 (file)
@@ -5,12 +5,12 @@
 .\"    Case Western Reserve University
 .\"    chet@po.cwru.edu
 .\"
-.\"    Last Change: Sat Apr 12 17:15:24 EDT 2008
+.\"    Last Change: Sun May  4 22:27:45 EDT 2008
 .\"
 .\" bash_builtins, strip all but Built-Ins section
 .if \n(zZ=1 .ig zZ
 .if \n(zY=1 .ig zY
-.TH BASH 1 "2008 April 12" "GNU Bash-3.2"
+.TH BASH 1 "2008 May 4" "GNU Bash-4.0"
 .\"
 .\" There's some problem with having a `@'
 .\" in a tagged paragraph with the BSD man macros.
@@ -2872,6 +2872,12 @@ The special pattern characters have the following meanings:
 .TP
 .B *
 Matches any string, including the null string.
+When the \fBglobstar\fP shell option is enabled, and \fB*\fP is used in
+a filename expansion context, two adjacent \fB*\fPs used as a single
+pattern will match all files and zero or more directories and
+subdirectories.
+If followed by a \fB/\fP, two adjacent \fB*\fPs will match only directories
+and subdirectories.
 .TP
 .B ?
 Matches any single character.
@@ -3791,7 +3797,12 @@ A full search of the directories in
 .SM
 .B PATH
 is performed only if the command is not found in the hash table.
-If the search is unsuccessful, the shell prints an error
+If the search is unsuccessful, the shell searches for a defined shell
+function named \fBcommand_not_found_handle\fP.
+If that function exists, it is invoked with the original command and
+the original command's arguments as its arguments, and the function's
+exit status becomes the exit status of the shell.
+If that function is not defined, the shell prints an error
 message and returns an exit status of 127.
 .PP
 If the search is successful, or if the command name contains
@@ -7665,6 +7676,7 @@ not echoed.
 .B \-t \fItimeout\fP
 Cause \fBread\fP to time out and return failure if a complete line of
 input is not read within \fItimeout\fP seconds.
+\fItimeout\fP may be a decimal number with a fractional portion.
 This option has no effect if \fBread\fP is not reading input from the
 terminal or a pipe.
 .TP
@@ -8200,6 +8212,12 @@ If set,
 changes its behavior to that of version 3.1 with respect to quoted
 arguments to the conditional command's =~ operator.
 .TP 8
+.B dirspell
+If set,
+.B bash
+attempts spelling correction on directory names during word completion
+if the directory name initially supplied does not exist.
+.TP 8
 .B dotglob
 If set, 
 .B bash
@@ -8277,6 +8295,12 @@ See
 above for a description of \fBFIGNORE\fP.
 This option is enabled by default.
 .TP 8
+.B globstar
+If set, the pattern \fB**\fP used in a filename expansion context will
+match a files and zero or more directories and subdirectories.
+If the pattern is followed by a \fB/\fP, only directories and
+subdirectories match.
+.TP 8
 .B gnu_errfmt
 If set, shell error messages are written in the standard GNU error
 message format.
index 9ad608bfddb889fe6a7de497c3a55bffb004b4e6..f90cc23b27758576593f0e1e21023fe82c5f8fbb 100644 (file)
@@ -1886,6 +1886,12 @@ The special pattern characters have the following meanings:
 @table @code
 @item *
 Matches any string, including the null string.
+When the @code{globstar} shell option is enabled, and @samp{*} is used in
+a filename expansion context, two adjacent @samp{*}s used as a single
+pattern will match all files and zero or more directories and
+subdirectories.
+If followed by a @samp{/}, two adjacent @samp{*}s will match only
+directories and subdirectories.
 @item ?
 Matches any single character.
 @item [@dots{}]
@@ -3604,6 +3610,8 @@ not echoed.
 @item -t @var{timeout}
 Cause @code{read} to time out and return failure if a complete line of
 input is not read within @var{timeout} seconds.
+@var{timeout}  may be a decimal number with a fractional portion following
+the decimal point.
 This option has no effect if @code{read} is not reading input from the
 terminal or a pipe.
 
@@ -4143,6 +4151,11 @@ If set, Bash
 changes its behavior to that of version 3.1 with respect to quoted
 arguments to the conditional command's =~ operator.
 
+@item dirspell
+If set, Bash
+attempts spelling correction on directory names during word completion 
+if the directory name initially supplied does not exist.
+
 @item dotglob
 If set, Bash includes filenames beginning with a `.' in
 the results of filename expansion.
@@ -4212,6 +4225,12 @@ the ignored words are the only possible completions.
 @xref{Bash Variables}, for a description of @env{FIGNORE}.
 This option is enabled by default.
 
+@item globstar
+If set, the pattern @samp{**} used in a filename expansion context will
+match a files and zero or more directories and subdirectories.
+If the pattern is followed by a @samp{/}, only directories and
+subdirectories match.
+
 @item gnu_errfmt
 If set, shell error messages are written in the standard @sc{gnu} error
 message format.
index e8482ab2c264adf8dba9f0586689b817c099f22f..5664da2b732b1ac34b3c39f94d6daaeb0cf2ad18 100644 (file)
@@ -1886,6 +1886,12 @@ The special pattern characters have the following meanings:
 @table @code
 @item *
 Matches any string, including the null string.
+When the @code{globstar} shell option is enabled, and @samp{*} is used in
+a filename expansion context, two adjacent @samp{*}s used as a single
+pattern will match all files and zero or more directories and
+subdirectories.
+If followed by a @samp{/}, two adjacent @samp{*}s will match only
+directories and subdirectories.
 @item ?
 Matches any single character.
 @item [@dots{}]
@@ -2301,7 +2307,12 @@ pathnames of executable files to avoid multiple @env{PATH} searches
 (see the description of @code{hash} in @ref{Bourne Shell Builtins}).
 A full search of the directories in @env{$PATH}
 is performed only if the command is not found in the hash table.
-If the search is unsuccessful, the shell prints an error
+If the search is unsuccessful, the shell searches for a defined shell
+function named @code{command_not_found_handle}.
+If that function exists, it is invoked with the original command and
+the original command's arguments as its arguments, and the function's
+exit status becomes the exit status of the shell.
+If that function is not defined, the shell prints an error
 message and returns an exit status of 127.
 
 @item
@@ -4138,6 +4149,11 @@ If set, Bash
 changes its behavior to that of version 3.1 with respect to quoted
 arguments to the conditional command's =~ operator.
 
+@item dirspell
+If set, Bash
+attempts spelling correction on directory names during word completion 
+if the directory name initially supplied does not exist.
+
 @item dotglob
 If set, Bash includes filenames beginning with a `.' in
 the results of filename expansion.
@@ -4207,6 +4223,12 @@ the ignored words are the only possible completions.
 @xref{Bash Variables}, for a description of @env{FIGNORE}.
 This option is enabled by default.
 
+@item globstar
+If set, the pattern @samp{**} used in a filename expansion context will
+match a files and zero or more directories and subdirectories.
+If the pattern is followed by a @samp{/}, only directories and
+subdirectories match.
+
 @item gnu_errfmt
 If set, shell error messages are written in the standard @sc{gnu} error
 message format.
index 314c1efc7497c9ad349b71570d77c2a4293f2f60..ba448d24b0d31cb1681ba789d77e43076ac10894 100644 (file)
@@ -2,9 +2,9 @@
 Copyright (C) 1988-2008 Free Software Foundation, Inc.
 @end ignore
 
-@set LASTCHANGE Fri Apr 25 12:33:01 EDT 2008
+@set LASTCHANGE Sun May  4 22:23:58 EDT 2008
 
 @set EDITION 4.0
 @set VERSION 4.0
-@set UPDATED 25 April 2008
-@set UPDATED-MONTH April 2008
+@set UPDATED 4 May 2008
+@set UPDATED-MONTH May 2008
index 1e0036862159fbfc39dc45e7835c7b70e2338a4a..314c1efc7497c9ad349b71570d77c2a4293f2f60 100644 (file)
@@ -2,9 +2,9 @@
 Copyright (C) 1988-2008 Free Software Foundation, Inc.
 @end ignore
 
-@set LASTCHANGE Sat Apr 12 17:15:43 EDT 2008
+@set LASTCHANGE Fri Apr 25 12:33:01 EDT 2008
 
-@set EDITION 3.2
-@set VERSION 3.2
-@set UPDATED 12 April 2008
+@set EDITION 4.0
+@set VERSION 4.0
+@set UPDATED 25 April 2008
 @set UPDATED-MONTH April 2008
index 59aad9d101faf802da864ae990b16f59a9cc1f6e..5dabc9a6d55311c01b473bb18907764793f59d55 100644 (file)
--- a/general.c
+++ b/general.c
@@ -1,6 +1,6 @@
 /* general.c -- Stuff that is used by all files. */
 
-/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -489,6 +489,41 @@ check_binary_file (sample, sample_len)
   return (0);
 }
 
+/* **************************************************************** */
+/*                                                                 */
+/*                 Functions to manipulate pipes                   */
+/*                                                                 */
+/* **************************************************************** */
+
+int
+sh_openpipe (pv)
+     int *pv;
+{
+  int r;
+
+  if ((r = pipe (pv)) < 0)
+    return r;
+
+  pv[0] = move_to_high_fd (pv[0], 1, 64);
+  pv[1] = move_to_high_fd (pv[1], 1, 64);
+
+  return 0;  
+}
+
+int
+sh_closepipe (pv)
+     int *pv;
+{
+  if (pv[0] >= 0)
+    close (pv[0]);
+
+  if (pv[1] >= 0)
+    close (pv[1]);
+
+  pv[0] = pv[1] = -1;
+  return 0;
+}
+
 /* **************************************************************** */
 /*                                                                 */
 /*                 Functions to inspect pathnames                  */
@@ -642,6 +677,72 @@ polite_directory_format (name)
     return (name);
 }
 
+/* Trim NAME.  If NAME begins with `~/', skip over tilde prefix.  Trim to
+   keep any tilde prefix and PROMPT_DIRTRIM trailing directory components
+   and replace the intervening characters with `...' */
+char *
+trim_pathname (name, maxlen)
+     char *name;
+     int maxlen;
+{
+  int nlen, ndirs;
+  intmax_t nskip;
+  char *nbeg, *nend, *ntail, *v;
+
+  if (name == 0 || (nlen = strlen (name)) == 0)
+    return name;
+  nend = name + nlen;
+
+  v = get_string_value ("PROMPT_DIRTRIM");
+  if (v == 0 || *v == 0)
+    return name;
+  if (legal_number (v, &nskip) == 0 || nskip <= 0)
+    return name;
+
+  /* Skip over tilde prefix */
+  nbeg = name;
+  if (name[0] == '~')
+    for (nbeg = name; *nbeg; nbeg++)
+      if (*nbeg == '/')
+       {
+         nbeg++;
+         break;
+       }
+  if (*nbeg == 0)
+    return name;
+
+  for (ndirs = 0, ntail = nbeg; *ntail; ntail++)
+    if (*ntail == '/')
+      ndirs++;
+  if (ndirs <= nskip)
+    return name;
+
+  for (ntail = (*nend == '/') ? nend : nend - 1; ntail > nbeg; ntail--)
+    {
+      if (*ntail == '/')
+       nskip--;
+      if (nskip == 0)
+       break;
+    }
+  if (ntail == nbeg)
+    return name;
+
+  /* Now we want to return name[0..nbeg]+"..."+ntail, modifying name in place */
+  nlen = ntail - nbeg;
+  if (nlen <= 3)
+    return name;
+
+  *nbeg++ = '.';
+  *nbeg++ = '.';
+  *nbeg++ = '.';
+
+  nlen = nend - ntail;
+  memcpy (nbeg, ntail, nlen);
+  nbeg[nlen] = '\0';
+
+  return name;
+}
+
 /* Given a string containing units of information separated by colons,
    return the next one pointed to by (P_INDEX), or NULL if there are no more.
    Advance (P_INDEX) to the character after the colon. */
index 944b482edc3a4029d7e34bcf0724158127a146f4..10e1ff5874531ec655cbe0aaa4d08a511a9c398f 100644 (file)
@@ -1,6 +1,6 @@
 /* general.c -- Stuff that is used by all files. */
 
-/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -69,6 +69,7 @@ posix_initialize (on)
   if (on != 0)
     {
       interactive_comments = source_uses_path = expand_aliases = 1;
+      source_searches_cwd = 0;
     }
 
   /* Things that should be turned on when posix mode is disabled. */
@@ -488,6 +489,41 @@ check_binary_file (sample, sample_len)
   return (0);
 }
 
+/* **************************************************************** */
+/*                                                                 */
+/*                 Functions to manipulate pipes                   */
+/*                                                                 */
+/* **************************************************************** */
+
+int
+sh_openpipe (pv)
+     int *pv;
+{
+  int r;
+
+  if ((r = pipe (pv)) < 0)
+    return r;
+
+  pv[0] = move_to_high_fd (pv[0], 1, 64);
+  pv[1] = move_to_high_fd (pv[1], 1, 64);
+
+  return 0;  
+}
+
+int
+sh_closepipe (pv)
+     int *pv;
+{
+  if (pv[0] >= 0)
+    close (pv[0]);
+
+  if (pv[1] >= 0)
+    close (pv[1]);
+
+  pv[0] = pv[1] = -1;
+  return 0;
+}
+
 /* **************************************************************** */
 /*                                                                 */
 /*                 Functions to inspect pathnames                  */
index 5fc46cc6921721e07f2ba33573375d1a3bbe7a9a..a711d4cb832e8795695b948ee36de37b659663ae 100644 (file)
--- a/general.h
+++ b/general.h
@@ -1,6 +1,6 @@
 /* general.h -- defines that everybody likes to use. */
 
-/* Copyright (C) 1993-2004 Free Software Foundation, Inc.
+/* Copyright (C) 1993-2008 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -297,6 +297,9 @@ extern int check_binary_file __P((char *, int));
 extern int same_file __P((char *, char *, struct stat *, struct stat *));
 #endif
 
+extern int sh_openpipe __P((int *));
+extern int sh_closepipe __P((int *));
+
 extern int file_isdir __P((char  *));
 extern int file_iswdir __P((char  *));
 extern int absolute_pathname __P((const char *));
@@ -306,6 +309,7 @@ extern char *make_absolute __P((char *, char *));
 extern char *base_pathname __P((char *));
 extern char *full_pathname __P((char *));
 extern char *polite_directory_format __P((char *));
+extern char *trim_pathname __P((char *, int));
 
 extern char *extract_colon_unit __P((char *, int *));
 
index e1d01f565bd9e4cc69a6152b95af447618944fec..5fc46cc6921721e07f2ba33573375d1a3bbe7a9a 100644 (file)
@@ -281,7 +281,7 @@ extern void print_rlimtype __P((RLIMTYPE, int));
 #endif
 
 extern int all_digits __P((char *));
-extern int legal_number __P((char *, intmax_t *));
+extern int legal_number __P((const char *, intmax_t *));
 extern int legal_identifier __P((char *));
 extern int check_identifier __P((WORD_DESC *, int));
 extern int legal_alias_name __P((char *, int));
index 3d47c1c95f91b118ddcb1bbc243d76c4bb8fdd6f..30ffee165a0fe9b08454f635932ec9e988970239 100644 (file)
--- a/hashcmd.h
+++ b/hashcmd.h
@@ -1,6 +1,6 @@
 /* hashcmd.h - Common defines for hashing filenames. */
 
-/* Copyright (C) 1993 Free Software Foundation, Inc.
+/* Copyright (C) 1993-2008 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -25,7 +25,7 @@
 
 extern HASH_TABLE *hashed_filenames;
 
-typedef struct {
+typedef struct _pathdata {
   char *path;          /* The full pathname of the file. */
   int flags;
 } PATH_DATA;
diff --git a/hashcmd.h~ b/hashcmd.h~
new file mode 100644 (file)
index 0000000..3d47c1c
--- /dev/null
@@ -0,0 +1,43 @@
+/* hashcmd.h - Common defines for hashing filenames. */
+
+/* Copyright (C) 1993 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   Bash is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2, or (at your option) any later
+   version.
+
+   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Bash; see the file COPYING.  If not, write to the Free Software
+   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#include "stdc.h"
+#include "hashlib.h"
+
+#define FILENAME_HASH_BUCKETS 64       /* must be power of two */
+
+extern HASH_TABLE *hashed_filenames;
+
+typedef struct {
+  char *path;          /* The full pathname of the file. */
+  int flags;
+} PATH_DATA;
+
+#define HASH_RELPATH   0x01    /* this filename is a relative pathname. */
+#define HASH_CHKDOT    0x02    /* check `.' since it was earlier in $PATH */
+
+#define pathdata(x) ((PATH_DATA *)(x)->data)
+
+extern void phash_create __P((void));
+extern void phash_flush __P((void));
+
+extern void phash_insert __P((char *, char *, int, int));
+extern int phash_remove __P((const char *));
+extern char *phash_search __P((const char *));
diff --git a/jobs.c b/jobs.c
index df2ef7595f39f538f4bce86258ee394822b0960a..e701caf6451b84a2a759ef43b67553287f2c1ee0 100644 (file)
--- a/jobs.c
+++ b/jobs.c
@@ -3,7 +3,7 @@
 /* This file works with both POSIX and BSD systems.  It implements job
    control. */
 
-/* Copyright (C) 1989-2007 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2008 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -272,7 +272,6 @@ static void mark_dead_jobs_as_notified __P((int));
 static void restore_sigint_handler __P((void));
 #if defined (PGRP_PIPE)
 static void pipe_read __P((int *));
-static void pipe_close __P((int *));
 #endif
 
 static struct pidstat *bgp_alloc __P((pid_t, int));
@@ -455,7 +454,7 @@ start_pipeline ()
       cleanup_the_pipeline ();
       pipeline_pgrp = 0;
 #if defined (PGRP_PIPE)
-      pipe_close (pgrp_pipe);
+      sh_closepipe (pgrp_pipe);
 #endif
     }
 
@@ -485,7 +484,7 @@ stop_pipeline (async, deferred)
 
 #if defined (PGRP_PIPE)
   /* The parent closes the process group synchronization pipe. */
-  pipe_close (pgrp_pipe);
+  sh_closepipe (pgrp_pipe);
 #endif
 
   cleanup_dead_jobs ();
@@ -1104,7 +1103,7 @@ add_process (name, pid)
        internal_warning (_("add_process: process %5ld (%s) in the_pipeline"), (long)p->pid, p->command);
 #  endif
       if (PALIVE (p))
-        internal_warning ("add_process: pid %5ld (%s) marked as still alive", (long)p->pid, p->command);
+        internal_warning (_("add_process: pid %5ld (%s) marked as still alive"), (long)p->pid, p->command);
       p->running = PS_RECYCLED;                /* mark as recycled */
     }
 #endif
@@ -1793,16 +1792,18 @@ make_child (command, async_p)
 
 #if defined (PGRP_PIPE)
       /* Release the process group pipe, since our call to setpgid ()
-        is done.  The last call to pipe_close is done in stop_pipeline. */
-      pipe_close (pgrp_pipe);
+        is done.  The last call to sh_closepipe is done in stop_pipeline. */
+      sh_closepipe (pgrp_pipe);
 #endif /* PGRP_PIPE */
 
 #if 0
+      /* Don't set last_asynchronous_pid in the child */
       if (async_p)
        last_asynchronous_pid = mypid;          /* XXX */
+      else
 #endif
 #if defined (RECYCLES_PIDS)
-      else if (last_asynchronous_pid == mypid)
+      if (last_asynchronous_pid == mypid)
         /* Avoid pid aliasing.  1 seems like a safe, unusual pid value. */
        last_asynchronous_pid = 1;
 #endif
@@ -2213,6 +2214,7 @@ wait_sigint_handler (sig)
   /* XXX - should this be interrupt_state?  If it is, the shell will act
      as if it got the SIGINT interrupt. */
   wait_sigint_received = 1;
+
   /* Otherwise effectively ignore the SIGINT and allow the running job to
      be killed. */
   SIGRETURN (0);
@@ -3032,6 +3034,7 @@ waitchld (wpid, block)
       if (sigchld || block == 0)
        waitpid_flags |= WNOHANG;
       CHECK_TERMSIG;
+
       pid = WAITPID (-1, &status, waitpid_flags);
 
       /* WCONTINUED may be rejected by waitpid as invalid even when defined */
@@ -3078,7 +3081,11 @@ waitchld (wpid, block)
         a pipeline in backquote substitution.  Even so, I'm not
         sure child is ever non-zero. */
       if (child == 0)
-       continue;
+       {
+         if (WIFEXITED (status) || WIFSIGNALED (status))
+           js.c_reaped++;
+         continue;
+       }
 
       /* Remember status, and whether or not the process is running. */
       child->status = status;
@@ -4073,7 +4080,7 @@ without_job_control ()
   stop_making_children ();
   start_pipeline ();
 #if defined (PGRP_PIPE)
-  pipe_close (pgrp_pipe);
+  sh_closepipe (pgrp_pipe);
 #endif
   delete_all_jobs (0);
   set_job_control (0);
@@ -4136,25 +4143,11 @@ pipe_read (pp)
     }
 }
 
-/* Close the read and write ends of PP, an array of file descriptors. */
-static void
-pipe_close (pp)
-     int *pp;
-{
-  if (pp[0] >= 0)
-    close (pp[0]);
-
-  if (pp[1] >= 0)
-    close (pp[1]);
-
-  pp[0] = pp[1] = -1;
-}
-
 /* Functional interface closes our local-to-job-control pipes. */
 void
 close_pgrp_pipe ()
 {
-  pipe_close (pgrp_pipe);
+  sh_closepipe (pgrp_pipe);
 }
 
 #endif /* PGRP_PIPE */
diff --git a/jobs.c~ b/jobs.c~
index eb328a0c174cddcbd5bfb022dfefcfa6e4b2558a..1414bc46a1494ee4d559e6d56f63786fe1b40a85 100644 (file)
--- a/jobs.c~
+++ b/jobs.c~
@@ -3,7 +3,7 @@
 /* This file works with both POSIX and BSD systems.  It implements job
    control. */
 
-/* Copyright (C) 1989-2007 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2008 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -272,7 +272,6 @@ static void mark_dead_jobs_as_notified __P((int));
 static void restore_sigint_handler __P((void));
 #if defined (PGRP_PIPE)
 static void pipe_read __P((int *));
-static void pipe_close __P((int *));
 #endif
 
 static struct pidstat *bgp_alloc __P((pid_t, int));
@@ -455,7 +454,7 @@ start_pipeline ()
       cleanup_the_pipeline ();
       pipeline_pgrp = 0;
 #if defined (PGRP_PIPE)
-      pipe_close (pgrp_pipe);
+      sh_closepipe (pgrp_pipe);
 #endif
     }
 
@@ -485,7 +484,7 @@ stop_pipeline (async, deferred)
 
 #if defined (PGRP_PIPE)
   /* The parent closes the process group synchronization pipe. */
-  pipe_close (pgrp_pipe);
+  sh_closepipe (pgrp_pipe);
 #endif
 
   cleanup_dead_jobs ();
@@ -1104,7 +1103,7 @@ add_process (name, pid)
        internal_warning (_("add_process: process %5ld (%s) in the_pipeline"), (long)p->pid, p->command);
 #  endif
       if (PALIVE (p))
-        internal_warning ("add_process: pid %5ld (%s) marked as still alive", (long)p->pid, p->command);
+        internal_warning (_("add_process: pid %5ld (%s) marked as still alive"), (long)p->pid, p->command);
       p->running = PS_RECYCLED;                /* mark as recycled */
     }
 #endif
@@ -1793,16 +1792,18 @@ make_child (command, async_p)
 
 #if defined (PGRP_PIPE)
       /* Release the process group pipe, since our call to setpgid ()
-        is done.  The last call to pipe_close is done in stop_pipeline. */
-      pipe_close (pgrp_pipe);
+        is done.  The last call to sh_closepipe is done in stop_pipeline. */
+      sh_closepipe (pgrp_pipe);
 #endif /* PGRP_PIPE */
 
 #if 0
+      /* Don't set last_asynchronous_pid in the child */
       if (async_p)
        last_asynchronous_pid = mypid;          /* XXX */
+      else
 #endif
 #if defined (RECYCLES_PIDS)
-      else if (last_asynchronous_pid == mypid)
+      if (last_asynchronous_pid == mypid)
         /* Avoid pid aliasing.  1 seems like a safe, unusual pid value. */
        last_asynchronous_pid = 1;
 #endif
@@ -3032,6 +3033,7 @@ waitchld (wpid, block)
       if (sigchld || block == 0)
        waitpid_flags |= WNOHANG;
       CHECK_TERMSIG;
+
       pid = WAITPID (-1, &status, waitpid_flags);
 
       /* WCONTINUED may be rejected by waitpid as invalid even when defined */
@@ -3078,7 +3080,11 @@ waitchld (wpid, block)
         a pipeline in backquote substitution.  Even so, I'm not
         sure child is ever non-zero. */
       if (child == 0)
-       continue;
+       {
+         if (WIFEXITED (status) || WIFSIGNALED (status))
+           js.c_reaped++;
+         continue;
+       }
 
       /* Remember status, and whether or not the process is running. */
       child->status = status;
@@ -3893,7 +3899,7 @@ count_all_jobs ()
     {
 #if defined (DEBUG)
       if (i < js.j_firstj && jobs[i])
-       itrace<("count_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+       itrace("count_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
       if (i > js.j_lastj && jobs[i])
        itrace("count_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
 #endif
@@ -4073,7 +4079,7 @@ without_job_control ()
   stop_making_children ();
   start_pipeline ();
 #if defined (PGRP_PIPE)
-  pipe_close (pgrp_pipe);
+  sh_closepipe (pgrp_pipe);
 #endif
   delete_all_jobs (0);
   set_job_control (0);
@@ -4136,25 +4142,11 @@ pipe_read (pp)
     }
 }
 
-/* Close the read and write ends of PP, an array of file descriptors. */
-static void
-pipe_close (pp)
-     int *pp;
-{
-  if (pp[0] >= 0)
-    close (pp[0]);
-
-  if (pp[1] >= 0)
-    close (pp[1]);
-
-  pp[0] = pp[1] = -1;
-}
-
 /* Functional interface closes our local-to-job-control pipes. */
 void
 close_pgrp_pipe ()
 {
-  pipe_close (pgrp_pipe);
+  sh_closepipe (pgrp_pipe);
 }
 
 #endif /* PGRP_PIPE */
index 08a7da8532a4dca674a5e832967676da05cf7c47..55aff5667e20e0cbfa7c7a07fac22adaab354f8c 100644 (file)
@@ -1,6 +1,6 @@
 /* glob.c -- file-name wildcard pattern matching for Bash.
 
-   Copyright (C) 1985-2005 Free Software Foundation, Inc.
+   Copyright (C) 1985-2008 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -45,7 +45,8 @@
 
 #include "stdc.h"
 #include "memalloc.h"
-#include "quit.h"
+
+#include "shell.h"
 
 #include "glob.h"
 #include "strmatch.h"
 #  define ALLOCA_MAX   100000
 #endif
 
+struct globval
+  {
+    struct globval *next;
+    char *name;
+  };
+
 extern void throw_to_top_level __P((void));
 extern int sh_eaccess __P((char *, int));
+extern char *sh_makepath __P((const char *, const char *, int));
 
 extern int extended_glob;
 
@@ -88,10 +96,12 @@ int glob_ignore_case = 0;
 /* Global variable to return to signify an error in globbing. */
 char *glob_error_return;
 
+static struct globval finddirs_error_return;
+
 /* Some forward declarations. */
-static int skipname __P((char *, char *));
+static int skipname __P((char *, char *, int));
 #if HANDLE_MULTIBYTE
-static int mbskipname __P((char *, char *));
+static int mbskipname __P((char *, char *, int));
 #endif
 #if HANDLE_MULTIBYTE
 static void udequote_pathname __P((char *));
@@ -154,9 +164,10 @@ glob_pattern_p (pattern)
    with matching leading `.'. */
 
 static int
-skipname (pat, dname)
+skipname (pat, dname, flags)
      char *pat;
      char *dname;
+     int flags;
 {
   /* If a leading dot need not be explicitly matched, and the pattern
      doesn't start with a `.', don't match `.' or `..' */
@@ -179,8 +190,9 @@ skipname (pat, dname)
    characters in PAT and DNAME.  Mostly concerned with matching leading `.'. */
 
 static int
-mbskipname (pat, dname)
+mbskipname (pat, dname, flags)
      char *pat, *dname;
+     int flags;
 {
   int ret;
   wchar_t *pat_wc, *dn_wc;
@@ -315,6 +327,75 @@ glob_testdir (dir)
   return (0);
 }
 
+/* Recursively scan SDIR for directories matching PAT (PAT is always `**').
+   FLAGS is simply passed down to the recursive call to glob_vector.  Returns
+   a list of matching directory names.  EP, if non-null, is set to the last
+   element of the returned list.  NP, if non-null, is set to the number of
+   directories in the returned list.  These two variables exist for the
+   convenience of the caller (always glob_vector). */
+static struct globval *
+finddirs (pat, sdir, flags, ep, np)
+     char *pat;
+     char *sdir;
+     int flags;
+     struct globval **ep;
+     int *np;
+{
+  char **r, *n;
+  int ndirs;
+  struct globval *ret, *e, *g;
+
+/*itrace("finddirs: pat = `%s' sdir = `%s' flags = 0x%x", pat, sdir, flags);*/
+  e = ret = 0;
+  r = glob_vector (pat, sdir, flags);
+  if (r == 0 || r[0] == 0)
+    {
+      if (np)
+       *np = 0;
+      if (ep)
+        *ep = 0;
+      if (r)
+       free (r);
+      return (struct globval *)0;
+    }
+  for (ndirs = 0; r[ndirs] != 0; ndirs++)
+    {
+      g = (struct globval *) malloc (sizeof (struct globval));
+      if (g == 0)
+       {
+         while (ret)           /* free list built so far */
+           {
+             g = ret->next;
+             free (ret);
+             ret = g;
+           }
+
+         free (r);
+         if (np)
+           *np = 0;
+         if (ep)
+           *ep = 0;
+         return (&finddirs_error_return);
+       }
+      if (e == 0)
+       e = g;
+
+      g->next = ret;
+      ret = g;
+
+      g->name = r[ndirs];
+    }
+
+  free (r);
+  if (ep)
+    *ep = e;
+  if (np)
+    *np = ndirs;
+
+  return ret;
+}
+
+       
 /* Return a vector of names of files in directory DIR
    whose names match glob pattern PAT.
    The names are not in any particular order.
@@ -337,31 +418,27 @@ glob_vector (pat, dir, flags)
      char *dir;
      int flags;
 {
-  struct globval
-    {
-      struct globval *next;
-      char *name;
-    };
-
   DIR *d;
   register struct dirent *dp;
-  struct globval *lastlink;
+  struct globval *lastlink, *e, *dirlist;
   register struct globval *nextlink;
-  register char *nextname, *npat;
+  register char *nextname, *npat, *subdir;
   unsigned int count;
-  int lose, skip;
+  int lose, skip, ndirs, isdir, sdlen, add_current;
   register char **name_vector;
   register unsigned int i;
   int mflags;          /* Flags passed to strmatch (). */
+  int pflags;          /* flags passed to sh_makepath () */
   int nalloca;
   struct globval *firstmalloc, *tmplink;
 
   lastlink = 0;
-  count = lose = skip = 0;
+  count = lose = skip = add_current = 0;
 
   firstmalloc = 0;
   nalloca = 0;
 
+/*itrace("glob_vector: pat = `%s' dir = `%s' flags = 0x%x", pat, dir, flags);*/
   /* If PAT is empty, skip the loop, but return one (empty) filename. */
   if (pat == 0 || *pat == '\0')
     {
@@ -463,6 +540,8 @@ glob_vector (pat, dir, flags)
       if (extended_glob)
        mflags |= FNM_EXTMATCH;
 
+      add_current = ((flags & (GX_ALLDIRS|GX_ADDCURDIR)) == (GX_ALLDIRS|GX_ADDCURDIR));
+
       /* Scan the directory, finding all names that match.
         For each name that matches, allocate a struct globval
         on the stack and store the name in it.
@@ -490,13 +569,69 @@ glob_vector (pat, dir, flags)
 #endif
 
 #if HANDLE_MULTIBYTE
-         if (MB_CUR_MAX > 1 && mbskipname (pat, dp->d_name))
+         if (MB_CUR_MAX > 1 && mbskipname (pat, dp->d_name, flags))
            continue;
          else
 #endif
-         if (skipname (pat, dp->d_name))
+         if (skipname (pat, dp->d_name, flags))
            continue;
 
+         /* If we're only interested in directories, don't bother with files */
+         if (flags & (GX_MATCHDIRS|GX_ALLDIRS))
+           {
+             pflags = (flags & GX_ALLDIRS) ? MP_RMDOT : 0;
+             if (flags & GX_NULLDIR)
+               pflags |= MP_IGNDOT;
+             subdir = sh_makepath (dir, dp->d_name, pflags);
+             isdir = glob_testdir (subdir);
+             if (isdir < 0 && (flags & GX_MATCHDIRS))
+               {
+                 free (subdir);
+                 continue;
+               }
+           }
+
+         if (flags & GX_ALLDIRS)
+           {
+             if (isdir == 0)
+               {
+                 dirlist = finddirs (pat, subdir, (flags & ~GX_ADDCURDIR), &e, &ndirs);
+                 if (dirlist == &finddirs_error_return)
+                   {
+                     free (subdir);
+                     lose = 1;
+                     break;
+                   }
+                 if (ndirs)            /* add recursive directories to list */
+                   {
+                     if (firstmalloc == 0)
+                       firstmalloc = e;
+                     e->next = lastlink;
+                     lastlink = dirlist;
+                     count += ndirs;
+                   }
+               }
+
+             nextlink = (struct globval *) malloc (sizeof (struct globval));
+             if (firstmalloc == 0)
+               firstmalloc = nextlink;
+             sdlen = strlen (subdir);
+             nextname = (char *) malloc (sdlen + 1);
+             if (nextlink == 0 || nextname == 0)
+               {
+                 free (subdir);
+                 lose = 1;
+                 break;
+               }
+             nextlink->next = lastlink;
+             lastlink = nextlink;
+             nextlink->name = nextname;
+             bcopy (subdir, nextname, sdlen + 1);
+             free (subdir);
+             ++count;
+             continue;
+           }
+             
          if (strmatch (pat, dp->d_name, mflags) != FNM_NOMATCH)
            {
              if (nalloca < ALLOCA_MAX)
@@ -510,6 +645,7 @@ glob_vector (pat, dir, flags)
                  if (firstmalloc == 0)
                    firstmalloc = nextlink;
                }
+
              nextname = (char *) malloc (D_NAMLEN (dp) + 1);
              if (nextlink == 0 || nextname == 0)
                {
@@ -527,6 +663,27 @@ glob_vector (pat, dir, flags)
       (void) closedir (d);
     }
 
+  /* compat: if GX_ALLDIRS, add the passed directory also */
+  if (add_current)
+    {
+      sdlen = strlen (dir);
+      nextname = (char *)malloc (sdlen + 1);
+      nextlink = (struct globval *) malloc (sizeof (struct globval));
+      if (nextlink == 0 || nextname == 0)
+       lose = 1;
+      else
+       {
+         nextlink->name = nextname;
+         nextlink->next = lastlink;
+         lastlink = nextlink;
+         if (flags & GX_NULLDIR)
+           nextname[0] = '\0';
+         else
+           bcopy (dir, nextname, sdlen + 1);
+         ++count;
+       }
+    }
+
   if (lose == 0)
     {
       name_vector = (char **) malloc ((count + 1) * sizeof (char *));
@@ -585,7 +742,7 @@ glob_vector (pat, dir, flags)
          free (tmplink);
        }
     }
-       
+
   return (name_vector);
 }
 
@@ -678,9 +835,10 @@ glob_filename (pathname, flags)
 {
   char **result;
   unsigned int result_size;
-  char *directory_name, *filename;
+  char *directory_name, *filename, *dname;
   unsigned int directory_len;
   int free_dirname;                    /* flag */
+  int dflags;
 
   result = (char **) malloc (sizeof (char *));
   result_size = 1;
@@ -721,10 +879,14 @@ glob_filename (pathname, flags)
       char **directories;
       register unsigned int i;
 
+      dflags = flags & ~GX_MARKDIRS;
+      if ((flags & GX_GLOBSTAR) && directory_name[0] == '*' && directory_name[1] == '*' && (directory_name[2] == '/' || directory_name[2] == '\0'))
+       dflags |= GX_ALLDIRS|GX_ADDCURDIR;
+
       if (directory_name[directory_len - 1] == '/')
        directory_name[directory_len - 1] = '\0';
 
-      directories = glob_filename (directory_name, flags & ~GX_MARKDIRS);
+      directories = glob_filename (directory_name, dflags);
 
       if (free_dirname)
        {
@@ -753,10 +915,19 @@ glob_filename (pathname, flags)
        {
          char **temp_results;
 
-         /* Scan directory even on a NULL pathname.  That way, `*h/'
+         /* Scan directory even on a NULL filename.  That way, `*h/'
             returns only directories ending in `h', instead of all
             files ending in `h' with a `/' appended. */
-         temp_results = glob_vector (filename, directories[i], flags & ~GX_MARKDIRS);
+         dname = directories[i];
+         dflags = flags & ~GX_MARKDIRS;
+         if ((flags & GX_GLOBSTAR) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0')
+           dflags |= GX_ALLDIRS|GX_ADDCURDIR;
+         if (dname[0] == '\0' && filename[0])
+           {
+             dflags |= GX_NULLDIR;
+             dname = ".";      /* treat null directory name and non-null filename as current directory */
+           }
+         temp_results = glob_vector (filename, dname, dflags);
 
          /* Handle error cases. */
          if (temp_results == NULL)
@@ -830,9 +1001,14 @@ glob_filename (pathname, flags)
 
       /* Just return what glob_vector () returns appended to the
         directory name. */
+      dflags = flags & ~GX_MARKDIRS;
+      if (directory_len == 0)
+       dflags |= GX_NULLDIR;
+      if ((flags & GX_GLOBSTAR) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0')
+       dflags |= GX_ALLDIRS|GX_ADDCURDIR;
       temp_results = glob_vector (filename,
                                  (directory_len == 0 ? "." : directory_name),
-                                 flags & ~GX_MARKDIRS);
+                                 dflags);
 
       if (temp_results == NULL || temp_results == (char **)&glob_error_return)
        {
@@ -841,7 +1017,7 @@ glob_filename (pathname, flags)
          return (temp_results);
        }
 
-      result = glob_dir_to_array (directory_name, temp_results, flags);
+      result = glob_dir_to_array ((dflags & GX_ALLDIRS) ? "" : directory_name, temp_results, flags);
       if (free_dirname)
        free (directory_name);
       return (result);
diff --git a/lib/glob/glob.c~ b/lib/glob/glob.c~
new file mode 100644 (file)
index 0000000..34d0172
--- /dev/null
@@ -0,0 +1,1067 @@
+/* glob.c -- file-name wildcard pattern matching for Bash.
+
+   Copyright (C) 1985-2006 Free Software Foundation, Inc.
+
+   This program 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.
+
+   This program 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 this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.  */
+
+/* To whomever it may concern: I have never seen the code which most
+   Unix programs use to perform this function.  I wrote this from scratch
+   based on specifications for the pattern matching.  --RMS.  */
+
+#include <config.h>
+
+#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX)
+  #pragma alloca
+#endif /* _AIX && RISC6000 && !__GNUC__ */
+
+#include "bashtypes.h"
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include "bashansi.h"
+#include "posixdir.h"
+#include "posixstat.h"
+#include "shmbutil.h"
+#include "xmalloc.h"
+
+#include "filecntl.h"
+#if !defined (F_OK)
+#  define F_OK 0
+#endif
+
+#include "stdc.h"
+#include "memalloc.h"
+
+#include "shell.h"
+
+#include "glob.h"
+#include "strmatch.h"
+
+#if !defined (HAVE_BCOPY) && !defined (bcopy)
+#  define bcopy(s, d, n) ((void) memcpy ((d), (s), (n)))
+#endif /* !HAVE_BCOPY && !bcopy */
+
+#if !defined (NULL)
+#  if defined (__STDC__)
+#    define NULL ((void *) 0)
+#  else
+#    define NULL 0x0
+#  endif /* __STDC__ */
+#endif /* !NULL */
+
+#if !defined (FREE)
+#  define FREE(x)      if (x) free (x)
+#endif
+
+/* Don't try to alloca() more than this much memory for `struct globval'
+   in glob_vector() */
+#ifndef ALLOCA_MAX
+#  define ALLOCA_MAX   100000
+#endif
+
+struct globval
+  {
+    struct globval *next;
+    char *name;
+  };
+
+extern void throw_to_top_level __P((void));
+extern int sh_eaccess __P((char *, int));
+extern char *sh_makepath __P((const char *, const char *, int));
+
+extern int extended_glob;
+
+/* Global variable which controls whether or not * matches .*.
+   Non-zero means don't match .*.  */
+int noglob_dot_filenames = 1;
+
+/* Global variable which controls whether or not filename globbing
+   is done without regard to case. */
+int glob_ignore_case = 0;
+
+/* Global variable to return to signify an error in globbing. */
+char *glob_error_return;
+
+static struct globval finddirs_error_return;
+
+/* Some forward declarations. */
+static int skipname __P((char *, char *, int));
+#if HANDLE_MULTIBYTE
+static int mbskipname __P((char *, char *, int));
+#endif
+#if HANDLE_MULTIBYTE
+static void udequote_pathname __P((char *));
+static void wdequote_pathname __P((char *));
+#else
+#  define dequote_pathname udequote_pathname
+#endif
+static void dequote_pathname __P((char *));
+static int glob_testdir __P((char *));
+static char **glob_dir_to_array __P((char *, char **, int));
+
+/* Compile `glob_loop.c' for single-byte characters. */
+#define CHAR   unsigned char
+#define INT    int
+#define L(CS)  CS
+#define INTERNAL_GLOB_PATTERN_P internal_glob_pattern_p
+#include "glob_loop.c"
+
+/* Compile `glob_loop.c' again for multibyte characters. */
+#if HANDLE_MULTIBYTE
+
+#define CHAR   wchar_t
+#define INT    wint_t
+#define L(CS)  L##CS
+#define INTERNAL_GLOB_PATTERN_P internal_glob_wpattern_p
+#include "glob_loop.c"
+
+#endif /* HANDLE_MULTIBYTE */
+
+/* And now a function that calls either the single-byte or multibyte version
+   of internal_glob_pattern_p. */
+int
+glob_pattern_p (pattern)
+     const char *pattern;
+{
+#if HANDLE_MULTIBYTE
+  size_t n;
+  wchar_t *wpattern;
+  int r;
+
+  if (MB_CUR_MAX == 1)
+    return (internal_glob_pattern_p ((unsigned char *)pattern));
+
+  /* Convert strings to wide chars, and call the multibyte version. */
+  n = xdupmbstowcs (&wpattern, NULL, pattern);
+  if (n == (size_t)-1)
+    /* Oops.  Invalid multibyte sequence.  Try it as single-byte sequence. */
+    return (internal_glob_pattern_p ((unsigned char *)pattern));
+
+  r = internal_glob_wpattern_p (wpattern);
+  free (wpattern);
+
+  return r;
+#else
+  return (internal_glob_pattern_p (pattern));
+#endif
+}
+
+/* Return 1 if DNAME should be skipped according to PAT.  Mostly concerned
+   with matching leading `.'. */
+
+static int
+skipname (pat, dname, flags)
+     char *pat;
+     char *dname;
+     int flags;
+{
+  /* If a leading dot need not be explicitly matched, and the pattern
+     doesn't start with a `.', don't match `.' or `..' */
+  if (noglob_dot_filenames == 0 && pat[0] != '.' &&
+       (pat[0] != '\\' || pat[1] != '.') &&
+       (dname[0] == '.' &&
+         (dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0'))))
+    return 1;
+
+  /* If a dot must be explicity matched, check to see if they do. */
+  else if (noglob_dot_filenames && dname[0] == '.' && pat[0] != '.' &&
+       (pat[0] != '\\' || pat[1] != '.'))
+    return 1;
+
+  return 0;
+}
+
+#if HANDLE_MULTIBYTE
+/* Return 1 if DNAME should be skipped according to PAT.  Handles multibyte
+   characters in PAT and DNAME.  Mostly concerned with matching leading `.'. */
+
+static int
+mbskipname (pat, dname, flags)
+     char *pat, *dname;
+     int flags;
+{
+  int ret;
+  wchar_t *pat_wc, *dn_wc;
+  size_t pat_n, dn_n;
+
+  pat_n = xdupmbstowcs (&pat_wc, NULL, pat);
+  dn_n = xdupmbstowcs (&dn_wc, NULL, dname);
+
+  ret = 0;
+  if (pat_n != (size_t)-1 && dn_n !=(size_t)-1)
+    {
+      /* If a leading dot need not be explicitly matched, and the
+        pattern doesn't start with a `.', don't match `.' or `..' */
+      if (noglob_dot_filenames == 0 && pat_wc[0] != L'.' &&
+           (pat_wc[0] != L'\\' || pat_wc[1] != L'.') &&
+           (dn_wc[0] == L'.' &&
+             (dn_wc[1] == L'\0' || (dn_wc[1] == L'.' && dn_wc[2] == L'\0'))))
+       ret = 1;
+
+      /* If a leading dot must be explicity matched, check to see if the
+        pattern and dirname both have one. */
+     else if (noglob_dot_filenames && dn_wc[0] == L'.' &&
+          pat_wc[0] != L'.' &&
+          (pat_wc[0] != L'\\' || pat_wc[1] != L'.'))
+       ret = 1;
+    }
+
+  FREE (pat_wc);
+  FREE (dn_wc);
+
+  return ret;
+}
+#endif /* HANDLE_MULTIBYTE */
+
+/* Remove backslashes quoting characters in PATHNAME by modifying PATHNAME. */
+static void
+udequote_pathname (pathname)
+     char *pathname;
+{
+  register int i, j;
+
+  for (i = j = 0; pathname && pathname[i]; )
+    {
+      if (pathname[i] == '\\')
+       i++;
+
+      pathname[j++] = pathname[i++];
+
+      if (pathname[i - 1] == 0)
+       break;
+    }
+  pathname[j] = '\0';
+}
+
+#if HANDLE_MULTIBYTE
+/* Remove backslashes quoting characters in PATHNAME by modifying PATHNAME. */
+static void
+wdequote_pathname (pathname)
+     char *pathname;
+{
+  mbstate_t ps;
+  size_t len, n;
+  wchar_t *wpathname;
+  int i, j;
+  wchar_t *orig_wpathname;
+
+  len = strlen (pathname);
+  /* Convert the strings into wide characters.  */
+  n = xdupmbstowcs (&wpathname, NULL, pathname);
+  if (n == (size_t) -1)
+    /* Something wrong. */
+    return;
+  orig_wpathname = wpathname;
+
+  for (i = j = 0; wpathname && wpathname[i]; )
+    {
+      if (wpathname[i] == L'\\')
+       i++;
+
+      wpathname[j++] = wpathname[i++];
+
+      if (wpathname[i - 1] == L'\0')
+       break;
+    }
+  wpathname[j] = L'\0';
+
+  /* Convert the wide character string into unibyte character set. */
+  memset (&ps, '\0', sizeof(mbstate_t));
+  n = wcsrtombs(pathname, (const wchar_t **)&wpathname, len, &ps);
+  pathname[len] = '\0';
+
+  /* Can't just free wpathname here; wcsrtombs changes it in many cases. */
+  free (orig_wpathname);
+}
+
+static void
+dequote_pathname (pathname)
+     char *pathname;
+{
+  if (MB_CUR_MAX > 1)
+    wdequote_pathname (pathname);
+  else
+    udequote_pathname (pathname);
+}
+#endif /* HANDLE_MULTIBYTE */
+
+/* Test whether NAME exists. */
+
+#if defined (HAVE_LSTAT)
+#  define GLOB_TESTNAME(name)  (lstat (name, &finfo))
+#else /* !HAVE_LSTAT */
+#  if !defined (AFS)
+#    define GLOB_TESTNAME(name)  (sh_eaccess (nextname, F_OK))
+#  else /* AFS */
+#    define GLOB_TESTNAME(name)  (access (nextname, F_OK))
+#  endif /* AFS */
+#endif /* !HAVE_LSTAT */
+
+/* Return 0 if DIR is a directory, -1 otherwise. */
+static int
+glob_testdir (dir)
+     char *dir;
+{
+  struct stat finfo;
+
+  if (stat (dir, &finfo) < 0)
+    return (-1);
+
+  if (S_ISDIR (finfo.st_mode) == 0)
+    return (-1);
+
+  return (0);
+}
+
+/* Recursively scan SDIR for directories matching PAT (PAT is always `**').
+   FLAGS is simply passed down to the recursive call to glob_vector.  Returns
+   a list of matching directory names.  EP, if non-null, is set to the last
+   element of the returned list.  NP, if non-null, is set to the number of
+   directories in the returned list.  These two variables exist for the
+   convenience of the caller (always glob_vector). */
+static struct globval *
+finddirs (pat, sdir, flags, ep, np)
+     char *pat;
+     char *sdir;
+     int flags;
+     struct globval **ep;
+     int *np;
+{
+  char **r, *n;
+  int ndirs;
+  struct globval *ret, *e, *g;
+
+/*itrace("finddirs: pat = `%s' sdir = `%s' flags = 0x%x", pat, sdir, flags);*/
+  e = ret = 0;
+  r = glob_vector (pat, sdir, flags);
+  if (r == 0 || r[0] == 0)
+    {
+      if (np)
+       *np = 0;
+      if (ep)
+        *ep = 0;
+      if (r)
+       free (r);
+      return (struct globval *)0;
+    }
+  for (ndirs = 0; r[ndirs] != 0; ndirs++)
+    {
+      g = (struct globval *) malloc (sizeof (struct globval));
+      if (g == 0)
+       {
+         while (ret)           /* free list built so far */
+           {
+             g = ret->next;
+             free (ret);
+             ret = g;
+           }
+
+         free (r);
+         if (np)
+           *np = 0;
+         if (ep)
+           *ep = 0;
+         return (&finddirs_error_return);
+       }
+      if (e == 0)
+       e = g;
+
+      g->next = ret;
+      ret = g;
+
+      g->name = r[ndirs];
+    }
+
+  free (r);
+  if (ep)
+    *ep = e;
+  if (np)
+    *np = ndirs;
+
+  return ret;
+}
+
+       
+/* Return a vector of names of files in directory DIR
+   whose names match glob pattern PAT.
+   The names are not in any particular order.
+   Wildcards at the beginning of PAT do not match an initial period.
+
+   The vector is terminated by an element that is a null pointer.
+
+   To free the space allocated, first free the vector's elements,
+   then free the vector.
+
+   Return 0 if cannot get enough memory to hold the pointer
+   and the names.
+
+   Return -1 if cannot access directory DIR.
+   Look in errno for more information.  */
+
+char **
+glob_vector (pat, dir, flags)
+     char *pat;
+     char *dir;
+     int flags;
+{
+  DIR *d;
+  register struct dirent *dp;
+  struct globval *lastlink, *e, *dirlist;
+  register struct globval *nextlink;
+  register char *nextname, *npat, *subdir;
+  unsigned int count;
+  int lose, skip, ndirs, isdir, sdlen, add_current;
+  register char **name_vector;
+  register unsigned int i;
+  int mflags;          /* Flags passed to strmatch (). */
+  int pflags;          /* flags passed to sh_makepath () */
+  int nalloca;
+  struct globval *firstmalloc, *tmplink;
+
+  lastlink = 0;
+  count = lose = skip = add_current = 0;
+
+  firstmalloc = 0;
+  nalloca = 0;
+
+/*itrace("glob_vector: pat = `%s' dir = `%s' flags = 0x%x", pat, dir, flags);*/
+  /* If PAT is empty, skip the loop, but return one (empty) filename. */
+  if (pat == 0 || *pat == '\0')
+    {
+      if (glob_testdir (dir) < 0)
+       return ((char **) &glob_error_return);
+
+      nextlink = (struct globval *)alloca (sizeof (struct globval));
+      if (nextlink == NULL)
+       return ((char **) NULL);
+
+      nextlink->next = (struct globval *)0;
+      nextname = (char *) malloc (1);
+      if (nextname == 0)
+       lose = 1;
+      else
+       {
+         lastlink = nextlink;
+         nextlink->name = nextname;
+         nextname[0] = '\0';
+         count = 1;
+       }
+
+      skip = 1;
+    }
+
+  /* If the filename pattern (PAT) does not contain any globbing characters,
+     we can dispense with reading the directory, and just see if there is
+     a filename `DIR/PAT'.  If there is, and we can access it, just make the
+     vector to return and bail immediately. */
+  if (skip == 0 && glob_pattern_p (pat) == 0)
+    {
+      int dirlen;
+      struct stat finfo;
+
+      if (glob_testdir (dir) < 0)
+       return ((char **) &glob_error_return);
+
+      dirlen = strlen (dir);
+      nextname = (char *)malloc (dirlen + strlen (pat) + 2);
+      npat = (char *)malloc (strlen (pat) + 1);
+      if (nextname == 0 || npat == 0)
+       lose = 1;
+      else
+       {
+         strcpy (npat, pat);
+         dequote_pathname (npat);
+
+         strcpy (nextname, dir);
+         nextname[dirlen++] = '/';
+         strcpy (nextname + dirlen, npat);
+
+         if (GLOB_TESTNAME (nextname) >= 0)
+           {
+             free (nextname);
+             nextlink = (struct globval *)alloca (sizeof (struct globval));
+             if (nextlink)
+               {
+                 nextlink->next = (struct globval *)0;
+                 lastlink = nextlink;
+                 nextlink->name = npat;
+                 count = 1;
+               }
+             else
+               lose = 1;
+           }
+         else
+           {
+             free (nextname);
+             free (npat);
+           }
+       }
+
+      skip = 1;
+    }
+
+  if (skip == 0)
+    {
+      /* Open the directory, punting immediately if we cannot.  If opendir
+        is not robust (i.e., it opens non-directories successfully), test
+        that DIR is a directory and punt if it's not. */
+#if defined (OPENDIR_NOT_ROBUST)
+      if (glob_testdir (dir) < 0)
+       return ((char **) &glob_error_return);
+#endif
+
+      d = opendir (dir);
+      if (d == NULL)
+       return ((char **) &glob_error_return);
+
+      /* Compute the flags that will be passed to strmatch().  We don't
+        need to do this every time through the loop. */
+      mflags = (noglob_dot_filenames ? FNM_PERIOD : 0) | FNM_PATHNAME;
+
+#ifdef FNM_CASEFOLD
+      if (glob_ignore_case)
+       mflags |= FNM_CASEFOLD;
+#endif
+
+      if (extended_glob)
+       mflags |= FNM_EXTMATCH;
+
+      add_current = ((flags & (GX_ALLDIRS|GX_ADDCURDIR)) == (GX_ALLDIRS|GX_ADDCURDIR));
+
+      /* Scan the directory, finding all names that match.
+        For each name that matches, allocate a struct globval
+        on the stack and store the name in it.
+        Chain those structs together; lastlink is the front of the chain.  */
+      while (1)
+       {
+         /* Make globbing interruptible in the shell. */
+         if (interrupt_state || terminating_signal)
+           {
+             lose = 1;
+             break;
+           }
+         
+         dp = readdir (d);
+         if (dp == NULL)
+           break;
+
+         /* If this directory entry is not to be used, try again. */
+         if (REAL_DIR_ENTRY (dp) == 0)
+           continue;
+
+#if 0
+         if (dp->d_name == 0 || *dp->d_name == 0)
+           continue;
+#endif
+
+#if HANDLE_MULTIBYTE
+         if (MB_CUR_MAX > 1 && mbskipname (pat, dp->d_name, flags))
+           continue;
+         else
+#endif
+         if (skipname (pat, dp->d_name, flags))
+           continue;
+
+         /* If we're only interested in directories, don't bother with files */
+         if (flags & (GX_MATCHDIRS|GX_ALLDIRS))
+           {
+             pflags = (flags & GX_ALLDIRS) ? MP_RMDOT : 0;
+             if (flags & GX_NULLDIR)
+               pflags |= MP_IGNDOT;
+             subdir = sh_makepath (dir, dp->d_name, pflags);
+             isdir = glob_testdir (subdir);
+             if (isdir < 0 && (flags & GX_MATCHDIRS))
+               {
+                 free (subdir);
+                 continue;
+               }
+           }
+
+         if (flags & GX_ALLDIRS)
+           {
+             if (isdir == 0)
+               {
+                 dirlist = finddirs (pat, subdir, (flags & ~GX_ADDCURDIR), &e, &ndirs);
+                 if (dirlist == &finddirs_error_return)
+                   {
+                     free (subdir);
+                     lose = 1;
+                     break;
+                   }
+                 if (ndirs)            /* add recursive directories to list */
+                   {
+                     if (firstmalloc == 0)
+                       firstmalloc = e;
+                     e->next = lastlink;
+                     lastlink = dirlist;
+                     count += ndirs;
+                   }
+               }
+
+             nextlink = (struct globval *) malloc (sizeof (struct globval));
+             if (firstmalloc == 0)
+               firstmalloc = nextlink;
+             sdlen = strlen (subdir);
+             nextname = (char *) malloc (sdlen + 1);
+             if (nextlink == 0 || nextname == 0)
+               {
+                 free (subdir);
+                 lose = 1;
+                 break;
+               }
+             nextlink->next = lastlink;
+             lastlink = nextlink;
+             nextlink->name = nextname;
+             bcopy (subdir, nextname, sdlen + 1);
+             free (subdir);
+             ++count;
+             continue;
+           }
+             
+         if (strmatch (pat, dp->d_name, mflags) != FNM_NOMATCH)
+           {
+             if (nalloca < ALLOCA_MAX)
+               {
+                 nextlink = (struct globval *) alloca (sizeof (struct globval));
+                 nalloca += sizeof (struct globval);
+               }
+             else
+               {
+                 nextlink = (struct globval *) malloc (sizeof (struct globval));
+                 if (firstmalloc == 0)
+                   firstmalloc = nextlink;
+               }
+
+             nextname = (char *) malloc (D_NAMLEN (dp) + 1);
+             if (nextlink == 0 || nextname == 0)
+               {
+                 lose = 1;
+                 break;
+               }
+             nextlink->next = lastlink;
+             lastlink = nextlink;
+             nextlink->name = nextname;
+             bcopy (dp->d_name, nextname, D_NAMLEN (dp) + 1);
+             ++count;
+           }
+       }
+
+      (void) closedir (d);
+    }
+
+  /* compat: if GX_ALLDIRS, add the passed directory also */
+  if (add_current)
+    {
+      sdlen = strlen (dir);
+      nextname = (char *)malloc (sdlen + 1);
+      nextlink = (struct globval *) malloc (sizeof (struct globval));
+      if (nextlink == 0 || nextname == 0)
+       lose = 1;
+      else
+       {
+         nextlink->name = nextname;
+         nextlink->next = lastlink;
+         lastlink = nextlink;
+         if (flags & GX_NULLDIR)
+           nextname[0] = '\0';
+         else
+           bcopy (dir, nextname, sdlen + 1);
+         ++count;
+       }
+    }
+
+  if (lose == 0)
+    {
+      name_vector = (char **) malloc ((count + 1) * sizeof (char *));
+      lose |= name_vector == NULL;
+    }
+
+  /* Have we run out of memory?         */
+  if (lose)
+    {
+      tmplink = 0;
+
+      /* Here free the strings we have got.  */
+      while (lastlink)
+       {
+         /* Since we build the list in reverse order, the first N entries
+            will be allocated with malloc, if firstmalloc is set, from
+            lastlink to firstmalloc. */
+         if (firstmalloc)
+           {
+             if (lastlink == firstmalloc)
+               firstmalloc = 0;
+             tmplink = lastlink;
+           }
+         else
+           tmplink = 0;
+         free (lastlink->name);
+         lastlink = lastlink->next;
+         FREE (tmplink);
+       }
+
+      QUIT;
+
+      return ((char **)NULL);
+    }
+
+  /* Copy the name pointers from the linked list into the vector.  */
+  for (tmplink = lastlink, i = 0; i < count; ++i)
+    {
+      name_vector[i] = tmplink->name;
+      tmplink = tmplink->next;
+    }
+
+  name_vector[count] = NULL;
+
+  /* If we allocated some of the struct globvals, free them now. */
+  if (firstmalloc)
+    {
+      tmplink = 0;
+      while (lastlink)
+       {
+         tmplink = lastlink;
+         if (lastlink == firstmalloc)
+           lastlink = firstmalloc = 0;
+         else
+           lastlink = lastlink->next;
+         free (tmplink);
+       }
+    }
+
+  return (name_vector);
+}
+
+/* Return a new array which is the concatenation of each string in ARRAY
+   to DIR.  This function expects you to pass in an allocated ARRAY, and
+   it takes care of free()ing that array.  Thus, you might think of this
+   function as side-effecting ARRAY.  This should handle GX_MARKDIRS. */
+static char **
+glob_dir_to_array (dir, array, flags)
+     char *dir, **array;
+     int flags;
+{
+  register unsigned int i, l;
+  int add_slash;
+  char **result, *new;
+  struct stat sb;
+
+  l = strlen (dir);
+  if (l == 0)
+    {
+      if (flags & GX_MARKDIRS)
+       for (i = 0; array[i]; i++)
+         {
+           if ((stat (array[i], &sb) == 0) && S_ISDIR (sb.st_mode))
+             {
+               l = strlen (array[i]);
+               new = (char *)realloc (array[i], l + 2);
+               if (new == 0)
+                 return NULL;
+               new[l] = '/';
+               new[l+1] = '\0';
+               array[i] = new;
+             }
+         }
+      return (array);
+    }
+
+  add_slash = dir[l - 1] != '/';
+
+  i = 0;
+  while (array[i] != NULL)
+    ++i;
+
+  result = (char **) malloc ((i + 1) * sizeof (char *));
+  if (result == NULL)
+    return (NULL);
+
+  for (i = 0; array[i] != NULL; i++)
+    {
+      /* 3 == 1 for NUL, 1 for slash at end of DIR, 1 for GX_MARKDIRS */
+      result[i] = (char *) malloc (l + strlen (array[i]) + 3);
+
+      if (result[i] == NULL)
+       return (NULL);
+
+      strcpy (result[i], dir);
+      if (add_slash)
+       result[i][l] = '/';
+      strcpy (result[i] + l + add_slash, array[i]);
+      if (flags & GX_MARKDIRS)
+       {
+         if ((stat (result[i], &sb) == 0) && S_ISDIR (sb.st_mode))
+           {
+             size_t rlen;
+             rlen = strlen (result[i]);
+             result[i][rlen] = '/';
+             result[i][rlen+1] = '\0';
+           }
+       }
+    }
+  result[i] = NULL;
+
+  /* Free the input array.  */
+  for (i = 0; array[i] != NULL; i++)
+    free (array[i]);
+  free ((char *) array);
+
+  return (result);
+}
+
+/* Do globbing on PATHNAME.  Return an array of pathnames that match,
+   marking the end of the array with a null-pointer as an element.
+   If no pathnames match, then the array is empty (first element is null).
+   If there isn't enough memory, then return NULL.
+   If a file system error occurs, return -1; `errno' has the error code.  */
+char **
+glob_filename (pathname, flags)
+     char *pathname;
+     int flags;
+{
+  char **result;
+  unsigned int result_size;
+  char *directory_name, *filename, *dname;
+  unsigned int directory_len;
+  int free_dirname;                    /* flag */
+  int dflags;
+
+  result = (char **) malloc (sizeof (char *));
+  result_size = 1;
+  if (result == NULL)
+    return (NULL);
+
+  result[0] = NULL;
+
+  directory_name = NULL;
+
+  /* Find the filename.  */
+  filename = strrchr (pathname, '/');
+  if (filename == NULL)
+    {
+      filename = pathname;
+      directory_name = "";
+      directory_len = 0;
+      free_dirname = 0;
+    }
+  else
+    {
+      directory_len = (filename - pathname) + 1;
+      directory_name = (char *) malloc (directory_len + 1);
+
+      if (directory_name == 0)         /* allocation failed? */
+       return (NULL);
+
+      bcopy (pathname, directory_name, directory_len);
+      directory_name[directory_len] = '\0';
+      ++filename;
+      free_dirname = 1;
+    }
+
+  /* If directory_name contains globbing characters, then we
+     have to expand the previous levels.  Just recurse. */
+  if (glob_pattern_p (directory_name))
+    {
+      char **directories;
+      register unsigned int i;
+
+      dflags = flags & ~GX_MARKDIRS;
+      if ((flags & GX_GLOBSTAR) && directory_name[0] == '*' && directory_name[1] == '*' && (directory_name[2] == '/' || directory_name[2] == '\0'))
+       dflags |= GX_ALLDIRS|GX_ADDCURDIR;
+
+      if (directory_name[directory_len - 1] == '/')
+       directory_name[directory_len - 1] = '\0';
+
+      directories = glob_filename (directory_name, dflags);
+
+      if (free_dirname)
+       {
+         free (directory_name);
+         directory_name = NULL;
+       }
+
+      if (directories == NULL)
+       goto memory_error;
+      else if (directories == (char **)&glob_error_return)
+       {
+         free ((char *) result);
+         return ((char **) &glob_error_return);
+       }
+      else if (*directories == NULL)
+       {
+         free ((char *) directories);
+         free ((char *) result);
+         return ((char **) &glob_error_return);
+       }
+
+      /* We have successfully globbed the preceding directory name.
+        For each name in DIRECTORIES, call glob_vector on it and
+        FILENAME.  Concatenate the results together.  */
+      for (i = 0; directories[i] != NULL; ++i)
+       {
+         char **temp_results;
+
+         /* Scan directory even on a NULL filename.  That way, `*h/'
+            returns only directories ending in `h', instead of all
+            files ending in `h' with a `/' appended. */
+         dname = directories[i];
+         dflags = flags & ~GX_MARKDIRS;
+         if ((flags & GX_GLOBSTAR) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0')
+           dflags |= GX_ALLDIRS|GX_ADDCURDIR;
+         if (dname[0] == '\0' && filename[0])
+           {
+             dflags |= GX_NULLDIR;
+             dname = ".";      /* treat null directory name and non-null filename as current directory */
+           }
+         temp_results = glob_vector (filename, dname, dflags);
+
+         /* Handle error cases. */
+         if (temp_results == NULL)
+           goto memory_error;
+         else if (temp_results == (char **)&glob_error_return)
+           /* This filename is probably not a directory.  Ignore it.  */
+           ;
+         else
+           {
+             char **array;
+             register unsigned int l;
+
+             array = glob_dir_to_array (directories[i], temp_results, flags);
+             l = 0;
+             while (array[l] != NULL)
+               ++l;
+
+             result =
+               (char **)realloc (result, (result_size + l) * sizeof (char *));
+
+             if (result == NULL)
+               goto memory_error;
+
+             for (l = 0; array[l] != NULL; ++l)
+               result[result_size++ - 1] = array[l];
+
+             result[result_size - 1] = NULL;
+
+             /* Note that the elements of ARRAY are not freed.  */
+             free ((char *) array);
+           }
+       }
+      /* Free the directories.  */
+      for (i = 0; directories[i]; i++)
+       free (directories[i]);
+
+      free ((char *) directories);
+
+      return (result);
+    }
+
+  /* If there is only a directory name, return it. */
+  if (*filename == '\0')
+    {
+      result = (char **) realloc ((char *) result, 2 * sizeof (char *));
+      if (result == NULL)
+       return (NULL);
+      /* Handle GX_MARKDIRS here. */
+      result[0] = (char *) malloc (directory_len + 1);
+      if (result[0] == NULL)
+       goto memory_error;
+      bcopy (directory_name, result[0], directory_len + 1);
+      if (free_dirname)
+       free (directory_name);
+      result[1] = NULL;
+      return (result);
+    }
+  else
+    {
+      char **temp_results;
+
+      /* There are no unquoted globbing characters in DIRECTORY_NAME.
+        Dequote it before we try to open the directory since there may
+        be quoted globbing characters which should be treated verbatim. */
+      if (directory_len > 0)
+       dequote_pathname (directory_name);
+
+      /* We allocated a small array called RESULT, which we won't be using.
+        Free that memory now. */
+      free (result);
+
+      /* Just return what glob_vector () returns appended to the
+        directory name. */
+      dflags = flags & ~GX_MARKDIRS;
+      if (directory_len == 0)
+       dflags |= GX_NULLDIR;
+      if ((flags & GX_GLOBSTAR) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0')
+       dflags |= GX_ALLDIRS|GX_ADDCURDIR;
+      temp_results = glob_vector (filename,
+                                 (directory_len == 0 ? "." : directory_name),
+                                 dflags);
+
+      if (temp_results == NULL || temp_results == (char **)&glob_error_return)
+       {
+         if (free_dirname)
+           free (directory_name);
+         return (temp_results);
+       }
+
+      result = glob_dir_to_array ((dflags & GX_ALLDIRS) ? "" : directory_name, temp_results, flags);
+      if (free_dirname)
+       free (directory_name);
+      return (result);
+    }
+
+  /* We get to memory_error if the program has run out of memory, or
+     if this is the shell, and we have been interrupted. */
+ memory_error:
+  if (result != NULL)
+    {
+      register unsigned int i;
+      for (i = 0; result[i] != NULL; ++i)
+       free (result[i]);
+      free ((char *) result);
+    }
+
+  if (free_dirname && directory_name)
+    free (directory_name);
+
+  QUIT;
+
+  return (NULL);
+}
+
+#if defined (TEST)
+
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  unsigned int i;
+
+  for (i = 1; i < argc; ++i)
+    {
+      char **value = glob_filename (argv[i], 0);
+      if (value == NULL)
+       puts ("Out of memory.");
+      else if (value == &glob_error_return)
+       perror (argv[i]);
+      else
+       for (i = 0; value[i] != NULL; i++)
+         puts (value[i]);
+    }
+
+  exit (0);
+}
+#endif /* TEST.  */
index 6372a08f70e5c3fffc5efbc40e40eecef25d231e..720e4edfd3286d2eaf0c5be6fbd6d9f65affc5f6 100644 (file)
 #define GX_MARKDIRS    0x001   /* mark directory names with trailing `/' */
 #define GX_NOCASE      0x002   /* ignore case */
 #define GX_MATCHDOT    0x004   /* match `.' literally */
-#define GX_ALLDIRS     0x008   /* match all directories */
-#define GX_MATCHDIRS   0x010   /* return only matching directory names */
+#define GX_MATCHDIRS   0x008   /* match only directory names */
+#define GX_ALLDIRS     0x010   /* match all directory names, no others */
+#define GX_NULLDIR     0x100   /* internal -- no directory preceding pattern */
+#define GX_ADDCURDIR   0x200   /* internal -- add passed directory name */
+#define GX_GLOBSTAR    0x400   /* turn on special handling of ** */
 
 extern int glob_pattern_p __P((const char *));
 extern char **glob_vector __P((char *, char *, int));
index 325d442a8565b215c81284b40e47faa2eca7a19e..19c5f9dcda5f6eb69013a21450d410f44e1ddbd0 100644 (file)
@@ -317,7 +317,7 @@ rl_macro_bind (keyseq, macro, map)
 
   if (rl_translate_keyseq (macro, macro_keys, &macro_keys_len))
     {
-      free (macro_keys);
+      xfree (macro_keys);
       return -1;
     }
   rl_generic_bind (ISMACR, keyseq, macro_keys, map);
@@ -347,7 +347,7 @@ rl_generic_bind (type, keyseq, data, map)
   if (keyseq == 0 || *keyseq == 0)
     {
       if (type == ISMACR)
-       free (data);
+       xfree (data);
       return -1;
     }
 
@@ -358,7 +358,7 @@ rl_generic_bind (type, keyseq, data, map)
      KEYS into KEYS_LEN. */
   if (rl_translate_keyseq (keyseq, keys, &keys_len))
     {
-      free (keys);
+      xfree (keys);
       return -1;
     }
 
@@ -371,7 +371,7 @@ rl_generic_bind (type, keyseq, data, map)
       ic = uc;
       if (ic < 0 || ic >= KEYMAP_SIZE)
         {
-          free (keys);
+          xfree (keys);
          return -1;
         }
 
@@ -414,7 +414,7 @@ rl_generic_bind (type, keyseq, data, map)
       else
        {
          if (map[ic].type == ISMACR)
-           free ((char *)map[ic].function);
+           xfree ((char *)map[ic].function);
          else if (map[ic].type == ISKMAP)
            {
              map = FUNCTION_TO_KEYMAP (map, ic);
@@ -427,7 +427,7 @@ rl_generic_bind (type, keyseq, data, map)
 
       rl_binding_keymap = map;
     }
-  free (keys);
+  xfree (keys);
   return 0;
 }
 
@@ -793,7 +793,7 @@ _rl_read_file (filename, sizep)
 
   if (i < 0)
     {
-      free (buffer);
+      xfree (buffer);
       return ((char *)NULL);
     }
 
@@ -863,7 +863,7 @@ _rl_read_init_file (filename, include_level)
 
   openname = tilde_expand (filename);
   buffer = _rl_read_file (openname, &file_size);
-  free (openname);
+  xfree (openname);
 
   if (buffer == 0)
     return (errno);
@@ -911,7 +911,7 @@ _rl_read_init_file (filename, include_level)
       current_readline_init_lineno++;
     }
 
-  free (buffer);
+  xfree (buffer);
   currently_reading_init_file = 0;
   return (0);
 }
@@ -1002,7 +1002,7 @@ parser_if (args)
         `$if term=sun-cmd' into their .inputrc. */
       _rl_parsing_conditionalized_out = _rl_stricmp (args + 5, tname) &&
                                        _rl_stricmp (args + 5, rl_terminal_name);
-      free (tname);
+      xfree (tname);
     }
 #if defined (VI_MODE)
   else if (_rl_strnicmp (args, "mode=", 5) == 0)
@@ -1352,7 +1352,7 @@ rl_parse_and_bind (string)
       else
        rl_bind_keyseq (seq, rl_named_function (funname));
 
-      free (seq);
+      xfree (seq);
       return 0;
     }
 
@@ -1695,7 +1695,7 @@ sv_isrchterm (value)
   rl_translate_keyseq (v + beg, _rl_isearch_terminators, &end);
   _rl_isearch_terminators[end] = '\0';
 
-  free (v);
+  xfree (v);
   return 0;
 }
       
@@ -1856,7 +1856,7 @@ rl_list_funmap_names ()
   for (i = 0; funmap_names[i]; i++)
     fprintf (rl_outstream, "%s\n", funmap_names[i]);
 
-  free (funmap_names);
+  xfree (funmap_names);
 }
 
 static char *
@@ -2022,7 +2022,7 @@ rl_invoking_keyseqs_in_map (function, map)
                  }
                
                strcat (keyname, seqs[i]);
-               free (seqs[i]);
+               xfree (seqs[i]);
 
                if (result_index + 2 > result_size)
                  {
@@ -2034,7 +2034,7 @@ rl_invoking_keyseqs_in_map (function, map)
                result[result_index] = (char *)NULL;
              }
 
-           free (seqs);
+           xfree (seqs);
          }
          break;
        }
@@ -2086,10 +2086,10 @@ rl_function_dumper (print_readably)
                {
                  fprintf (rl_outstream, "\"%s\": %s\n",
                           invokers[j], name);
-                 free (invokers[j]);
+                 xfree (invokers[j]);
                }
 
-             free (invokers);
+             xfree (invokers);
            }
        }
       else
@@ -2113,9 +2113,9 @@ rl_function_dumper (print_readably)
                fprintf (rl_outstream, "...\n");
 
              for (j = 0; invokers[j]; j++)
-               free (invokers[j]);
+               xfree (invokers[j]);
 
-             free (invokers);
+             xfree (invokers);
            }
        }
     }
@@ -2161,8 +2161,8 @@ _rl_macro_dumper_internal (print_readably, map, prefix)
            fprintf (rl_outstream, "%s%s outputs %s\n", prefix ? prefix : "",
                                                        keyname,
                                                        out ? out : "");
-         free (keyname);
-         free (out);
+         xfree (keyname);
+         xfree (out);
          break;
        case ISFUNC:
          break;
@@ -2185,13 +2185,13 @@ _rl_macro_dumper_internal (print_readably, map, prefix)
                  out = (char *)xmalloc (strlen (keyname) + prefix_len + 1);
                  strcpy (out, prefix);
                  strcpy (out + prefix_len, keyname);
-                 free (keyname);
+                 xfree (keyname);
                  keyname = out;
                }
            }
 
          _rl_macro_dumper_internal (print_readably, FUNCTION_TO_KEYMAP (map, key), keyname);
-         free (keyname);
+         xfree (keyname);
          break;
        }
     }
@@ -2252,7 +2252,7 @@ _rl_get_string_variable_value (name)
       if (ret)
        {
          strncpy (numbuf, ret, sizeof (numbuf) - 1);
-         free (ret);
+         xfree (ret);
          numbuf[sizeof(numbuf) - 1] = '\0';
        }
       else
index b0a8895807ed0b541a62e2ffc64f395e84320ae0..325d442a8565b215c81284b40e47faa2eca7a19e 100644 (file)
@@ -1709,7 +1709,7 @@ sv_histsize (value)
     {
       nval = atoi (value);
       if (nval < 0)
-       nval = 0;
+       return 1;
     }
   stifle_history (nval);
   return 0;
index 4a52d7fca9ebd0f73c79473eb9e5f6391c832910..fc3f1fd1f6495ed2d040cdb84efd9528d26c11b1 100644 (file)
@@ -1,6 +1,6 @@
 /* complete.c -- filename completion for readline. */
 
-/* Copyright (C) 1987-2006 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2008 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.
@@ -188,6 +188,10 @@ int rl_complete_with_tilde_expansion = 0;
    completer. */
 rl_compentry_func_t *rl_completion_entry_function = (rl_compentry_func_t *)NULL;
 
+/* Pointer to generator function for rl_menu_complete ().  NULL means to use
+   *rl_completion_entry_function (see above). */
+rl_compentry_func_t *rl_menu_completion_entry_function = (rl_compentry_func_t *)NULL;
+
 /* Pointer to alternative function to create matches.
    Function is called with TEXT, START, and END.
    START and END are indices in RL_LINE_BUFFER saying what the boundaries
@@ -336,6 +340,9 @@ int rl_sort_completion_matches = 1;
 /* Local variable states what happened during the last completion attempt. */
 static int completion_changed_buffer;
 
+/* The result of the query to the user about displaying completion matches */
+static int completion_y_or_n;
+
 /*************************************/
 /*                                  */
 /*    Bindable completion functions  */
@@ -1186,8 +1193,7 @@ compute_lcd_of_matches (match_list, matches, text)
            }
 
          /* sort the list to get consistent answers. */
-         if (rl_sort_completion_matches)
-           qsort (match_list+1, matches, sizeof(char *), (QSFUNC *)_rl_qsort_string_compare);
+         qsort (match_list+1, matches, sizeof(char *), (QSFUNC *)_rl_qsort_string_compare);
 
          si = strlen (text);
          if (si <= low)
@@ -1433,7 +1439,7 @@ display_matches (matches)
       rl_crlf ();
       fprintf (rl_outstream, "Display all %d possibilities? (y or n)", len);
       fflush (rl_outstream);
-      if (get_y_or_n (0) == 0)
+      if ((completion_y_or_n = get_y_or_n (0)) == 0)
        {
          rl_crlf ();
 
@@ -2140,7 +2146,7 @@ rl_filename_completion_function (text, state)
    hit the end of the match list, we restore the original unmatched text,
    ring the bell, and reset the counter to zero. */
 int
-rl_menu_complete (count, invoking_key)
+rl_old_menu_complete (count, invoking_key)
      int count, invoking_key;
 {
   rl_compentry_func_t *our_func;
@@ -2171,7 +2177,9 @@ rl_menu_complete (count, invoking_key)
       /* Only the completion entry function can change these. */
       set_completion_defaults ('%');
 
-      our_func = rl_completion_entry_function
+      our_func = rl_menu_completion_entry_function;
+      if (our_func == 0)
+       our_func = rl_completion_entry_function
                        ? rl_completion_entry_function
                        : rl_filename_completion_function;
 
@@ -2212,6 +2220,10 @@ rl_menu_complete (count, invoking_key)
         ;
       /* matches[0] is lcd if match_list_size > 1, but the circular buffer
         code below should take care of it. */
+
+      if
+ (match_list_size > 1 && _rl_complete_show_all)
+       display_matches (matches);
     }
 
   /* Now we have the list of matches.  Replace the text between
@@ -2248,3 +2260,158 @@ rl_menu_complete (count, invoking_key)
   completion_changed_buffer = 1;
   return (0);
 }
+
+int
+rl_menu_complete (count, ignore)
+     int count, ignore;
+{
+  rl_compentry_func_t *our_func;
+  int matching_filenames, found_quote;
+
+  static char *orig_text;
+  static char **matches = (char **)0;
+  static int match_list_index = 0;
+  static int match_list_size = 0;
+  static int nontrivial_lcd = 0;
+  static int full_completion = 0;      /* set to 1 if menu completion should reinitialize on next call */
+  static int orig_start, orig_end;
+  static char quote_char;
+  static int delimiter;
+
+  /* The first time through, we generate the list of matches and set things
+     up to insert them. */
+  if (rl_last_func != rl_menu_complete || full_completion)
+    {
+      /* Clean up from previous call, if any. */
+      FREE (orig_text);
+      if (matches)
+       _rl_free_match_list (matches);
+
+      match_list_index = match_list_size = 0;
+      matches = (char **)NULL;
+
+      full_completion = 0;
+
+      /* Only the completion entry function can change these. */
+      set_completion_defaults ('%');
+
+      our_func = rl_menu_completion_entry_function;
+      if (our_func == 0)
+       our_func = rl_completion_entry_function
+                       ? rl_completion_entry_function
+                       : rl_filename_completion_function;
+
+      /* We now look backwards for the start of a filename/variable word. */
+      orig_end = rl_point;
+      found_quote = delimiter = 0;
+      quote_char = '\0';
+
+      if (rl_point)
+       /* This (possibly) changes rl_point.  If it returns a non-zero char,
+          we know we have an open quote. */
+       quote_char = _rl_find_completion_word (&found_quote, &delimiter);
+
+      orig_start = rl_point;
+      rl_point = orig_end;
+
+      orig_text = rl_copy_text (orig_start, orig_end);
+      matches = gen_completion_matches (orig_text, orig_start, orig_end,
+                                       our_func, found_quote, quote_char);
+
+      nontrivial_lcd = matches && strcmp (orig_text, matches[0]) != 0;
+
+      /* If we are matching filenames, the attempted completion function will
+        have set rl_filename_completion_desired to a non-zero value.  The basic
+        rl_filename_completion_function does this. */
+      matching_filenames = rl_filename_completion_desired;
+
+      if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0)
+       {
+         rl_ding ();
+         FREE (matches);
+         matches = (char **)0;
+         FREE (orig_text);
+         orig_text = (char *)0;
+         completion_changed_buffer = 0;
+          return (0);
+       }
+
+      for (match_list_size = 0; matches[match_list_size]; match_list_size++)
+        ;
+
+      if (match_list_size == 0) 
+       {
+         rl_ding ();
+         FREE (matches);
+         matches = (char **)0;
+         match_list_index = 0;
+         completion_changed_buffer = 0;
+         return (0);
+        }
+
+      /* matches[0] is lcd if match_list_size > 1, but the circular buffer
+        code below should take care of it. */
+      if (*matches[0])
+       {
+         insert_match (matches[0], orig_start, matches[1] ? MULT_MATCH : SINGLE_MATCH, &quote_char);
+         orig_end = orig_start + strlen (matches[0]);
+         completion_changed_buffer = STREQ (orig_text, matches[0]) == 0;
+       }
+
+      if (match_list_size > 1 && _rl_complete_show_all)
+       {
+         display_matches (matches);
+         /* If there are so many matches that the user has to be asked
+            whether or not he wants to see the matches, menu completion
+            is unwieldy. */
+         if (rl_completion_query_items > 0 && match_list_size >= rl_completion_query_items)
+           {
+             rl_ding ();
+             FREE (matches);
+             matches = (char **)0;
+             full_completion = 1;
+             return (0);
+           }
+       }
+      else if (match_list_size <= 1)
+       {
+         append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd);
+         full_completion = 1;
+         return (0);
+       }
+    }
+
+  /* Now we have the list of matches.  Replace the text between
+     rl_line_buffer[orig_start] and rl_line_buffer[rl_point] with
+     matches[match_list_index], and add any necessary closing char. */
+
+  if (matches == 0 || match_list_size == 0) 
+    {
+      rl_ding ();
+      FREE (matches);
+      matches = (char **)0;
+      completion_changed_buffer = 0;
+      return (0);
+    }
+
+  match_list_index += count;
+  if (match_list_index < 0)
+    match_list_index += match_list_size;
+  else
+    match_list_index %= match_list_size;
+
+  if (match_list_index == 0 && match_list_size > 1)
+    {
+      rl_ding ();
+      insert_match (matches[0], orig_start, MULT_MATCH, &quote_char);
+    }
+  else
+    {
+      insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, &quote_char);
+      append_to_match (matches[match_list_index], delimiter, quote_char,
+                      strcmp (orig_text, matches[match_list_index]));
+    }
+
+  completion_changed_buffer = 1;
+  return (0);
+}
index 194a0a09d8adceecb821afaf1f17440531a5b827..a8f8c56e1203b05020fa01e48a7e3f78cfae6df9 100644 (file)
@@ -1,6 +1,6 @@
 /* complete.c -- filename completion for readline. */
 
-/* Copyright (C) 1987-2006 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2008 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.
@@ -188,6 +188,10 @@ int rl_complete_with_tilde_expansion = 0;
    completer. */
 rl_compentry_func_t *rl_completion_entry_function = (rl_compentry_func_t *)NULL;
 
+/* Pointer to generator function for rl_menu_complete ().  NULL means to use
+   *rl_completion_entry_function (see above). */
+rl_compentry_func_t *rl_menu_completion_entry_function = (rl_compentry_func_t *)NULL;
+
 /* Pointer to alternative function to create matches.
    Function is called with TEXT, START, and END.
    START and END are indices in RL_LINE_BUFFER saying what the boundaries
@@ -336,6 +340,9 @@ int rl_sort_completion_matches = 1;
 /* Local variable states what happened during the last completion attempt. */
 static int completion_changed_buffer;
 
+/* The result of the query to the user about displaying completion matches */
+static int completion_y_or_n;
+
 /*************************************/
 /*                                  */
 /*    Bindable completion functions  */
@@ -405,7 +412,7 @@ rl_completion_mode (cfunc)
 /*                                 */
 /************************************/
 
-/* Reset readline state on a signal. */
+/* Reset readline state on a signal or other event. */
 void
 _rl_reset_completion_state ()
 {
@@ -1433,7 +1440,7 @@ display_matches (matches)
       rl_crlf ();
       fprintf (rl_outstream, "Display all %d possibilities? (y or n)", len);
       fflush (rl_outstream);
-      if (get_y_or_n (0) == 0)
+      if ((completion_y_or_n = get_y_or_n (0)) == 0)
        {
          rl_crlf ();
 
@@ -1705,6 +1712,7 @@ rl_complete_internal (what_to_do)
       FREE (saved_line_buffer);
       completion_changed_buffer = 0;
       RL_UNSETSTATE(RL_STATE_COMPLETING);
+      _rl_reset_completion_state ();
       return (0);
     }
 
@@ -1719,6 +1727,7 @@ rl_complete_internal (what_to_do)
       FREE (saved_line_buffer);
       completion_changed_buffer = 0;
       RL_UNSETSTATE(RL_STATE_COMPLETING);
+      _rl_reset_completion_state ();
       return (0);
     }
 
@@ -1773,6 +1782,7 @@ rl_complete_internal (what_to_do)
       rl_ding ();
       FREE (saved_line_buffer);
       RL_UNSETSTATE(RL_STATE_COMPLETING);
+      _rl_reset_completion_state ();
       return 1;
     }
 
@@ -1786,6 +1796,7 @@ rl_complete_internal (what_to_do)
     }
 
   RL_UNSETSTATE(RL_STATE_COMPLETING);
+  _rl_reset_completion_state ();
   return 0;
 }
 
@@ -2136,7 +2147,7 @@ rl_filename_completion_function (text, state)
    hit the end of the match list, we restore the original unmatched text,
    ring the bell, and reset the counter to zero. */
 int
-rl_menu_complete (count, invoking_key)
+rl_old_menu_complete (count, invoking_key)
      int count, invoking_key;
 {
   rl_compentry_func_t *our_func;
@@ -2167,7 +2178,9 @@ rl_menu_complete (count, invoking_key)
       /* Only the completion entry function can change these. */
       set_completion_defaults ('%');
 
-      our_func = rl_completion_entry_function
+      our_func = rl_menu_completion_entry_function;
+      if (our_func == 0)
+       our_func = rl_completion_entry_function
                        ? rl_completion_entry_function
                        : rl_filename_completion_function;
 
@@ -2208,6 +2221,9 @@ rl_menu_complete (count, invoking_key)
         ;
       /* matches[0] is lcd if match_list_size > 1, but the circular buffer
         code below should take care of it. */
+
+      if (match_list_size > 1 && _rl_complete_show_all)
+       display_matches (matches);
     }
 
   /* Now we have the list of matches.  Replace the text between
@@ -2244,3 +2260,158 @@ rl_menu_complete (count, invoking_key)
   completion_changed_buffer = 1;
   return (0);
 }
+
+int
+rl_menu_complete (count, ignore)
+     int count, ignore;
+{
+  rl_compentry_func_t *our_func;
+  int matching_filenames, found_quote;
+
+  static char *orig_text;
+  static char **matches = (char **)0;
+  static int match_list_index = 0;
+  static int match_list_size = 0;
+  static int nontrivial_lcd = 0;
+  static int full_completion = 0;      /* set to 1 if menu completion should reinitialize on next call */
+  static int orig_start, orig_end;
+  static char quote_char;
+  static int delimiter;
+
+  /* The first time through, we generate the list of matches and set things
+     up to insert them. */
+  if (rl_last_func != rl_menu_complete || full_completion)
+    {
+      /* Clean up from previous call, if any. */
+      FREE (orig_text);
+      if (matches)
+       _rl_free_match_list (matches);
+
+      match_list_index = match_list_size = 0;
+      matches = (char **)NULL;
+
+      full_completion = 0;
+
+      /* Only the completion entry function can change these. */
+      set_completion_defaults ('%');
+
+      our_func = rl_menu_completion_entry_function;
+      if (our_func == 0)
+       our_func = rl_completion_entry_function
+                       ? rl_completion_entry_function
+                       : rl_filename_completion_function;
+
+      /* We now look backwards for the start of a filename/variable word. */
+      orig_end = rl_point;
+      found_quote = delimiter = 0;
+      quote_char = '\0';
+
+      if (rl_point)
+       /* This (possibly) changes rl_point.  If it returns a non-zero char,
+          we know we have an open quote. */
+       quote_char = _rl_find_completion_word (&found_quote, &delimiter);
+
+      orig_start = rl_point;
+      rl_point = orig_end;
+
+      orig_text = rl_copy_text (orig_start, orig_end);
+      matches = gen_completion_matches (orig_text, orig_start, orig_end,
+                                       our_func, found_quote, quote_char);
+
+      nontrivial_lcd = matches && strcmp (orig_text, matches[0]) != 0;
+
+      /* If we are matching filenames, the attempted completion function will
+        have set rl_filename_completion_desired to a non-zero value.  The basic
+        rl_filename_completion_function does this. */
+      matching_filenames = rl_filename_completion_desired;
+
+      if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0)
+       {
+         rl_ding ();
+         FREE (matches);
+         matches = (char **)0;
+         FREE (orig_text);
+         orig_text = (char *)0;
+         completion_changed_buffer = 0;
+          return (0);
+       }
+
+      for (match_list_size = 0; matches[match_list_size]; match_list_size++)
+        ;
+
+      if (match_list_size == 0) 
+       {
+         rl_ding ();
+         FREE (matches);
+         matches = (char **)0;
+         match_list_index = 0;
+         completion_changed_buffer = 0;
+         return (0);
+        }
+
+      /* matches[0] is lcd if match_list_size > 1, but the circular buffer
+        code below should take care of it. */
+      if (*matches[0])
+       {
+         insert_match (matches[0], orig_start, matches[1] ? MULT_MATCH : SINGLE_MATCH, &quote_char);
+         orig_end = orig_start + strlen (matches[0]);
+         completion_changed_buffer = STREQ (orig_text, matches[0]) == 0;
+       }
+
+      if (match_list_size > 1 && _rl_complete_show_all)
+       {
+         display_matches (matches);
+         /* If there are so many matches that the user has to be asked
+            whether or not he wants to see the matches, menu completion
+            is unwieldy. */
+         if (rl_completion_query_items > 0 && match_list_size >= rl_completion_query_items)
+           {
+             rl_ding ();
+             FREE (matches);
+             matches = (char **)0;
+             full_completion = 1;
+             return (0);
+           }
+       }
+      else if (match_list_size <= 1)
+       {
+         append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd);
+         full_completion = 1;
+         return (0);
+       }
+    }
+
+  /* Now we have the list of matches.  Replace the text between
+     rl_line_buffer[orig_start] and rl_line_buffer[rl_point] with
+     matches[match_list_index], and add any necessary closing char. */
+
+  if (matches == 0 || match_list_size == 0) 
+    {
+      rl_ding ();
+      FREE (matches);
+      matches = (char **)0;
+      completion_changed_buffer = 0;
+      return (0);
+    }
+
+  match_list_index += count;
+  if (match_list_index < 0)
+    match_list_index += match_list_size;
+  else
+    match_list_index %= match_list_size;
+
+  if (match_list_index == 0 && match_list_size > 1)
+    {
+      rl_ding ();
+      insert_match (matches[0], orig_start, MULT_MATCH, &quote_char);
+    }
+  else
+    {
+      insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, &quote_char);
+      append_to_match (matches[match_list_index], delimiter, quote_char,
+                      strcmp (orig_text, matches[match_list_index]));
+    }
+
+  completion_changed_buffer = 1;
+  return (0);
+}
diff --git a/lib/readline/menucomp b/lib/readline/menucomp
new file mode 100644 (file)
index 0000000..c4deca5
--- /dev/null
@@ -0,0 +1,276 @@
+/* An initial implementation of a menu completion function a la tcsh.  The
+   first time (if the last readline command was not rl_menu_complete), we
+   generate the list of matches.  This code is very similar to the code in
+   rl_complete_internal -- there should be a way to combine the two.  Then,
+   for each item in the list of matches, we insert the match in an undoable
+   fashion, with the appropriate character appended (this happens on the
+   second and subsequent consecutive calls to rl_menu_complete).  When we
+   hit the end of the match list, we restore the original unmatched text,
+   ring the bell, and reset the counter to zero. */
+int
+rl_old_menu_complete (count, ignore)
+     int count, ignore;
+{
+  rl_compentry_func_t *our_func;
+  int matching_filenames, found_quote;
+
+  static char *orig_text;
+  static char **matches = (char **)0;
+  static int match_list_index = 0;
+  static int match_list_size = 0;
+  static int orig_start, orig_end;
+  static char quote_char;
+  static int delimiter;
+
+  /* The first time through, we generate the list of matches and set things
+     up to insert them. */
+  if (rl_last_func != rl_menu_complete)
+    {
+      /* Clean up from previous call, if any. */
+      FREE (orig_text);
+      if (matches)
+       _rl_free_match_list (matches);
+
+      match_list_index = match_list_size = 0;
+      matches = (char **)NULL;
+
+      /* Only the completion entry function can change these. */
+      set_completion_defaults ('%');
+
+      our_func = rl_menu_completion_entry_function;
+      if (our_func == 0)
+       our_func = rl_completion_entry_function
+                       ? rl_completion_entry_function
+                       : rl_filename_completion_function;
+
+      /* We now look backwards for the start of a filename/variable word. */
+      orig_end = rl_point;
+      found_quote = delimiter = 0;
+      quote_char = '\0';
+
+      if (rl_point)
+       /* This (possibly) changes rl_point.  If it returns a non-zero char,
+          we know we have an open quote. */
+       quote_char = _rl_find_completion_word (&found_quote, &delimiter);
+
+      orig_start = rl_point;
+      rl_point = orig_end;
+
+      orig_text = rl_copy_text (orig_start, orig_end);
+      matches = gen_completion_matches (orig_text, orig_start, orig_end,
+                                       our_func, found_quote, quote_char);
+
+      /* If we are matching filenames, the attempted completion function will
+        have set rl_filename_completion_desired to a non-zero value.  The basic
+        rl_filename_completion_function does this. */
+      matching_filenames = rl_filename_completion_desired;
+
+      if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0)
+       {
+         rl_ding ();
+         FREE (matches);
+         matches = (char **)0;
+         FREE (orig_text);
+         orig_text = (char *)0;
+         completion_changed_buffer = 0;
+          return (0);
+       }
+
+      for (match_list_size = 0; matches[match_list_size]; match_list_size++)
+        ;
+      /* matches[0] is lcd if match_list_size > 1, but the circular buffer
+        code below should take care of it. */
+
+      if (match_list_size > 1 && _rl_complete_show_all)
+       display_matches (matches);
+    }
+
+  /* Now we have the list of matches.  Replace the text between
+     rl_line_buffer[orig_start] and rl_line_buffer[rl_point] with
+     matches[match_list_index], and add any necessary closing char. */
+
+  if (matches == 0 || match_list_size == 0) 
+    {
+      rl_ding ();
+      FREE (matches);
+      matches = (char **)0;
+      completion_changed_buffer = 0;
+      return (0);
+    }
+
+  match_list_index += count;
+  if (match_list_index < 0)
+    match_list_index += match_list_size;
+  else
+    match_list_index %= match_list_size;
+
+  if (match_list_index == 0 && match_list_size > 1)
+    {
+      rl_ding ();
+      insert_match (orig_text, orig_start, MULT_MATCH, &quote_char);
+    }
+  else
+    {
+      insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, &quote_char);
+      append_to_match (matches[match_list_index], delimiter, quote_char,
+                      strcmp (orig_text, matches[match_list_index]));
+    }
+
+  completion_changed_buffer = 1;
+  return (0);
+}
+
+int
+rl_menu_complete (count, ignore)
+     int count, ignore;
+{
+  rl_compentry_func_t *our_func;
+  int matching_filenames, found_quote;
+
+  static char *orig_text;
+  static char **matches = (char **)0;
+  static int match_list_index = 0;
+  static int match_list_size = 0;
+  static int nontrivial_lcd = 0;
+  static int full_completion = 0;      /* set to 1 if menu completion should reinitialize on next call */
+  static int orig_start, orig_end;
+  static char quote_char;
+  static int delimiter;
+
+  /* The first time through, we generate the list of matches and set things
+     up to insert them. */
+  if (rl_last_func != rl_menu_complete || full_completion)
+    {
+      /* Clean up from previous call, if any. */
+      FREE (orig_text);
+      if (matches)
+       _rl_free_match_list (matches);
+
+      match_list_index = match_list_size = 0;
+      matches = (char **)NULL;
+
+      full_completion = 0;
+
+      /* Only the completion entry function can change these. */
+      set_completion_defaults ('%');
+
+      our_func = rl_menu_completion_entry_function;
+      if (our_func == 0)
+       our_func = rl_completion_entry_function
+                       ? rl_completion_entry_function
+                       : rl_filename_completion_function;
+
+      /* We now look backwards for the start of a filename/variable word. */
+      orig_end = rl_point;
+      found_quote = delimiter = 0;
+      quote_char = '\0';
+
+      if (rl_point)
+       /* This (possibly) changes rl_point.  If it returns a non-zero char,
+          we know we have an open quote. */
+       quote_char = _rl_find_completion_word (&found_quote, &delimiter);
+
+      orig_start = rl_point;
+      rl_point = orig_end;
+
+      orig_text = rl_copy_text (orig_start, orig_end);
+      matches = gen_completion_matches (orig_text, orig_start, orig_end,
+                                       our_func, found_quote, quote_char);
+
+      nontrivial_lcd = matches && strcmp (orig_text, matches[0]) != 0;
+
+      /* If we are matching filenames, the attempted completion function will
+        have set rl_filename_completion_desired to a non-zero value.  The basic
+        rl_filename_completion_function does this. */
+      matching_filenames = rl_filename_completion_desired;
+
+      if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0)
+       {
+         rl_ding ();
+         FREE (matches);
+         matches = (char **)0;
+         FREE (orig_text);
+         orig_text = (char *)0;
+         completion_changed_buffer = 0;
+          return (0);
+       }
+
+      for (match_list_size = 0; matches[match_list_size]; match_list_size++)
+        ;
+
+      if (match_list_size == 0) 
+       {
+         rl_ding ();
+         FREE (matches);
+         matches = (char **)0;
+         match_list_index = 0;
+         completion_changed_buffer = 0;
+         return (0);
+        }
+
+      /* matches[0] is lcd if match_list_size > 1, but the circular buffer
+        code below should take care of it. */
+      if (*matches[0])
+       {
+         insert_match (matches[0], orig_start, matches[1] ? MULT_MATCH : SINGLE_MATCH, &quote_char);
+         orig_end = orig_start + strlen (matches[0]);
+         completion_changed_buffer = STREQ (orig_text, matches[0]) == 0;
+       }
+
+      if (match_list_size > 1 && _rl_complete_show_all)
+       {
+         display_matches (matches);
+         /* If there are so many matches that the user has to be asked
+            whether or not he wants to see the matches, menu completion
+            is unwieldy. */
+         if (rl_completion_query_items > 0 && match_list_size >= rl_completion_query_items)
+           {
+             rl_ding ();
+             FREE (matches);
+             matches = (char **)0;
+             full_completion = 1;
+             return (0);
+           }
+       }
+      else if (match_list_size <= 1)
+       {
+         append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd);
+         full_completion = 1;
+         return (0);
+       }
+    }
+
+  /* Now we have the list of matches.  Replace the text between
+     rl_line_buffer[orig_start] and rl_line_buffer[rl_point] with
+     matches[match_list_index], and add any necessary closing char. */
+
+  if (matches == 0 || match_list_size == 0) 
+    {
+      rl_ding ();
+      FREE (matches);
+      matches = (char **)0;
+      completion_changed_buffer = 0;
+      return (0);
+    }
+
+  match_list_index += count;
+  if (match_list_index < 0)
+    match_list_index += match_list_size;
+  else
+    match_list_index %= match_list_size;
+
+  if (match_list_index == 0 && match_list_size > 1)
+    {
+      rl_ding ();
+      insert_match (matches[0], orig_start, MULT_MATCH, &quote_char);
+    }
+  else
+    {
+      insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, &quote_char);
+      append_to_match (matches[match_list_index], delimiter, quote_char,
+                      strcmp (orig_text, matches[match_list_index]));
+    }
+
+  completion_changed_buffer = 1;
+  return (0);
+}
index ddeff0be2f61f0683599fdbad0725c498f59cc82..27aa9495b572af504dc04d1755ace7a0e9708cfa 100644 (file)
@@ -605,6 +605,10 @@ extern int rl_catch_sigwinch;
    filename completer. */
 extern rl_compentry_func_t *rl_completion_entry_function;
 
+/* Optional generator for menu completion.  Default is
+   rl_completion_entry_function (rl_filename_completion_function). */
+ extern rl_compentry_func_t *rl_menu_completion_entry_function;
+
 /* If rl_ignore_some_completions_function is non-NULL it is the address
    of a function to call after all of the possible matches have been
    generated, but before the actual completion is done to the input line.
index c47e3912ef8cc875f69dd434d2dc8e72d50396d0..ddeff0be2f61f0683599fdbad0725c498f59cc82 100644 (file)
@@ -1,6 +1,6 @@
 /* Readline.h -- the names of functions callable from within readline. */
 
-/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2008 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.
@@ -233,6 +233,7 @@ extern int rl_vi_append_mode PARAMS((int, int));
 extern int rl_vi_append_eol PARAMS((int, int));
 extern int rl_vi_eof_maybe PARAMS((int, int));
 extern int rl_vi_insertion_mode PARAMS((int, int));
+extern int rl_vi_insert_mode PARAMS((int, int));
 extern int rl_vi_movement_mode PARAMS((int, int));
 extern int rl_vi_arg_digit PARAMS((int, int));
 extern int rl_vi_change_case PARAMS((int, int));
diff --git a/parse.y b/parse.y
index 2b710a6de3165d2a0a8707673bcd9e6e764a7ad2..53b09435f52907d0990e609ae3057d3df7a4c3ca 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -1013,24 +1013,6 @@ timespec:        TIME
        ;
 %%
 
-/* Possible states for the parser that require it to do special things. */
-#define PST_CASEPAT    0x0001          /* in a case pattern list */
-#define PST_ALEXPNEXT  0x0002          /* expand next word for aliases */
-#define PST_ALLOWOPNBRC        0x0004          /* allow open brace for function def */
-#define PST_NEEDCLOSBRC        0x0008          /* need close brace */
-#define PST_DBLPAREN   0x0010          /* double-paren parsing */
-#define PST_SUBSHELL   0x0020          /* ( ... ) subshell */
-#define PST_CMDSUBST   0x0040          /* $( ... ) command substitution */
-#define PST_CASESTMT   0x0080          /* parsing a case statement */
-#define PST_CONDCMD    0x0100          /* parsing a [[...]] command */
-#define PST_CONDEXPR   0x0200          /* parsing the guts of [[...]] */
-#define PST_ARITHFOR   0x0400          /* parsing an arithmetic for command */
-#define PST_ALEXPAND   0x0800          /* OK to expand aliases - unused */
-#define PST_CMDTOKEN   0x1000          /* command token OK - unused */
-#define PST_COMPASSIGN 0x2000          /* parsing x=(...) compound assignment */
-#define PST_ASSIGNOK   0x4000          /* assignment statement ok in this context */
-#define PST_REGEXP     0x8000          /* parsing an ERE/BRE as a single word */
-
 /* Initial size to allocate for tokens, and the
    amount to grow them by. */
 #define TOKEN_DEFAULT_INITIAL_SIZE 496
index e1796bd85631d7e05de0b1f30af850bc8e3ddaf6..2b710a6de3165d2a0a8707673bcd9e6e764a7ad2 100644 (file)
--- a/parse.y~
+++ b/parse.y~
@@ -2616,9 +2616,9 @@ read_token (command)
              /* If '<' then we could be at "<<" or at "<<-".  We have to
                 look ahead one more character. */
              peek_char = shell_getc (1);
-             if (peek_char == '-')
+             if MBTEST(peek_char == '-')
                return (LESS_LESS_MINUS);
-             else if (peek_char == '<')
+             else if MBTEST(peek_char == '<')
                return (LESS_LESS_LESS);
              else
                {
index 626651cc4b1769bdb8fd09bf0ca583a8a815d647..d9937c38a31b3eaf8f6db094b7da0cf6aebe89f2 100644 (file)
--- a/parser.h
+++ b/parser.h
 #  include "command.h"
 #  include "input.h"
 
+/* Possible states for the parser that require it to do special things. */
+#define PST_CASEPAT    0x00001         /* in a case pattern list */
+#define PST_ALEXPNEXT  0x00002         /* expand next word for aliases */
+#define PST_ALLOWOPNBRC        0x00004         /* allow open brace for function def */
+#define PST_NEEDCLOSBRC        0x00008         /* need close brace */
+#define PST_DBLPAREN   0x00010         /* double-paren parsing */
+#define PST_SUBSHELL   0x00020         /* ( ... ) subshell */
+#define PST_CMDSUBST   0x00040         /* $( ... ) command substitution */
+#define PST_CASESTMT   0x00080         /* parsing a case statement */
+#define PST_CONDCMD    0x00100         /* parsing a [[...]] command */
+#define PST_CONDEXPR   0x00200         /* parsing the guts of [[...]] */
+#define PST_ARITHFOR   0x00400         /* parsing an arithmetic for command */
+#define PST_ALEXPAND   0x00800         /* OK to expand aliases - unused */
+#define PST_CMDTOKEN   0x01000         /* command token OK - unused */
+#define PST_COMPASSIGN 0x02000         /* parsing x=(...) compound assignment */
+#define PST_ASSIGNOK   0x04000         /* assignment statement ok in this context */
+#define PST_EOFTOKEN   0x08000         /* yylex checks against shell_eof_token */
+#define PST_REGEXP     0x10000         /* parsing an ERE/BRE as a single word */
+
 /* Definition of the delimiter stack.  Needed by parse.y and bashhist.c. */
 struct dstack {
 /* DELIMITERS is a stack of the nested delimiters that we have
diff --git a/parser.h~ b/parser.h~
new file mode 100644 (file)
index 0000000..5586de8
--- /dev/null
+++ b/parser.h~
@@ -0,0 +1,59 @@
+/* parser.h -- Everything you wanted to know about the parser, but were
+   afraid to ask. */
+
+/* Copyright (C) 1995 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   Bash is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2, or (at your option) any later
+   version.
+
+   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Bash; see the file COPYING.  If not, write to the Free Software
+   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#if !defined (_PARSER_H_)
+#  define _PARSER_H_
+
+#  include "command.h"
+#  include "input.h"
+
+/* Possible states for the parser that require it to do special things. */
+#define PST_CASEPAT    0x00001         /* in a case pattern list */
+#define PST_ALEXPNEXT  0x00002         /* expand next word for aliases */
+#define PST_ALLOWOPNBRC        0x00004         /* allow open brace for function def */
+#define PST_NEEDCLOSBRC        0x00008         /* need close brace */
+#define PST_DBLPAREN   0x00010         /* double-paren parsing */
+#define PST_SUBSHELL   0x00020         /* ( ... ) subshell */
+#define PST_CMDSUBST   0x00040         /* $( ... ) command substitution */
+#define PST_CASESTMT   0x00080         /* parsing a case statement */
+#define PST_CONDCMD    0x00100         /* parsing a [[...]] command */
+#define PST_CONDEXPR   0x00200         /* parsing the guts of [[...]] */
+#define PST_ARITHFOR   0x00400         /* parsing an arithmetic for command */
+#define PST_ALEXPAND   0x00800         /* OK to expand aliases - unused */
+#define PST_CMDTOKEN   0x01000         /* command token OK - unused */
+#define PST_COMPASSIGN 0x02000         /* parsing x=(...) compound assignment */
+#define PST_ASSIGNOK   0x04000         /* assignment statement ok in this context */
+#define PST_REGEXP     0x08000         /* parsing an ERE/BRE as a single word */
+
+/* Definition of the delimiter stack.  Needed by parse.y and bashhist.c. */
+struct dstack {
+/* DELIMITERS is a stack of the nested delimiters that we have
+   encountered so far. */
+  char *delimiters;
+
+/* Offset into the stack of delimiters. */
+  int delimiter_depth;
+
+/* How many slots are allocated to DELIMITERS. */
+  int delimiter_space;
+};
+
+#endif /* _PARSER_H_ */
index b2305e038ccebc46ab24611504a5d36a93e79067..c60d0d24283f532b807d3f815f0e9925f79f9fc6 100644 (file)
--- a/pathexp.c
+++ b/pathexp.c
@@ -53,6 +53,9 @@ int glob_dot_filenames;
 /* Control whether the extended globbing features are enabled. */
 int extended_glob = 0;
 
+/* Control enabling special handling of `**' */
+int glob_star = 0;
+
 /* Return nonzero if STRING has any unquoted special globbing chars in it.  */
 int
 unquoted_glob_pattern_p (string)
@@ -137,6 +140,28 @@ ere_char (c)
   return (0);
 }
 
+int
+glob_char_p (s)
+     const char *s;
+{
+  switch (*s)
+    {
+    case '*':
+    case '[':
+    case ']':
+    case '?':
+    case '\\':
+      return 1;
+    case '+':
+    case '@':
+    case '!':
+      if (s[1] == '(')        /*(*/
+       return 1;
+      break;
+    }
+  return 0;
+}
+
 /* PATHNAME can contain characters prefixed by CTLESC; this indicates
    that the character is to be quoted.  We quote it here in the style
    that the glob library recognizes.  If flags includes QGLOB_CVTNULL,
@@ -204,22 +229,8 @@ quote_globbing_chars (string)
   temp = (char *)xmalloc (slen * 2 + 1);
   for (t = temp, s = string; *s; )
     {
-      switch (*s)
-       {
-       case '*':
-       case '[':
-       case ']':
-       case '?':
-       case '\\':
-         *t++ = '\\';
-         break;
-       case '+':
-       case '@':
-       case '!':
-         if (s[1] == '(')      /*(*/
-           *t++ = '\\';
-         break;
-       }
+      if (glob_char_p (s))
+       *t++ = '\\';
 
       /* Copy a single (possibly multibyte) character from s to t,
          incrementing both. */
@@ -287,7 +298,7 @@ shell_glob_filename (pathname)
   noglob_dot_filenames = glob_dot_filenames == 0;
 
   temp = quote_string_for_globbing (pathname, QGLOB_FILENAME);
-  results = glob_filename (temp, 0);
+  results = glob_filename (temp, glob_star ? GX_GLOBSTAR : 0);
   free (temp);
 
   if (results && ((GLOB_FAILED (results)) == 0))
diff --git a/pathexp.c~ b/pathexp.c~
new file mode 100644 (file)
index 0000000..c583baa
--- /dev/null
@@ -0,0 +1,485 @@
+/* pathexp.c -- The shell interface to the globbing library. */
+
+/* Copyright (C) 1995-2007 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 <stdio.h>
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include "bashansi.h"
+
+#include "shell.h"
+#include "pathexp.h"
+#include "flags.h"
+
+#include "shmbutil.h"
+
+#include <glob/strmatch.h>
+
+static int glob_name_is_acceptable __P((const char *));
+static void ignore_globbed_names __P((char **, sh_ignore_func_t *));
+               
+#if defined (USE_POSIX_GLOB_LIBRARY)
+#  include <glob.h>
+typedef int posix_glob_errfunc_t __P((const char *, int));
+#else
+#  include <glob/glob.h>
+#endif
+
+/* Control whether * matches .files in globbing. */
+int glob_dot_filenames;
+
+/* Control whether the extended globbing features are enabled. */
+int extended_glob = 0;
+
+/* Control enabling special handling of `**' */
+int glob_star = 0;
+
+/* Return nonzero if STRING has any unquoted special globbing chars in it.  */
+int
+unquoted_glob_pattern_p (string)
+     register char *string;
+{
+  register int c;
+  char *send;
+  int open;
+
+  DECLARE_MBSTATE;
+
+  open = 0;
+  send = string + strlen (string);
+
+  while (c = *string++)
+    {
+      switch (c)
+       {
+       case '?':
+       case '*':
+         return (1);
+
+       case '[':
+         open++;
+         continue;
+
+       case ']':
+         if (open)
+           return (1);
+         continue;
+
+       case '+':
+       case '@':
+       case '!':
+         if (*string == '(')   /*)*/
+           return (1);
+         continue;
+
+       case CTLESC:
+       case '\\':
+         if (*string++ == '\0')
+           return (0);
+       }
+
+      /* Advance one fewer byte than an entire multibyte character to
+        account for the auto-increment in the loop above. */
+#ifdef HANDLE_MULTIBYTE
+      string--;
+      ADVANCE_CHAR_P (string, send - string);
+      string++;
+#else
+      ADVANCE_CHAR_P (string, send - string);
+#endif
+    }
+  return (0);
+}
+
+/* Return 1 if C is a character that is `special' in a POSIX ERE and needs to
+   be quoted to match itself. */
+static inline int
+ere_char (c)
+     int c;
+{
+  switch (c)
+    {
+    case '.':
+    case '[':
+    case '\\':
+    case '(':
+    case ')':
+    case '*':
+    case '+':
+    case '?':
+    case '{':
+    case '|':
+    case '^':
+    case '$':
+      return 1;
+    default: 
+      return 0;
+    }
+  return (0);
+}
+
+int
+glob_char_p (s)
+     const char *s;
+{
+  switch (*s)
+    {
+    case '*':
+    case '[':
+    case ']':
+    case '?':
+    case '\\':
+      return 1;
+    case '+':
+    case '@':
+    case '!':
+      if (s[1] == '(')        /*(*/
+       return 1;
+      break;
+    }
+  return 0;
+}
+
+/* PATHNAME can contain characters prefixed by CTLESC; this indicates
+   that the character is to be quoted.  We quote it here in the style
+   that the glob library recognizes.  If flags includes QGLOB_CVTNULL,
+   we change quoted null strings (pathname[0] == CTLNUL) into empty
+   strings (pathname[0] == 0).  If this is called after quote removal
+   is performed, (flags & QGLOB_CVTNULL) should be 0; if called when quote
+   removal has not been done (for example, before attempting to match a
+   pattern while executing a case statement), flags should include
+   QGLOB_CVTNULL.  If flags includes QGLOB_FILENAME, appropriate quoting
+   to match a filename should be performed. */
+char *
+quote_string_for_globbing (pathname, qflags)
+     const char *pathname;
+     int qflags;
+{
+  char *temp;
+  register int i, j;
+
+  temp = (char *)xmalloc (strlen (pathname) + 1);
+
+  if ((qflags & QGLOB_CVTNULL) && QUOTED_NULL (pathname))
+    {
+      temp[0] = '\0';
+      return temp;
+    }
+
+  for (i = j = 0; pathname[i]; i++)
+    {
+      if (pathname[i] == CTLESC)
+       {
+         if ((qflags & QGLOB_FILENAME) && pathname[i+1] == '/')
+           continue;
+         if ((qflags & QGLOB_REGEXP) && ere_char (pathname[i+1]) == 0)
+           continue;
+         temp[j++] = '\\';
+         i++;
+         if (pathname[i] == '\0')
+           break;
+       }
+      else if (pathname[i] == '\\')
+       {
+         temp[j++] = '\\';
+         i++;
+         if (pathname[i] == '\0')
+           break;
+       }
+      temp[j++] = pathname[i];
+    }
+  temp[j] = '\0';
+
+  return (temp);
+}
+
+char *
+quote_globbing_chars (string)
+     char *string;
+{
+  size_t slen;
+  char *temp, *s, *t, *send;
+  DECLARE_MBSTATE;
+
+  slen = strlen (string);
+  send = string + slen;
+
+  temp = (char *)xmalloc (slen * 2 + 1);
+  for (t = temp, s = string; *s; )
+    {
+      if (glob_char_p (*s))
+       *t++ = '\\';
+
+      /* Copy a single (possibly multibyte) character from s to t,
+         incrementing both. */
+      COPY_CHAR_P (t, s, send);
+    }
+  *t = '\0';
+  return temp;
+}
+
+/* Call the glob library to do globbing on PATHNAME. */
+char **
+shell_glob_filename (pathname)
+     const char *pathname;
+{
+#if defined (USE_POSIX_GLOB_LIBRARY)
+  register int i;
+  char *temp, **results;
+  glob_t filenames;
+  int glob_flags;
+
+  temp = quote_string_for_globbing (pathname, QGLOB_FILENAME);
+
+  filenames.gl_offs = 0;
+
+#  if defined (GLOB_PERIOD)
+  glob_flags = glob_dot_filenames ? GLOB_PERIOD : 0;
+#  else
+  glob_flags = 0;
+#  endif /* !GLOB_PERIOD */
+
+  glob_flags |= (GLOB_ERR | GLOB_DOOFFS);
+
+  i = glob (temp, glob_flags, (posix_glob_errfunc_t *)NULL, &filenames);
+
+  free (temp);
+
+  if (i == GLOB_NOSPACE || i == GLOB_ABORTED)
+    return ((char **)NULL);
+  else if (i == GLOB_NOMATCH)
+    filenames.gl_pathv = (char **)NULL;
+  else if (i != 0)             /* other error codes not in POSIX.2 */
+    filenames.gl_pathv = (char **)NULL;
+
+  results = filenames.gl_pathv;
+
+  if (results && ((GLOB_FAILED (results)) == 0))
+    {
+      if (should_ignore_glob_matches ())
+       ignore_glob_matches (results);
+      if (results && results[0])
+       strvec_sort (results);
+      else
+       {
+         FREE (results);
+         results = (char **)NULL;
+       }
+    }
+
+  return (results);
+
+#else /* !USE_POSIX_GLOB_LIBRARY */
+
+  char *temp, **results;
+
+  noglob_dot_filenames = glob_dot_filenames == 0;
+
+  temp = quote_string_for_globbing (pathname, QGLOB_FILENAME);
+  results = glob_filename (temp, glob_star ? GX_GLOBSTAR : 0);
+  free (temp);
+
+  if (results && ((GLOB_FAILED (results)) == 0))
+    {
+      if (should_ignore_glob_matches ())
+       ignore_glob_matches (results);
+      if (results && results[0])
+       strvec_sort (results);
+      else
+       {
+         FREE (results);
+         results = (char **)&glob_error_return;
+       }
+    }
+
+  return (results);
+#endif /* !USE_POSIX_GLOB_LIBRARY */
+}
+
+/* Stuff for GLOBIGNORE. */
+
+static struct ignorevar globignore =
+{
+  "GLOBIGNORE",
+  (struct ign *)0,
+  0,
+  (char *)0,
+  (sh_iv_item_func_t *)0,
+};
+
+/* Set up to ignore some glob matches because the value of GLOBIGNORE
+   has changed.  If GLOBIGNORE is being unset, we also need to disable
+   the globbing of filenames beginning with a `.'. */
+void
+setup_glob_ignore (name)
+     char *name;
+{
+  char *v;
+
+  v = get_string_value (name);
+  setup_ignore_patterns (&globignore);
+
+  if (globignore.num_ignores)
+    glob_dot_filenames = 1;
+  else if (v == 0)
+    glob_dot_filenames = 0;
+}
+
+int
+should_ignore_glob_matches ()
+{
+  return globignore.num_ignores;
+}
+
+/* Return 0 if NAME matches a pattern in the globignore.ignores list. */
+static int
+glob_name_is_acceptable (name)
+     const char *name;
+{
+  struct ign *p;
+  int flags;
+
+  /* . and .. are never matched */
+  if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
+    return (0);
+
+  flags = FNM_PATHNAME | FNMATCH_EXTFLAG;
+  for (p = globignore.ignores; p->val; p++)
+    {
+      if (strmatch (p->val, (char *)name, flags) != FNM_NOMATCH)
+       return (0);
+    }
+  return (1);
+}
+
+/* Internal function to test whether filenames in NAMES should be
+   ignored.  NAME_FUNC is a pointer to a function to call with each
+   name.  It returns non-zero if the name is acceptable to the particular
+   ignore function which called _ignore_names; zero if the name should
+   be removed from NAMES. */
+
+static void
+ignore_globbed_names (names, name_func)
+     char **names;
+     sh_ignore_func_t *name_func;
+{
+  char **newnames;
+  int n, i;
+
+  for (i = 0; names[i]; i++)
+    ;
+  newnames = strvec_create (i + 1);
+
+  for (n = i = 0; names[i]; i++)
+    {
+      if ((*name_func) (names[i]))
+       newnames[n++] = names[i];
+      else
+       free (names[i]);
+    }
+
+  newnames[n] = (char *)NULL;
+
+  if (n == 0)
+    {
+      names[0] = (char *)NULL;
+      free (newnames);
+      return;
+    }
+
+  /* Copy the acceptable names from NEWNAMES back to NAMES and set the
+     new array end. */
+  for (n = 0; newnames[n]; n++)
+    names[n] = newnames[n];
+  names[n] = (char *)NULL;
+  free (newnames);
+}
+
+void
+ignore_glob_matches (names)
+     char **names;
+{
+  if (globignore.num_ignores == 0)
+    return;
+
+  ignore_globbed_names (names, glob_name_is_acceptable);
+}
+
+void
+setup_ignore_patterns (ivp)
+     struct ignorevar *ivp;
+{
+  int numitems, maxitems, ptr;
+  char *colon_bit, *this_ignoreval;
+  struct ign *p;
+
+  this_ignoreval = get_string_value (ivp->varname);
+
+  /* If nothing has changed then just exit now. */
+  if ((this_ignoreval && ivp->last_ignoreval && STREQ (this_ignoreval, ivp->last_ignoreval)) ||
+      (!this_ignoreval && !ivp->last_ignoreval))
+    return;
+
+  /* Oops.  The ignore variable has changed.  Re-parse it. */
+  ivp->num_ignores = 0;
+
+  if (ivp->ignores)
+    {
+      for (p = ivp->ignores; p->val; p++)
+       free(p->val);
+      free (ivp->ignores);
+      ivp->ignores = (struct ign *)NULL;
+    }
+
+  if (ivp->last_ignoreval)
+    {
+      free (ivp->last_ignoreval);
+      ivp->last_ignoreval = (char *)NULL;
+    }
+
+  if (this_ignoreval == 0 || *this_ignoreval == '\0')
+    return;
+
+  ivp->last_ignoreval = savestring (this_ignoreval);
+
+  numitems = maxitems = ptr = 0;
+
+  while (colon_bit = extract_colon_unit (this_ignoreval, &ptr))
+    {
+      if (numitems + 1 >= maxitems)
+       {
+         maxitems += 10;
+         ivp->ignores = (struct ign *)xrealloc (ivp->ignores, maxitems * sizeof (struct ign));
+       }
+      ivp->ignores[numitems].val = colon_bit;
+      ivp->ignores[numitems].len = strlen (colon_bit);
+      ivp->ignores[numitems].flags = 0;
+      if (ivp->item_func)
+       (*ivp->item_func) (&ivp->ignores[numitems]);
+      numitems++;
+    }
+  ivp->ignores[numitems].val = (char *)NULL;
+  ivp->num_ignores = numitems;
+}
index b4afcb3a4d0dbe4e1b67464e9e67a1bffb235795..76213e2dd9e5fb9b0c444fd5240a95d134f842bd 100644 (file)
--- a/pathexp.h
+++ b/pathexp.h
@@ -1,6 +1,6 @@
 /* pathexp.h -- The shell interface to the globbing library. */
 
-/* Copyright (C) 1987-2007 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -46,6 +46,7 @@ extern char *glob_error_return;
 
 extern int glob_dot_filenames;
 extern int extended_glob;
+extern int glob_star;
 extern int match_ignore_case;  /* doesn't really belong here */
 
 extern int unquoted_glob_pattern_p __P((char *));
@@ -62,6 +63,7 @@ extern int unquoted_glob_pattern_p __P((char *));
    to match a filename should be performed. */
 extern char *quote_string_for_globbing __P((const char *, int));
 
+extern int glob_char_p __P((const char *));
 extern char *quote_globbing_chars __P((char *));
 
 /* Call the glob library to do globbing on PATHNAME. */
diff --git a/pathexp.h~ b/pathexp.h~
new file mode 100644 (file)
index 0000000..1d1216f
--- /dev/null
@@ -0,0 +1,101 @@
+/* pathexp.h -- The shell interface to the globbing library. */
+
+/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   Bash is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2, or (at your option) any later
+   version.
+
+   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Bash; see the file COPYING.  If not, write to the Free Software
+   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#if !defined (_PATHEXP_H_)
+#define _PATHEXP_H_
+
+#if defined (USE_POSIX_GLOB_LIBRARY)
+#  define GLOB_FAILED(glist)   !(glist)
+#else /* !USE_POSIX_GLOB_LIBRARY */
+#  define GLOB_FAILED(glist)   (glist) == (char **)&glob_error_return
+extern int noglob_dot_filenames;
+extern char *glob_error_return;
+#endif /* !USE_POSIX_GLOB_LIBRARY */
+
+/* Flag values for quote_string_for_globbing */
+#define QGLOB_CVTNULL  0x01    /* convert QUOTED_NULL strings to '\0' */
+#define QGLOB_FILENAME 0x02    /* do correct quoting for matching filenames */
+#define QGLOB_REGEXP   0x04    /* quote an ERE for regcomp/regexec */
+
+#if defined (EXTENDED_GLOB)
+/* Flags to OR with other flag args to strmatch() to enabled the extended
+   pattern matching. */
+#  define FNMATCH_EXTFLAG      (extended_glob ? FNM_EXTMATCH : 0)
+#else
+#  define FNMATCH_EXTFLAG      0
+#endif /* !EXTENDED_GLOB */
+
+#define FNMATCH_IGNCASE                (match_ignore_case ? FNM_CASEFOLD : 0)
+
+extern int glob_dot_filenames;
+extern int extended_glob;
+extern int glob_star;
+extern int match_ignore_case;  /* doesn't really belong here */
+
+extern int unquoted_glob_pattern_p __P((char *));
+
+/* PATHNAME can contain characters prefixed by CTLESC; this indicates
+   that the character is to be quoted.  We quote it here in the style
+   that the glob library recognizes.  If flags includes QGLOB_CVTNULL,
+   we change quoted null strings (pathname[0] == CTLNUL) into empty
+   strings (pathname[0] == 0).  If this is called after quote removal
+   is performed, (flags & QGLOB_CVTNULL) should be 0; if called when quote
+   removal has not been done (for example, before attempting to match a
+   pattern while executing a case statement), flags should include
+   QGLOB_CVTNULL.  If flags includes QGLOB_FILENAME, appropriate quoting
+   to match a filename should be performed. */
+extern char *quote_string_for_globbing __P((const char *, int));
+
+extern char *quote_globbing_chars __P((char *));
+
+/* Call the glob library to do globbing on PATHNAME. */
+extern char **shell_glob_filename __P((const char *));
+
+/* Filename completion ignore.  Used to implement the "fignore" facility of
+   tcsh and GLOBIGNORE (like ksh-93 FIGNORE).
+
+   It is passed a NULL-terminated array of (char *)'s that must be
+   free()'d if they are deleted.  The first element (names[0]) is the
+   least-common-denominator string of the matching patterns (i.e.
+   u<TAB> produces names[0] = "und", names[1] = "under.c", names[2] =
+   "undun.c", name[3] = NULL).  */
+
+struct ign {
+  char *val;
+  int len, flags;
+};
+
+typedef int sh_iv_item_func_t __P((struct ign *));
+
+struct ignorevar {
+  char *varname;       /* FIGNORE or GLOBIGNORE */
+  struct ign *ignores; /* Store the ignore strings here */
+  int num_ignores;     /* How many are there? */
+  char *last_ignoreval;        /* Last value of variable - cached for speed */
+  sh_iv_item_func_t *item_func; /* Called when each item is parsed from $`varname' */
+};
+
+extern void setup_ignore_patterns __P((struct ignorevar *));
+
+extern void setup_glob_ignore __P((char *));
+extern int should_ignore_glob_matches __P((void));
+extern void ignore_glob_matches __P((char **));
+
+#endif
index 3efcf32d68e9722024b6ca9d67f9e81b2aa5ac04..72ec06a2c1fd8dde92acea5e8ac773e35f1d061b 100755 (executable)
@@ -1,4 +1,4 @@
-BUILD_DIR=/usr/local/build/chet/bash/bash-current
+BUILD_DIR=/usr/local/build/bash/bash-current
 THIS_SH=$BUILD_DIR/bash
 PATH=$PATH:$BUILD_DIR
 
index 44488e188e011e4d8030ad6c227a94971e1d6c56..fdf872ab9701d1feebd86bc473906021a142b4c9 100644 (file)
@@ -520,4 +520,19 @@ argv[1] = <12>
 argv[1] = <>
 argv[1] = <>
 argv[1] = </tmp/test/TEST>
-./new-exp.tests: line 560: ABXD: parameter unset
+foo is a function
+foo () 
+{ 
+    echo < <(cat x1)
+}
+foo () 
+{ 
+    echo < <(cat x1)
+}
+bar () { echo < <(cat x1) }
+bar is a function
+bar () 
+{ 
+    echo < <(cat x1)
+}
+./new-exp.tests: line 562: ABXD: parameter unset
index 78a0e7fb0087853458a5f0e3e06cb00af782a612..0fc265db836686f87fd5da59c5cd9672274511e4 100644 (file)
@@ -555,6 +555,8 @@ echo ${var##?}
 
 ${THIS_SH} ./new-exp6.sub
 
+${THIS_SH} ./new-exp7.sub
+
 # this must be last!
 expect $0: 'ABXD: parameter unset'
 recho ${ABXD:?"parameter unset"}
diff --git a/tests/new-exp.tests~ b/tests/new-exp.tests~
new file mode 100644 (file)
index 0000000..78a0e7f
--- /dev/null
@@ -0,0 +1,560 @@
+# must do this because posix mode causes process substitution to be disabled
+# and flagged as a syntax error, which causes the shell to exit
+set +o posix
+
+expect()
+{
+        echo expect "$@"
+}
+
+HOME=/usr/homes/chet   # to make the check against new-exp.right work
+expect '<foo bar>'
+recho "${undef-"foo bar"}"     # should be foo bar
+expect '<foo>'
+recho "${und="foo"}"           # should be foo
+
+expect "<$HOME>"
+recho ${HOME-"}"}
+expect "<$HOME>"
+recho "${HOME-'}'}"
+expect "<$HOME>"
+recho "${HOME-"}"}"
+
+expect $0: 'HOME: }: syntax error: operand expected (error token is "}")'
+recho "${HOME:`echo }`}"       # should be a math error -- bad substring substitution
+
+expect unset
+_ENV=oops
+x=${_ENV[(_$-=0)+(_=1)-_${-%%*i*}]}
+echo ${x:-unset}
+
+expect "<$HOME>"
+recho ${HOME}
+expect "<$HOME>"
+recho ${HOME:-`echo }`}
+expect "<$HOME>"
+recho ${HOME:-`echo "}"`}
+expect "<$HOME>"
+recho "${HOME:-`echo "}"`}"
+expect "<$HOME>"
+recho "$(echo "${HOME}")"
+expect "<$HOME>"
+recho "$(echo "$(echo ${HOME})")"
+expect "<$HOME>"
+recho "$(echo "$(echo "${HOME}")")"
+
+P=*@*
+expect '<*@>'
+recho "${P%"*"}"       # 
+expect '<*@>'
+recho "${P%'*'}"       # 
+expect '<@*>'
+recho "${P#\*}"                # should be @*
+
+expect '<)>'
+recho "$(echo ")")"    # should be )
+expect '<")">'
+recho "$(echo "\")\"")"        # should be ")"
+
+foo='abcd   '
+expect '<-abcd> <->'
+recho -${foo}-         # should be -abcd -
+expect '<-abcd> <->'
+recho -${foo% *}-      # should be -abcd -
+expect '<-abcd->'
+recho -${foo%% *}-     # should be -abcd-
+
+foo=bar
+expect '<bar foo>'
+echo -n $foo' ' ; echo foo
+
+expect '<bar foo>'
+echo -n $foo" " ; echo foo
+
+expect '<bar foo>'
+echo -n "$foo " ; echo foo
+
+expect '<barfoo>'
+echo -e "$foo\c " ; echo foo
+
+expect '<barfoo>'
+echo -e $foo"\c " ; echo foo
+
+# make sure backslashes are preserved in front of characters that are not
+# valid backslash escapes
+expect '<\x>'
+echo -e '\x'
+
+# substring tests
+z=abcdefghijklmnop
+expect '<abcd>'
+recho ${z:0:4}
+
+expect '<efg> <nop>'
+recho ${z:4:3} ${z:${#z}-3:3}
+
+expect '<efg> <nop>'
+recho ${z:4:3} ${z: -3:3}
+
+expect '<hijklmnop>'
+recho ${z:7:30}
+
+expect '<abcdefghijklmnop>'
+recho ${z:0:100}
+
+expect '<abcdefghijklmnop>'
+recho ${z:0:${#z}}
+
+set 'ab cd' 'ef' 'gh ij' 'kl mn' 'op'
+expect '<ab cd> <ef>'
+recho "${@:1:2}"
+
+expect '<gh ij> <kl mn>'
+recho "${@:3:2}"
+
+expect '<gh ij> <kl mn> <op>'
+recho "${@:3:4}"
+
+expect '<ab cd> <ef> <gh ij> <kl mn> <op>'
+recho "${@:1:$#}"
+
+# code to ad-hoc parse arithmetic expressions in substring expansions was
+# broken until post-2.04
+base=/home/chet/foo//bar
+string1=$base/abcabcabc
+x=1 j=4
+
+expect '</home/chet/foo//bar/abcabcabc>'
+recho ${string1:0}
+
+expect '<home/chet/foo//bar/abcabcabc>'
+recho ${string1:1}
+
+expect '<home>'
+recho ${string1:(j?1:0):j}
+
+expect '<home>'
+recho ${string1:j?1:0:j}
+
+expect '<home>'
+recho ${string1:(j?(x?1:0):0):j}
+
+expect '<home>'
+recho ${string1:j?(x?1:0):0:j}
+
+unset base string1 x j
+
+# indirect variable references
+expect '<abcdefghijklmnop>'
+recho ${!9:-$z}
+
+ef=4
+expect '<4>'
+recho ${!2}
+
+expect '<op>'
+recho ${!#}
+
+set a b c d e
+a=
+expect '<abcdefghijklmnop>'
+recho ${a:-$z}
+expect '<abcdefghijklmnop>'
+recho ${!1:-$z}
+
+expect nothing
+recho ${a-$z}
+expect nothing
+recho ${!1-$z}
+
+set -u
+expect $0: ABX: unbound variable
+( recho ${ABX} )
+set +u
+
+expect $0: '$6: cannot assign in this way'
+recho ${6="arg6"}
+
+v=abcde
+
+# sed-like variable substitution
+expect '<xxcde>'
+recho ${v/a[a-z]/xx}
+expect '<axxde>'
+recho ${v/a??/axx}
+expect '<abxyz>'
+recho ${v/c??/xyz}
+expect '<abbcde>'
+recho ${v/#a/ab}
+expect '<abcde>'
+recho ${v/#d/ab}
+expect '<abcabe>'
+recho ${v/d/ab}
+expect '<abcdlast>'
+recho ${v/%?/last}
+expect '<abcde>'
+recho ${v/%x/last}
+
+av=(abcd efgh ijkl mnop qrst uvwx)
+
+expect '<xxcd>'
+recho ${av/??/xx}
+expect '<abxx>'
+recho ${av/%??/xx}
+expect '<xxgh>'
+recho ${av[1]/??/xx}
+expect '<efgh>'
+recho ${av[1]/%ab/xx}
+expect '<xxfgh>'
+recho ${av[1]/#?/xx}
+expect '<zagh>'
+recho ${av[1]/??/za}
+expect '<zaza>'
+recho ${av[1]//??/za}
+expect '<zagh>'
+recho ${av[1]/#??/za}
+expect '<efza>'
+recho ${av[1]/%??/za}
+
+expect '<yyy> <yyy> <yyy> <yyy> <yyy> <yyy>'
+recho ${av[@]/*/yyy}
+expect '<yyy> <yyy> <yyy> <yyy> <yyy> <yyy>'
+recho ${av[@]/#*/yyy}
+expect '<yyy> <yyy> <yyy> <yyy> <yyy> <yyy>'
+recho ${av[@]/%*/yyy}
+expect '<yyy> <efgh> <ijkl> <mnop> <qrst> <uvwx>'
+recho ${av[@]/a*/yyy}
+expect '<abxx> <efxx> <ijxx> <mnxx> <qrxx> <uvxx>'
+recho ${av[@]/%??/xx}
+
+set abcd efgh ijkl mnop qrst uvwx
+
+expect '<xxcd>'
+recho ${1/??/xx}
+expect '<xxcd> <xxgh> <xxkl> <xxop> <xxst> <xxwx>'
+recho ${@/??/xx}
+expect '<xxcd> <xxgh> <xxkl> <xxop> <xxst> <xxwx>'
+recho ${@/%??/xx}
+expect '<zaza>'
+recho ${3//??/za}
+expect '<efza>'
+recho ${3/%??/za}
+expect '<zaza> <zaza> <zaza> <zaza> <zaza> <zaza>'
+recho ${@//??/za}
+expect '<zacd> <zagh> <zakl> <zaop> <zast> <zawx>'
+recho ${@/#??/za}
+expect '<yyy> <yyy> <yyy> <yyy> <yyy> <yyy>'
+recho ${@//*/yyy}
+expect '<yyy> <efgh> <ijkl> <mnop> <qrst> <uvwx>'
+recho ${@//a*/yyy}
+expect '<abcd> <efgh> <ijkl> <mnop> <qrst> <uvwyyy>'
+recho ${@/%x*/yyy}
+
+expect a newline
+echo $abmcde
+
+# sneaky way to replace a newline in a variable value with something else
+AVAR=$'This\nstring\nhas\nmultiple\nlines.'
+echo "${AVAR}"
+
+eval BVAR=\"\${AVAR//$'\n'/-}\"
+echo "$BVAR"
+
+unset AVAR BVAR
+
+# run process substitution tests in a subshell so that syntax errors
+# caused by a shell not implementing process substitution (e.g., one
+# built on a NeXT) will not cause the whole test to exit prematurely
+${THIS_SH} ./new-exp1.sub
+
+# run the tests of $(<filename) in a subshell to avoid cluttering up
+# this script
+${THIS_SH} ./new-exp2.sub
+
+expect '<6>'
+recho ${#:-foo}
+expect $0: '${#:}: bad substitution'
+echo ${#:}
+
+expect "<'>"
+recho "'"
+expect '<">'
+recho '"'
+expect '<"hello">'
+recho "\"hello\""
+
+shift $#
+unset foo
+z=abcdef
+z1='abc def'
+
+expect '<>'
+recho ${foo:-""}
+expect nothing
+recho ${foo:-"$@"}
+expect '<>'
+recho "${foo:-$@}"
+
+# unset var
+expect '<>'
+recho ${foo:-"$zbcd"}
+expect nothing
+recho ${foo:-$zbcd}
+
+# set var
+expect '<abcdef>'
+recho ${foo:-"$z"}
+expect '<abc def>'
+recho ${foo:-"$z1"}
+
+expect '<abcdef>'
+recho ${foo:-$z}
+expect '<abc> <def>'
+recho ${foo:-$z1}
+
+expect '<abcdef>'
+recho "${foo:-$z}"
+expect '<abc def>'
+recho "${foo:-$z1}"
+
+expect '<abcdef>'
+recho "${foo:-"$z"}"
+# this disagrees with sh and ksh, but I think it is right according
+# to posix.2.
+expect '<abc def>'
+recho "${foo:-"$z1"}"
+
+set ab cd ef gh
+expect '<ab> <cd> <ef> <gh>'
+recho ${foo:-"$@"}
+expect '<ab> <cd> <ef> <gh>'
+recho "${foo:-$@}"
+expect '<ab> <cd> <ef> <gh>'
+recho "${foo:-"$@"}"
+
+shift $#
+expect nothing
+recho $xxx"$@"
+expect nothing
+recho ${foo:-$xxx"$@"}
+expect '<>'
+recho "${foo:-$xxx$@}"
+expect '<>'
+recho "${foo:-$xxx"$@"}"
+
+expect nothing
+recho $xxx"$@"
+expect nothing
+recho "$xxx$@"
+expect nothing
+recho "$@"$xxx
+
+expect '<>'
+recho $xxx""
+expect '<>'
+recho $xxx''
+expect '<>'
+recho ''$xxx
+expect '<>'
+recho ""$xxx
+
+AB='abcdefghijklmnopqrstuvwxyz'
+
+recho ${AB:7:15}
+recho ${AB:15:7}
+
+recho ${AB:20}
+
+recho ${AB:0}
+recho ${AB:0:20}
+
+recho ${AB:10:7}
+recho ${AB:10:3+4}
+recho ${AB:20/2:3+4}
+
+set 1 2 3 4 5 6
+recho \""${*:2:2}"\"
+
+IFS=:
+recho \""${*:2:2}"\"
+
+IFS=$' \t\n'
+
+z=123456
+
+recho \""${z:2:2}"\"
+recho \""${z:2}"\"
+recho \""${z:2:4}"\"
+recho \""${z:2:6}"\"
+
+set $'\1' $'\2' $'\177'
+
+recho $*
+recho $@
+
+recho ${*}
+recho ${@}
+
+xx=one/two/two
+recho ${xx%/*}
+recho ${xx/\/two}
+
+yy=oneonetwo
+recho ${yy//one}
+recho ${yy/\/one}
+
+xx=oneonetwo
+
+recho ${xx/one}
+recho ${xx//one}
+recho ${xx/\/one}
+
+# out-of-range substrings
+var=abc
+c=${var:3}
+expect nothing
+recho $c
+c=${var:4}
+expect nothing
+recho $c
+expect '<./new-exp.tests: -2: substring expression < 0>'
+c=${var:0:-2}
+
+var=abcdefghi
+c=${var:3:12}
+recho $c
+c=${var:4:20}
+recho $c
+
+# make sure null patterns work
+xxx=endocrine
+yyy=n
+unset zzz
+
+recho ${xxx/$yyy/*}
+recho ${xxx//$yyy/*}
+
+recho ${xxx/$zzz/*}
+recho ${xxx//$zzz/*}
+
+recho ${xxx//%${zzz}/}
+recho ${xxx//%${zzz}}
+recho ${xxx//#${zzz}/}
+recho ${xxx//#${zzz}}
+
+# another case that caused a core dump in bash-2.0
+XPATH=/usr/bin:/bin:/usr/local/bin:/usr/gnu/bin::/usr/bin/X11:/sbin:/usr/sbin
+
+recho ${XPATH//:/ }
+
+xx=(ar as at au av aw ax ay az)
+
+recho ${xx[@]/a/}
+recho ${xx[@]//a/}
+
+recho ${xx[*]/a/}
+recho ${xx[*]//a/}
+
+recho ${xx[@]%?}
+recho ${xx[*]%?}
+
+recho ${xx[@]#?}
+recho ${xx[*]#?}
+
+set -- ar as at au av aw ax ay az
+
+recho ${@/a/}
+recho ${@//a/}
+
+recho ${*/a/}
+recho ${*//a/}
+
+recho ${@%?}
+recho ${*%?}
+
+recho ${@#?}
+recho ${*#?}
+
+shift $#
+set -u
+( recho $9 ; echo after 1)
+( recho ${9} ; echo after 2)
+( recho $UNSET ; echo after 3)
+( recho ${UNSET} ; echo after 4)
+( recho "$UNSET" ; echo after 5)
+( recho "${UNSET}" ; echo after 6)
+( recho "${#UNSET}" ; echo after 7)
+set +u
+
+RECEIVED="12345"
+recho "${RECEIVED:$((${#RECEIVED}-1)):1}"
+RECEIVED="12345#"
+recho "${RECEIVED:$((${#RECEIVED}-1)):1}"
+RECEIVED="#"
+recho "${RECEIVED:$((${#RECEIVED}-1)):1}"
+RECEIVED=""
+recho "${RECEIVED:$((${#RECEIVED}-1)):1}"
+
+# tests of new prefix expansion ${!prefix*}
+${THIS_SH} ./new-exp3.sub
+
+# bug with indirect expansion through bash-2.05b
+${THIS_SH} ./new-exp4.sub
+
+# these caused errors and core dumps in versions before bash-2.04
+c=""
+echo ${c//${$(($#-1))}/x/}
+
+set a b c d e f g
+recho "$@"
+
+set -- ${@:1:$(($# - 2))}
+recho "$@"
+
+set a b
+recho ${@:1:$(($# - 2))}
+
+recho ${@:1:0}
+recho ${@:1:1}
+recho ${@:1:2}
+
+recho "${*:1:0}"
+
+# this is an error -- negative expression
+set a
+recho ${@:1:$(($# - 2))}
+
+XPATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:.:/sbin:/usr/sbin
+set $( IFS=: ; echo $XPATH ) 
+
+recho ${@##*/}
+recho ${@%%[!/]*}
+
+recho ${@#/*}
+recho ${@%*/}
+
+set /full/path/to/x16 /another/full/path
+
+recho ${1%/*}
+recho ${1%%[!/]*}
+recho ${1#*/}
+recho ${1##*/}
+
+${THIS_SH} ./new-exp5.sub
+
+unset var
+var=blah
+
+# these had better agree
+echo ${var[@]:3}
+echo ${var:3}
+echo ${var[@]/#/--}
+echo ${var/#/--}
+echo ${var[@]##?}
+echo ${var##?}
+
+${THIS_SH} ./new-exp6.sub
+
+# this must be last!
+expect $0: 'ABXD: parameter unset'
+recho ${ABXD:?"parameter unset"}
diff --git a/tests/new-exp7.sub b/tests/new-exp7.sub
new file mode 100644 (file)
index 0000000..970475c
--- /dev/null
@@ -0,0 +1,13 @@
+foo()
+{
+       echo < <(cat x1)
+}
+
+type foo
+
+declare -f foo
+
+echo $(declare -f foo | sed 's:foo:bar:')
+eval "$(declare -f foo | sed 's:foo:bar:')"
+
+type bar
index ac8fdeada340fff869d3f4d94da33a26417e51f7..0b98ba95c476d3eada59e9fe1ee1746978f4cda0 100644 (file)
@@ -9,6 +9,7 @@ shopt -u checkjobs
 shopt -u checkwinsize
 shopt -s cmdhist
 shopt -u compat31
+shopt -u dirspell
 shopt -u dotglob
 shopt -u execfail
 shopt -s expand_aliases
@@ -17,6 +18,7 @@ shopt -u extglob
 shopt -s extquote
 shopt -u failglob
 shopt -s force_fignore
+shopt -u globstar
 shopt -u gnu_errfmt
 shopt -u histappend
 shopt -u histreedit
@@ -59,11 +61,13 @@ shopt -u checkhash
 shopt -u checkjobs
 shopt -u checkwinsize
 shopt -u compat31
+shopt -u dirspell
 shopt -u dotglob
 shopt -u execfail
 shopt -u extdebug
 shopt -u extglob
 shopt -u failglob
+shopt -u globstar
 shopt -u gnu_errfmt
 shopt -u histappend
 shopt -u histreedit
@@ -86,11 +90,13 @@ checkhash           off
 checkjobs              off
 checkwinsize           off
 compat31               off
+dirspell               off
 dotglob                off
 execfail               off
 extdebug               off
 extglob                off
 failglob               off
+globstar               off
 gnu_errfmt             off
 histappend             off
 histreedit             off
index 1a9b55a6548618efe7eacecb0287073651791890..5e331d5e643ed06ccd0103330d9eb1efd0f007a6 100644 (file)
@@ -3518,6 +3518,8 @@ push_func_var (data)
         shell_variables->flags |= VC_HASTMPVAR;
       v->attributes |= var->attributes;
     }
+  else
+    stupidly_hack_special_variables (var->name);       /* XXX */
 
   dispose_variable (var);
 }
@@ -3604,6 +3606,8 @@ push_exported_var (data)
        var->attributes &= ~att_propagate;
       v->attributes |= var->attributes;
     }
+  else
+    stupidly_hack_special_variables (var->name);       /* XXX */
 
   dispose_variable (var);
 }