commit bash-20040129 snapshot

This commit is contained in:
Chet Ramey
2011-12-03 12:54:16 -05:00
parent 113d85a4ab
commit 704a1a2a9b
39 changed files with 10607 additions and 444 deletions
+3
View File
@@ -101,6 +101,9 @@ g. Fixed some display (and other) bugs encountered in multibyte locales
h. Fixed some display bugs caused by multibyte characters in prompt strings.
i. Fixed a problem with history expansion caused by non-whitespace characters
used as history word delimiters.
3. New Features in Bash
a. printf builtin understands two new escape sequences: \" and \?.
+62
View File
@@ -9101,3 +9101,65 @@ lib/readline/funmap.c
lib/readline/doc/{readline.3,rluser.texi},doc/bash.1
- documented `unix-filename-rubout'
1/29
----
lib/readline/histexpand.c
- change history_tokenize_internal to handle non-whitespace delimiter
characters by creating separate fields (like the shell does when
splitting on $IFS)
1/30
----
lib/glob/xmbsrtowcs.c
- new function, xdupmbstowcs, for convenience: calls xmbsrtowcs
while allocating memory for the new wide character string
- some small efficiency improvments to xmbsrtowcs
include/shmbutil.h
- extern declaration for xdupmbstowcs
lib/glob/strmatch.h
- include config.h for definition of HANDLE_MULTIBYTE
- remove the HAVE_LIBC_FNM_EXTMATCH tests
- new extern declaration for wcsmatch(whchar_t *, wchar_t *, int)
configure.in
- remove call to BASH_FUNC_FNMATCH_EXTMATCH; it's no longer used
lib/glob/smatch.c
- simplify xstrmatch() by using xdupmbstowcs() instead of inline code
lib/glob/glob.c
- modify mbskipname() to avoid the use of alloca
- simplify mbskipname() by using xdupmbstowcs() instead of inline code
- simplify glob_pattern_p() by using xdupmbstowcs() instead of
inline code
- fix memory leak in wdequote_pathname
- simplify wdequote_pathname() by using xdupmbstowcs() instead of
inline code
lib/glob/strmatch.c
- new function, wcsmatch(), `exported' wide-character equivalent of
strmatch()
subst.c
- old match_pattern is now match_upattern
- match_pattern now either calls match_upattern or converts
mbstrings to wide chars and calls match_wpattern
- match_upattern reverted to old non-multibyte code
- new function: match_pattern_wchar, wide character version of
match_pattern_char
2/1
---
subst.c
- old remove_pattern is now remove_upattern
- remove_upattern reverted to old non-multibyte code (pre-Waugh patch)
- new multibyte version of remove_pattern: remove_wpattern
- remove_pattern now calls either remove_upattern or converts a
multibyte string to a wide character string and calls
remove_wpattern
- new function, wcsdup, wide-character version of strdup(3)
+81
View File
@@ -9069,3 +9069,84 @@ shell.c
- in open_shell_script, check to see whether or not we can find and
open the filename argument before setting dollar_vars[0] or
manipulating BASH_SOURCE, so the error messages come out better
subst.c
- in string_list_internal, short-circuit right away to savestring()
if the list only has a single element
1/28
----
lib/readline/rltypedefs.h
- new set of typedefs for functions returning char * with various
arguments (standard set)
lib/readline/complete.c
- new function pointer, rl_completion_word_break_hook, called by
_rl_find_completion_word, used to set word break characters at
completion time, allowing them to be position-based
lib/readline/doc/rltech.texi
- documented rl_completion_word_break_hook
lib/readline/kill.c
- added new rl_unix_filename_rubout, which deletes one filename
component in a Unix pathname backward (delimiters are whitespace
and `/')
lib/readline/readline.h
- extern declaration for rl_unix_filename_rubout
lib/readline/funmap.c
- new bindable readline command `unix-filename-rubout'
lib/readline/doc/{readline.3,rluser.texi},doc/bash.1
- documented `unix-filename-rubout'
1/29
----
lib/readline/histexpand.c
- change history_tokenize_internal to handle non-whitespace delimiter
characters by creating separate fields (like the shell does when
splitting on $IFS)
1/30
----
lib/glob/xmbsrtowcs.c
- new function, xdupmbstowcs, for convenience: calls xmbsrtowcs
while allocating memory for the new wide character string
- some small efficiency improvments to xmbsrtowcs
include/shmbutil.h
- extern declaration for xdupmbstowcs
lib/glob/strmatch.h
- include config.h for definition of HANDLE_MULTIBYTE
- remove the HAVE_LIBC_FNM_EXTMATCH tests
- new extern declaration for wcsmatch(whchar_t *, wchar_t *, int)
configure.in
- remove call to BASH_FUNC_FNMATCH_EXTMATCH; it's no longer used
lib/glob/smatch.c
- simplify xstrmatch() by using xdupmbstowcs() instead of inline code
lib/glob/glob.c
- modify mbskipname() to avoid the use of alloca
- simplify mbskipname() by using xdupmbstowcs() instead of inline code
- simplify glob_pattern_p() by using xdupmbstowcs() instead of
inline code
- fix memory leak in wdequote_pathname
- simplify wdequote_pathname() by using xdupmbstowcs() instead of
inline code
lib/glob/strmatch.c
- new function, wcsmatch(), `exported' wide-character equivalent of
strmatch()
subst.c
- old match_pattern is now internal_match_pattern
- match_pattern now either calls internal_match_pattern or converts
mbstrings to wide chars and calls internal_match_wpattern
- internal_match_pattern reverted to old non-multibyte code
- new function: match_pattern_wchar, wide character version of
match_pattern_char
+1 -2
View File
@@ -1,5 +1,5 @@
@%:@! /bin/sh
@%:@ From configure.in for Bash 3.0, version 3.160, from autoconf version AC_ACVERSION.
@%:@ From configure.in for Bash 3.0, version 3.161, from autoconf version AC_ACVERSION.
@%:@ Guess values for system-dependent variables and create Makefiles.
@%:@ Generated by GNU Autoconf 2.57 for bash 3.0-beta1.
@%:@
@@ -22719,7 +22719,6 @@ _ACEOF
fi
echo "$as_me:$LINENO: checking for printf floating point output in hex notation" >&5
echo $ECHO_N "checking for printf floating point output in hex notation... $ECHO_C" >&6
if test "${bash_cv_printf_a_format+set}" = set; then
+78 -78
View File
@@ -15,96 +15,96 @@
'configure.in'
],
{
'AH_OUTPUT' => 1,
'AC_FUNC_STRERROR_R' => 1,
'AC_CHECK_HEADERS' => 1,
'AC_HEADER_MAJOR' => 1,
'AC_FUNC_MMAP' => 1,
'AC_INIT' => 1,
'AM_CONDITIONAL' => 1,
'AC_REPLACE_FNMATCH' => 1,
'AC_FUNC_MKTIME' => 1,
'AC_FUNC_CLOSEDIR_VOID' => 1,
'AC_PROG_GCC_TRADITIONAL' => 1,
'AC_FUNC_VPRINTF' => 1,
'AC_FUNC_MBRTOWC' => 1,
'AC_FUNC_STRTOD' => 1,
'AC_TYPE_MODE_T' => 1,
'AC_C_VOLATILE' => 1,
'AC_FUNC_STRNLEN' => 1,
'AM_AUTOMAKE_VERSION' => 1,
'AC_PROG_CXX' => 1,
'AC_TYPE_PID_T' => 1,
'AC_STRUCT_ST_BLOCKS' => 1,
'AC_PROG_INSTALL' => 1,
'AC_PROG_CC' => 1,
'AC_TYPE_OFF_T' => 1,
'AC_FUNC_FORK' => 1,
'AM_INIT_AUTOMAKE' => 1,
'AC_PROG_LN_S' => 1,
'AC_C_VOLATILE' => 1,
'AC_TYPE_SIZE_T' => 1,
'AM_GNU_GETTEXT' => 1,
'AC_C_CONST' => 1,
'AC_PATH_X' => 1,
'AC_DEFINE_TRACE_LITERAL' => 1,
'AC_STRUCT_TIMEZONE' => 1,
'AC_FUNC_MEMCMP' => 1,
'AC_CHECK_TYPES' => 1,
'AC_CANONICAL_SYSTEM' => 1,
'AC_HEADER_SYS_WAIT' => 1,
'AC_SUBST' => 1,
'AC_PROG_AWK' => 1,
'AC_FUNC_REALLOC' => 1,
'AC_PROG_RANLIB' => 1,
'AC_FUNC_SELECT_ARGTYPES' => 1,
'AC_DECL_SYS_SIGLIST' => 1,
'AM_MAINTAINER_MODE' => 1,
'AC_FUNC_MALLOC' => 1,
'AC_FUNC_STRCOLL' => 1,
'AC_PROG_LIBTOOL' => 1,
'AC_FUNC_GETPGRP' => 1,
'AC_CHECK_LIB' => 1,
'AC_FUNC_SETVBUF_REVERSED' => 1,
'AC_CHECK_FUNCS' => 1,
'AC_LIBSOURCE' => 1,
'AC_FUNC_ERROR_AT_LINE' => 1,
'AC_DEFINE_TRACE_LITERAL' => 1,
'AC_STRUCT_TM' => 1,
'AC_CONFIG_SUBDIRS' => 1,
'AC_FUNC_WAIT3' => 1,
'AC_PROG_CPP' => 1,
'AC_FUNC_GETLOADAVG' => 1,
'AC_TYPE_UID_T' => 1,
'AC_CANONICAL_HOST' => 1,
'AC_CONFIG_FILES' => 1,
'AC_FUNC_STAT' => 1,
'AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK' => 1,
'AC_PROG_LEX' => 1,
'AC_FUNC_CLOSEDIR_VOID' => 1,
'AC_TYPE_SIZE_T' => 1,
'AC_PROG_LN_S' => 1,
'AC_PROG_MAKE_SET' => 1,
'AC_FUNC_ALLOCA' => 1,
'AC_C_INLINE' => 1,
'AC_FUNC_FSEEKO' => 1,
'AC_CONFIG_HEADERS' => 1,
'm4_include' => 1,
'AC_HEADER_DIRENT' => 1,
'AC_LIBSOURCE' => 1,
'AC_C_INLINE' => 1,
'AC_DECL_SYS_SIGLIST' => 1,
'AC_FUNC_OBSTACK' => 1,
'AC_CHECK_FUNCS' => 1,
'AC_FUNC_UTIME_NULL' => 1,
'AC_STRUCT_ST_BLOCKS' => 1,
'AC_FUNC_GETLOADAVG' => 1,
'AC_PROG_INSTALL' => 1,
'AM_GNU_GETTEXT' => 1,
'AC_CONFIG_AUX_DIR' => 1,
'AC_HEADER_STDC' => 1,
'AC_PROG_YACC' => 1,
'AC_PROG_RANLIB' => 1,
'AC_CONFIG_HEADERS' => 1,
'AC_FUNC_STRCOLL' => 1,
'AC_HEADER_TIME' => 1,
'AC_FUNC_WAIT3' => 1,
'AC_SUBST' => 1,
'AH_OUTPUT' => 1,
'AC_FUNC_CHOWN' => 1,
'AC_FUNC_LSTAT' => 1,
'AC_CHECK_MEMBERS' => 1,
'AM_PROG_CC_C_O' => 1,
'AC_PROG_CPP' => 1,
'AC_PROG_CXX' => 1,
'AC_HEADER_DIRENT' => 1,
'AC_FUNC_ERROR_AT_LINE' => 1,
'AC_FUNC_MBRTOWC' => 1,
'AC_PATH_X' => 1,
'AC_FUNC_STAT' => 1,
'm4_pattern_forbid' => 1,
'AC_HEADER_STAT' => 1,
'AC_FUNC_UTIME_NULL' => 1,
'AC_FUNC_GETMNTENT' => 1,
'AC_FUNC_SETPGRP' => 1,
'AC_FUNC_STRFTIME' => 1,
'AC_FUNC_OBSTACK' => 1,
'AC_FUNC_GETGROUPS' => 1,
'AC_HEADER_TIME' => 1,
'AC_TYPE_MODE_T' => 1,
'AC_PROG_YACC' => 1,
'AC_TYPE_PID_T' => 1,
'AC_PROG_LEX' => 1,
'AC_TYPE_OFF_T' => 1,
'AC_PROG_CC' => 1,
'AC_CANONICAL_SYSTEM' => 1,
'AC_CHECK_LIB' => 1,
'AC_FUNC_SETVBUF_REVERSED' => 1,
'AC_CANONICAL_HOST' => 1,
'AC_FUNC_MMAP' => 1,
'AM_CONDITIONAL' => 1,
'AM_PROG_CC_C_O' => 1,
'm4_include' => 1,
'AC_HEADER_MAJOR' => 1,
'AC_FUNC_MKTIME' => 1,
'AC_FUNC_GETPGRP' => 1,
'AC_CHECK_HEADERS' => 1,
'AC_FUNC_STRTOD' => 1,
'AC_FUNC_MALLOC' => 1,
'AC_HEADER_SYS_WAIT' => 1,
'AC_FUNC_SELECT_ARGTYPES' => 1,
'AC_FUNC_VPRINTF' => 1,
'AC_FUNC_STRERROR_R' => 1,
'AC_CHECK_MEMBERS' => 1,
'AC_INIT' => 1,
'AM_MAINTAINER_MODE' => 1,
'AC_C_CONST' => 1,
'AC_FUNC_MEMCMP' => 1,
'AM_INIT_AUTOMAKE' => 1,
'AC_FUNC_ALLOCA' => 1,
'm4_pattern_allow' => 1,
'AC_STRUCT_TIMEZONE' => 1,
'AC_PROG_AWK' => 1,
'AC_FUNC_REALLOC' => 1,
'AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK' => 1,
'include' => 1,
'AC_TYPE_SIGNAL' => 1,
'AC_CONFIG_AUX_DIR' => 1,
'include' => 1
'AC_FUNC_FORK' => 1,
'AC_CONFIG_SUBDIRS' => 1,
'AC_PROG_GCC_TRADITIONAL' => 1,
'AC_CONFIG_FILES' => 1,
'AC_FUNC_GETGROUPS' => 1,
'AC_CHECK_TYPES' => 1,
'AC_FUNC_SETPGRP' => 1,
'AC_REPLACE_FNMATCH' => 1,
'AC_FUNC_STRFTIME' => 1,
'AC_HEADER_STAT' => 1,
'AC_TYPE_UID_T' => 1,
'AC_FUNC_GETMNTENT' => 1
}
], 'Request' )
);
+58 -58
View File
@@ -1124,73 +1124,73 @@ m4trace:configure.in:825: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STD_PUTENV])
m4trace:configure.in:827: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STD_PUTENV])
m4trace:configure.in:830: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STD_UNSETENV])
m4trace:configure.in:832: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STD_UNSETENV])
m4trace:configure.in:847: -1- AC_DEFINE_TRACE_LITERAL([HAVE_PRINTF_A_FORMAT])
m4trace:configure.in:850: -1- AC_DEFINE_TRACE_LITERAL([MUST_REINSTALL_SIGHANDLERS])
m4trace:configure.in:851: -1- AC_DEFINE_TRACE_LITERAL([JOB_CONTROL_MISSING])
m4trace:configure.in:852: -1- AC_DEFINE_TRACE_LITERAL([NAMED_PIPES_MISSING])
m4trace:configure.in:855: -1- AC_DEFINE_TRACE_LITERAL([GWINSZ_IN_SYS_IOCTL])
m4trace:configure.in:855: -1- AH_OUTPUT([GWINSZ_IN_SYS_IOCTL], [/* Define to 1 if `TIOCGWINSZ\' requires <sys/ioctl.h>. */
m4trace:configure.in:835: -1- AC_DEFINE_TRACE_LITERAL([HAVE_PRINTF_A_FORMAT])
m4trace:configure.in:838: -1- AC_DEFINE_TRACE_LITERAL([MUST_REINSTALL_SIGHANDLERS])
m4trace:configure.in:839: -1- AC_DEFINE_TRACE_LITERAL([JOB_CONTROL_MISSING])
m4trace:configure.in:840: -1- AC_DEFINE_TRACE_LITERAL([NAMED_PIPES_MISSING])
m4trace:configure.in:843: -1- AC_DEFINE_TRACE_LITERAL([GWINSZ_IN_SYS_IOCTL])
m4trace:configure.in:843: -1- AH_OUTPUT([GWINSZ_IN_SYS_IOCTL], [/* Define to 1 if `TIOCGWINSZ\' requires <sys/ioctl.h>. */
#undef GWINSZ_IN_SYS_IOCTL])
m4trace:configure.in:856: -1- AC_DEFINE_TRACE_LITERAL([TIOCSTAT_IN_SYS_IOCTL])
m4trace:configure.in:857: -1- AC_DEFINE_TRACE_LITERAL([FIONREAD_IN_SYS_IOCTL])
m4trace:configure.in:860: -1- AC_DEFINE_TRACE_LITERAL([SPEED_T_IN_SYS_TYPES])
m4trace:configure.in:861: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETPW_DECLS])
m4trace:configure.in:862: -1- AC_DEFINE_TRACE_LITERAL([UNUSABLE_RT_SIGNALS])
m4trace:configure.in:863: -1- AC_SUBST([SIGLIST_O])
m4trace:configure.in:867: -1- AC_DEFINE_TRACE_LITERAL([RLIMIT_NEEDS_KERNEL])
m4trace:configure.in:875: -1- AC_CHECK_LIB([termcap], [tgetent], [bash_cv_termcap_lib=libtermcap], [AC_CHECK_LIB(tinfo, tgetent, bash_cv_termcap_lib=libtinfo,
m4trace:configure.in:844: -1- AC_DEFINE_TRACE_LITERAL([TIOCSTAT_IN_SYS_IOCTL])
m4trace:configure.in:845: -1- AC_DEFINE_TRACE_LITERAL([FIONREAD_IN_SYS_IOCTL])
m4trace:configure.in:848: -1- AC_DEFINE_TRACE_LITERAL([SPEED_T_IN_SYS_TYPES])
m4trace:configure.in:849: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETPW_DECLS])
m4trace:configure.in:850: -1- AC_DEFINE_TRACE_LITERAL([UNUSABLE_RT_SIGNALS])
m4trace:configure.in:851: -1- AC_SUBST([SIGLIST_O])
m4trace:configure.in:855: -1- AC_DEFINE_TRACE_LITERAL([RLIMIT_NEEDS_KERNEL])
m4trace:configure.in:863: -1- AC_CHECK_LIB([termcap], [tgetent], [bash_cv_termcap_lib=libtermcap], [AC_CHECK_LIB(tinfo, tgetent, bash_cv_termcap_lib=libtinfo,
[AC_CHECK_LIB(curses, tgetent, bash_cv_termcap_lib=libcurses,
[AC_CHECK_LIB(ncurses, tgetent, bash_cv_termcap_lib=libncurses,
bash_cv_termcap_lib=gnutermcap)])])])
m4trace:configure.in:875: -1- AC_CHECK_LIB([tinfo], [tgetent], [bash_cv_termcap_lib=libtinfo], [AC_CHECK_LIB(curses, tgetent, bash_cv_termcap_lib=libcurses,
m4trace:configure.in:863: -1- AC_CHECK_LIB([tinfo], [tgetent], [bash_cv_termcap_lib=libtinfo], [AC_CHECK_LIB(curses, tgetent, bash_cv_termcap_lib=libcurses,
[AC_CHECK_LIB(ncurses, tgetent, bash_cv_termcap_lib=libncurses,
bash_cv_termcap_lib=gnutermcap)])])
m4trace:configure.in:875: -1- AC_CHECK_LIB([curses], [tgetent], [bash_cv_termcap_lib=libcurses], [AC_CHECK_LIB(ncurses, tgetent, bash_cv_termcap_lib=libncurses,
m4trace:configure.in:863: -1- AC_CHECK_LIB([curses], [tgetent], [bash_cv_termcap_lib=libcurses], [AC_CHECK_LIB(ncurses, tgetent, bash_cv_termcap_lib=libncurses,
bash_cv_termcap_lib=gnutermcap)])
m4trace:configure.in:875: -1- AC_CHECK_LIB([ncurses], [tgetent], [bash_cv_termcap_lib=libncurses], [bash_cv_termcap_lib=gnutermcap])
m4trace:configure.in:877: -1- AC_SUBST([TERMCAP_LIB])
m4trace:configure.in:878: -1- AC_SUBST([TERMCAP_DEP])
m4trace:configure.in:880: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_FD])
m4trace:configure.in:880: -1- AC_DEFINE_TRACE_LITERAL([DEV_FD_PREFIX])
m4trace:configure.in:880: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_FD])
m4trace:configure.in:880: -1- AC_DEFINE_TRACE_LITERAL([DEV_FD_PREFIX])
m4trace:configure.in:881: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_STDIN])
m4trace:configure.in:882: -1- AC_DEFINE_TRACE_LITERAL([DEFAULT_MAIL_DIRECTORY])
m4trace:configure.in:889: -1- AC_DEFINE_TRACE_LITERAL([JOB_CONTROL])
m4trace:configure.in:895: -1- AC_SUBST([JOBS_O])
m4trace:configure.in:908: -1- AC_DEFINE_TRACE_LITERAL([SVR4_2])
m4trace:configure.in:909: -1- AC_DEFINE_TRACE_LITERAL([SVR4])
m4trace:configure.in:910: -1- AC_DEFINE_TRACE_LITERAL([SVR4])
m4trace:configure.in:911: -1- AC_DEFINE_TRACE_LITERAL([SVR5])
m4trace:configure.in:968: -1- AC_SUBST([SHOBJ_CC])
m4trace:configure.in:969: -1- AC_SUBST([SHOBJ_CFLAGS])
m4trace:configure.in:970: -1- AC_SUBST([SHOBJ_LD])
m4trace:configure.in:971: -1- AC_SUBST([SHOBJ_LDFLAGS])
m4trace:configure.in:972: -1- AC_SUBST([SHOBJ_XLDFLAGS])
m4trace:configure.in:973: -1- AC_SUBST([SHOBJ_LIBS])
m4trace:configure.in:974: -1- AC_SUBST([SHOBJ_STATUS])
m4trace:configure.in:995: -1- AC_SUBST([PROFILE_FLAGS])
m4trace:configure.in:997: -1- AC_SUBST([incdir])
m4trace:configure.in:998: -1- AC_SUBST([BUILD_DIR])
m4trace:configure.in:1000: -1- AC_SUBST([YACC])
m4trace:configure.in:1001: -1- AC_SUBST([AR])
m4trace:configure.in:1002: -1- AC_SUBST([ARFLAGS])
m4trace:configure.in:1004: -1- AC_SUBST([BASHVERS])
m4trace:configure.in:1005: -1- AC_SUBST([RELSTATUS])
m4trace:configure.in:1006: -1- AC_SUBST([DEBUG])
m4trace:configure.in:1007: -1- AC_SUBST([MALLOC_DEBUG])
m4trace:configure.in:1009: -1- AC_SUBST([host_cpu])
m4trace:configure.in:1010: -1- AC_SUBST([host_vendor])
m4trace:configure.in:1011: -1- AC_SUBST([host_os])
m4trace:configure.in:1013: -1- AC_SUBST([LOCAL_LIBS])
m4trace:configure.in:1014: -1- AC_SUBST([LOCAL_CFLAGS])
m4trace:configure.in:1015: -1- AC_SUBST([LOCAL_LDFLAGS])
m4trace:configure.in:1016: -1- AC_SUBST([LOCAL_DEFS])
m4trace:configure.in:1030: -1- AC_CONFIG_FILES([Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile \
m4trace:configure.in:863: -1- AC_CHECK_LIB([ncurses], [tgetent], [bash_cv_termcap_lib=libncurses], [bash_cv_termcap_lib=gnutermcap])
m4trace:configure.in:865: -1- AC_SUBST([TERMCAP_LIB])
m4trace:configure.in:866: -1- AC_SUBST([TERMCAP_DEP])
m4trace:configure.in:868: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_FD])
m4trace:configure.in:868: -1- AC_DEFINE_TRACE_LITERAL([DEV_FD_PREFIX])
m4trace:configure.in:868: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_FD])
m4trace:configure.in:868: -1- AC_DEFINE_TRACE_LITERAL([DEV_FD_PREFIX])
m4trace:configure.in:869: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_STDIN])
m4trace:configure.in:870: -1- AC_DEFINE_TRACE_LITERAL([DEFAULT_MAIL_DIRECTORY])
m4trace:configure.in:877: -1- AC_DEFINE_TRACE_LITERAL([JOB_CONTROL])
m4trace:configure.in:883: -1- AC_SUBST([JOBS_O])
m4trace:configure.in:896: -1- AC_DEFINE_TRACE_LITERAL([SVR4_2])
m4trace:configure.in:897: -1- AC_DEFINE_TRACE_LITERAL([SVR4])
m4trace:configure.in:898: -1- AC_DEFINE_TRACE_LITERAL([SVR4])
m4trace:configure.in:899: -1- AC_DEFINE_TRACE_LITERAL([SVR5])
m4trace:configure.in:956: -1- AC_SUBST([SHOBJ_CC])
m4trace:configure.in:957: -1- AC_SUBST([SHOBJ_CFLAGS])
m4trace:configure.in:958: -1- AC_SUBST([SHOBJ_LD])
m4trace:configure.in:959: -1- AC_SUBST([SHOBJ_LDFLAGS])
m4trace:configure.in:960: -1- AC_SUBST([SHOBJ_XLDFLAGS])
m4trace:configure.in:961: -1- AC_SUBST([SHOBJ_LIBS])
m4trace:configure.in:962: -1- AC_SUBST([SHOBJ_STATUS])
m4trace:configure.in:983: -1- AC_SUBST([PROFILE_FLAGS])
m4trace:configure.in:985: -1- AC_SUBST([incdir])
m4trace:configure.in:986: -1- AC_SUBST([BUILD_DIR])
m4trace:configure.in:988: -1- AC_SUBST([YACC])
m4trace:configure.in:989: -1- AC_SUBST([AR])
m4trace:configure.in:990: -1- AC_SUBST([ARFLAGS])
m4trace:configure.in:992: -1- AC_SUBST([BASHVERS])
m4trace:configure.in:993: -1- AC_SUBST([RELSTATUS])
m4trace:configure.in:994: -1- AC_SUBST([DEBUG])
m4trace:configure.in:995: -1- AC_SUBST([MALLOC_DEBUG])
m4trace:configure.in:997: -1- AC_SUBST([host_cpu])
m4trace:configure.in:998: -1- AC_SUBST([host_vendor])
m4trace:configure.in:999: -1- AC_SUBST([host_os])
m4trace:configure.in:1001: -1- AC_SUBST([LOCAL_LIBS])
m4trace:configure.in:1002: -1- AC_SUBST([LOCAL_CFLAGS])
m4trace:configure.in:1003: -1- AC_SUBST([LOCAL_LDFLAGS])
m4trace:configure.in:1004: -1- AC_SUBST([LOCAL_DEFS])
m4trace:configure.in:1018: -1- AC_CONFIG_FILES([Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile \
lib/intl/Makefile \
lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile \
lib/tilde/Makefile doc/Makefile support/Makefile po/Makefile.in \
examples/loadables/Makefile examples/loadables/perl/Makefile \
pathnames.h])
m4trace:configure.in:1030: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs])
m4trace:configure.in:1030: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs])
m4trace:configure.in:1018: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs])
m4trace:configure.in:1018: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs])
Vendored
+1 -2
View File
@@ -1,5 +1,5 @@
#! /bin/sh
# From configure.in for Bash 3.0, version 3.160, from autoconf version AC_ACVERSION.
# From configure.in for Bash 3.0, version 3.161, from autoconf version AC_ACVERSION.
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.57 for bash 3.0-beta1.
#
@@ -22719,7 +22719,6 @@ _ACEOF
fi
echo "$as_me:$LINENO: checking for printf floating point output in hex notation" >&5
echo $ECHO_N "checking for printf floating point output in hex notation... $ECHO_C" >&6
if test "${bash_cv_printf_a_format+set}" = set; then
+1 -13
View File
@@ -22,7 +22,7 @@ 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.0, version 3.160, from autoconf version] AC_ACVERSION)dnl
AC_REVISION([for Bash 3.0, version 3.161, from autoconf version] AC_ACVERSION)dnl
define(bashvers, 3.0)
define(relstatus, beta1)
@@ -832,18 +832,6 @@ else
AC_DEFINE(HAVE_STD_UNSETENV)
fi
dnl I have removed this check. The existing libc FNM_EXTMATCH implementation
dnl (glibc-2.2.4) disagrees with bash on the matching of incorrectly-formed
dnl patterns (bash treats them as strings or characters to be matched without
dnl any special meaning) and has one outright bug: a[X-]b should match
dnl both a-b and aXb.
dnl
dnl Once Ulrich and I get together on this, the check can return
dnl
dnl chet 10/31/2001
dnl
dnl BASH_FUNC_FNMATCH_EXTMATCH
BASH_FUNC_PRINTF_A_FORMAT
dnl presence and behavior of OS functions
+3 -1
View File
@@ -4767,7 +4767,9 @@ BBUUGGSS
Commands inside of $$((...)) command substitution are not parsed until
substitution is attempted. This will delay error reporting until some
time after the command is entered.
time after the command is entered. For example, unmatched parentheses,
even inside shell comments, will result in error messages while the
construct is being read.
Array variables may not (yet) be exported.
+3 -1
View File
@@ -8720,7 +8720,9 @@ a unit.
.PP
Commands inside of \fB$(\fP...\fB)\fP command substitution are not
parsed until substitution is attempted. This will delay error
reporting until some time after the command is entered.
reporting until some time after the command is entered. For example,
unmatched parentheses, even inside shell comments, will result in
error messages while the construct is being read.
.PP
Array variables may not (yet) be exported.
.zZ
+4 -2
View File
@@ -11233,7 +11233,9 @@ a unit.
Commands inside of <B>$(</B>...<B>)</B> command substitution are not
parsed until substitution is attempted. This will delay error
reporting until some time after the command is entered.
reporting until some time after the command is entered. For example,
unmatched parentheses, even inside shell comments, will result in
error messages while the construct is being read.
<P>
Array variables may not (yet) be exported.
@@ -11341,6 +11343,6 @@ Array variables may not (yet) be exported.
</DL>
<HR>
This document was created by man2html from bash.1.<BR>
Time: 28 January 2004 15:50:27 EST
Time: 29 January 2004 16:59:30 EST
</BODY>
</HTML>
+9 -5
View File
@@ -1,6 +1,6 @@
%!PS-Adobe-3.0
%%Creator: groff version 1.18.1
%%CreationDate: Wed Jan 28 15:50:15 2004
%%CreationDate: Thu Jan 29 16:59:28 2004
%%DocumentNeededResources: font Times-Roman
%%+ font Times-Bold
%%+ font Times-Italic
@@ -7241,10 +7241,14 @@ F1(bashbug)108.13 393.6 Q F2 1.316(inserts the \214rst thr)4.296 F 1.316
(ce it into a subshell, which may be stopped as a unit.)-.18 E .95
(Commands inside of)108 595.2 R F4($\()3.451 E F2(...)A F4(\))A F2 .951
(command substitution ar)3.451 F 3.451(en)-.18 G .951
(ot parsed until substitution is attempted.)-3.451 F
(This will delay err)108 607.2 Q(or r)-.18 E
(eporting until some time after the command is enter)-.18 E(ed.)-.18 E
(Array variables may not \(yet\) be exported.)108 624 Q F0(GNU Bash-3.0)
(ot parsed until substitution is attempted.)-3.451 F 2.132
(This will delay err)108 607.2 R 2.132(or r)-.18 F 2.131
(eporting until some time after the command is enter)-.18 F 4.631
(ed. For)-.18 F(example,)4.631 E .43(unmatched par)108 619.2 R .431
(entheses, even inside shell comments, will r)-.18 F .431(esult in err)
-.18 F .431(or messages while the con-)-.18 F(str)108 631.2 Q
(uct is being r)-.08 E(ead.)-.18 E
(Array variables may not \(yet\) be exported.)108 648 Q F0(GNU Bash-3.0)
72 768 Q(2004 Jan 28)149.845 E(63)199.835 E 0 Cg EP
%%Trailer
end
+1 -1
View File
@@ -1,6 +1,6 @@
%!PS-Adobe-3.0
%%Creator: groff version 1.18.1
%%CreationDate: Wed Jan 28 15:50:16 2004
%%CreationDate: Thu Jan 29 16:59:29 2004
%%DocumentNeededResources: font Times-Roman
%%+ font Times-Bold
%%+ font Times-Italic
+1 -1
View File
@@ -1,6 +1,6 @@
%!PS-Adobe-3.0
%%Creator: groff version 1.18.1
%%CreationDate: Wed Jan 28 15:50:16 2004
%%CreationDate: Thu Jan 29 16:59:29 2004
%%DocumentNeededResources: font Times-Roman
%%+ font Times-Bold
%%DocumentSuppliedResources: procset grops 1.18 1
+1
View File
@@ -67,6 +67,7 @@
#if defined (HANDLE_MULTIBYTE)
extern size_t xmbsrtowcs __P((wchar_t *, const char **, size_t, mbstate_t *));
extern size_t xdupmbstowcs __P((wchar_t **, char ***, const char *));
extern char *xstrchr __P((const char *, int));
+2 -2
View File
@@ -442,8 +442,8 @@ extern char *xstrchr __P((const char *, int));
/* Watch out when using this -- it's just straight textual subsitution */
#if defined (HANDLE_MULTIBYTE)
# define SADD_MBQCHAR_BODY(_dst, _src, _si, _srcsize) \
\ int i; \
\
int i; \
mbstate_t state_bak; \
size_t mblength; \
\
+25 -52
View File
@@ -62,6 +62,10 @@
# endif /* __STDC__ */
#endif /* !NULL */
#if !defined (FREE)
# define FREE(x) if (x) free (x)
#endif
extern void throw_to_top_level __P((void));
extern int test_eaccess __P((char *, int));
@@ -118,7 +122,6 @@ glob_pattern_p (pattern)
const char *pattern;
{
#if HANDLE_MULTIBYTE
mbstate_t ps;
size_t n;
wchar_t *wpattern;
int r;
@@ -127,15 +130,14 @@ glob_pattern_p (pattern)
return (internal_glob_pattern_p (pattern));
/* Convert strings to wide chars, and call the multibyte version. */
memset (&ps, '\0', sizeof (ps));
n = xmbsrtowcs (NULL, (const char **)&pattern, 0, &ps);
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 (pattern));
wpattern = (wchar_t *)xmalloc ((n + 1) * sizeof (wchar_t));
(void) xmbsrtowcs (wpattern, (const char **)&pattern, n + 1, &ps);
r = internal_glob_wpattern_p (wpattern);
free (wpattern);
return r;
#else
return (internal_glob_pattern_p (pattern));
@@ -174,57 +176,36 @@ static int
mbskipname (pat, dname)
char *pat, *dname;
{
char *pat_bak, *dn_bak;
int ret;
wchar_t *pat_wc, *dn_wc;
mbstate_t pat_ps, dn_ps;
size_t pat_n, dn_n, n;
n = strlen(pat);
pat_bak = (char *) alloca (n + 1);
if (pat_bak == 0)
return 0;
memcpy (pat_bak, pat, n + 1);
n = strlen(dname);
dn_bak = (char *) alloca (n + 1);
if (dn_bak == 0)
return 0;
memcpy (dn_bak, dname, n + 1);
memset(&pat_ps, '\0', sizeof(mbstate_t));
memset(&dn_ps, '\0', sizeof(mbstate_t));
pat_n = xmbsrtowcs (NULL, (const char **)&pat_bak, 0, &pat_ps);
dn_n = xmbsrtowcs (NULL, (const char **)&dn_bak, 0, &dn_ps);
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)
{
pat_wc = (wchar_t *) alloca ((pat_n + 1) * sizeof(wchar_t));
dn_wc = (wchar_t *) alloca ((dn_n + 1) * sizeof(wchar_t));
if (pat_wc == 0 || dn_wc == 0)
return 0;
(void) xmbsrtowcs (pat_wc, (const char **)&pat_bak, pat_n + 1, &pat_ps);
(void) xmbsrtowcs (dn_wc, (const char **)&dn_bak, dn_n + 1, &dn_ps);
/* 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'))))
return 1;
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'.'))
return 1;
ret = 1;
}
return 0;
FREE (pat_wc);
FREE (dn_wc);
return ret;
}
#endif /* HANDLE_MULTIBYTE */
@@ -242,7 +223,7 @@ udequote_pathname (pathname)
pathname[j++] = pathname[i++];
if (!pathname[i - 1])
if (pathname[i - 1] == 0)
break;
}
pathname[j] = '\0';
@@ -257,27 +238,16 @@ wdequote_pathname (pathname)
mbstate_t ps;
size_t len, n;
wchar_t *wpathname;
char *pathname_bak;
int i, j;
wchar_t *orig_wpathname;
len = strlen (pathname);
pathname_bak = (char *) alloca (len + 1);
if (pathname_bak == 0)
return;
memcpy (pathname_bak, pathname , len + 1);
/* Convert the strings into wide characters. */
memset (&ps, '\0', sizeof (ps));
n = xmbsrtowcs (NULL, (const char **)&pathname_bak, 0, &ps);
n = xdupmbstowcs (&wpathname, NULL, pathname);
if (n == (size_t) -1)
/* Something wrong. */
return;
wpathname = (wchar_t *)alloca ((n + 1) * sizeof (wchar_t));
if (wpathname == 0)
return;
(void) xmbsrtowcs (wpathname, (const char **)&pathname_bak, n + 1, &ps);
orig_wpathname = wpathname;
for (i = j = 0; wpathname && wpathname[i]; )
{
@@ -286,7 +256,7 @@ wdequote_pathname (pathname)
wpathname[j++] = wpathname[i++];
if (!wpathname[i - 1])
if (wpathname[i - 1] == L'\0')
break;
}
wpathname[j] = L'\0';
@@ -295,6 +265,9 @@ wdequote_pathname (pathname)
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
+839
View File
@@ -0,0 +1,839 @@
/* glob.c -- file-name wildcard pattern matching for Bash.
Copyright (C) 1985-2002 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 "quit.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
extern void throw_to_top_level __P((void));
extern int test_eaccess __P((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;
/* Some forward declarations. */
static int skipname __P((char *, char *));
#if HANDLE_MULTIBYTE
static int mbskipname __P((char *, char *));
#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 (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 (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)
char *pat;
char *dname;
{
/* 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)
char *pat, *dname;
{
int ret;
wchar_t *pat_wc, *dn_wc;
size_t pat_n, dn_n, 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';
if (wpathname != orig_wpathname)
itrace("wdequote_pathname: 1: wpathname (%p) != orig_wpathname (%p)", wpathname, orig_wpathname);
/* 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';
if (wpathname != orig_wpathname)
itrace("wdequote_pathname: 2: wpathname (%p) != orig_wpathname (%p)", wpathname, orig_wpathname);
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) (test_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);
}
/* 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;
{
struct globval
{
struct globval *next;
char *name;
};
DIR *d;
register struct dirent *dp;
struct globval *lastlink;
register struct globval *nextlink;
register char *nextname, *npat;
unsigned int count;
int lose, skip;
register char **name_vector;
register unsigned int i;
int mflags; /* Flags passed to strmatch (). */
lastlink = 0;
count = lose = skip = 0;
/* 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;
/* 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)
{
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 HANDLE_MULTIBYTE
if (MB_CUR_MAX > 1 && mbskipname (pat, dp->d_name))
continue;
else
#endif
if (skipname (pat, dp->d_name))
continue;
if (strmatch (pat, dp->d_name, mflags) != FNM_NOMATCH)
{
nextname = (char *) malloc (D_NAMLEN (dp) + 1);
nextlink = (struct globval *) alloca (sizeof (struct globval));
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);
}
if (lose == 0)
{
name_vector = (char **) malloc ((count + 1) * sizeof (char *));
lose |= name_vector == NULL;
}
/* Have we run out of memory? */
if (lose)
{
/* Here free the strings we have got. */
while (lastlink)
{
free (lastlink->name);
lastlink = lastlink->next;
}
QUIT;
return ((char **)NULL);
}
/* Copy the name pointers from the linked list into the vector. */
for (i = 0; i < count; ++i)
{
name_vector[i] = lastlink->name;
lastlink = lastlink->next;
}
name_vector[count] = NULL;
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;
unsigned int directory_len;
int free_dirname; /* flag */
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;
if (directory_name[directory_len - 1] == '/')
directory_name[directory_len - 1] = '\0';
directories = glob_filename (directory_name, flags & ~GX_MARKDIRS);
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 pathname. 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);
/* 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. */
temp_results = glob_vector (filename,
(directory_len == 0 ? "." : directory_name),
flags & ~GX_MARKDIRS);
if (temp_results == NULL || temp_results == (char **)&glob_error_return)
{
if (free_dirname)
free (directory_name);
return (temp_results);
}
result = glob_dir_to_array (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. */
+4 -3
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 1991-2002 Free Software Foundation, Inc.
/* Copyright (C) 1991-2004 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -16,14 +16,15 @@
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
static int FCT __P((CHAR *, CHAR *, int));
int FCT __P((CHAR *, CHAR *, int));
static int GMATCH __P((CHAR *, CHAR *, CHAR *, CHAR *, int));
static CHAR *PARSE_COLLSYM __P((CHAR *, INT *));
static CHAR *BRACKMATCH __P((CHAR *, U_CHAR, int));
static int EXTMATCH __P((INT, CHAR *, CHAR *, CHAR *, CHAR *, int));
static CHAR *PATSCAN __P((CHAR *, CHAR *, INT));
static int
int
FCT (pattern, string, flags)
CHAR *pattern;
CHAR *string;
+750
View File
@@ -0,0 +1,750 @@
/* Copyright (C) 1991-2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
static int FCT __P((CHAR *, CHAR *, int));
static int GMATCH __P((CHAR *, CHAR *, CHAR *, CHAR *, int));
static CHAR *PARSE_COLLSYM __P((CHAR *, INT *));
static CHAR *BRACKMATCH __P((CHAR *, U_CHAR, int));
static int EXTMATCH __P((INT, CHAR *, CHAR *, CHAR *, CHAR *, int));
static CHAR *PATSCAN __P((CHAR *, CHAR *, INT));
static int
FCT (pattern, string, flags)
CHAR *pattern;
CHAR *string;
int flags;
{
CHAR *se, *pe;
if (string == 0 || pattern == 0)
return FNM_NOMATCH;
se = string + STRLEN ((XCHAR *)string);
pe = pattern + STRLEN ((XCHAR *)pattern);
return (GMATCH (string, se, pattern, pe, flags));
}
/* Match STRING against the filename pattern PATTERN, returning zero if
it matches, FNM_NOMATCH if not. */
static int
GMATCH (string, se, pattern, pe, flags)
CHAR *string, *se;
CHAR *pattern, *pe;
int flags;
{
CHAR *p, *n; /* pattern, string */
INT c; /* current pattern character - XXX U_CHAR? */
INT sc; /* current string character - XXX U_CHAR? */
p = pattern;
n = string;
if (string == 0 || pattern == 0)
return FNM_NOMATCH;
#if DEBUG_MATCHING
fprintf(stderr, "gmatch: string = %s; se = %s\n", string, se);
fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
#endif
while (p < pe)
{
c = *p++;
c = FOLD (c);
sc = n < se ? *n : '\0';
#ifdef EXTENDED_GLOB
/* EXTMATCH () will handle recursively calling GMATCH, so we can
just return what EXTMATCH() returns. */
if ((flags & FNM_EXTMATCH) && *p == L('(') &&
(c == L('+') || c == L('*') || c == L('?') || c == L('@') || c == L('!'))) /* ) */
{
int lflags;
/* If we're not matching the start of the string, we're not
concerned about the special cases for matching `.' */
lflags = (n == string) ? flags : (flags & ~FNM_PERIOD);
return (EXTMATCH (c, n, se, p, pe, lflags));
}
#endif /* EXTENDED_GLOB */
switch (c)
{
case L('?'): /* Match single character */
if (sc == '\0')
return FNM_NOMATCH;
else if ((flags & FNM_PATHNAME) && sc == L('/'))
/* If we are matching a pathname, `?' can never match a `/'. */
return FNM_NOMATCH;
else if ((flags & FNM_PERIOD) && sc == L('.') &&
(n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/'))))
/* `?' cannot match a `.' if it is the first character of the
string or if it is the first character following a slash and
we are matching a pathname. */
return FNM_NOMATCH;
break;
case L('\\'): /* backslash escape removes special meaning */
if (p == pe)
return FNM_NOMATCH;
if ((flags & FNM_NOESCAPE) == 0)
{
c = *p++;
/* A trailing `\' cannot match. */
if (p > pe)
return FNM_NOMATCH;
c = FOLD (c);
}
if (FOLD (sc) != (U_CHAR)c)
return FNM_NOMATCH;
break;
case '*': /* Match zero or more characters */
if (p == pe)
return 0;
if ((flags & FNM_PERIOD) && sc == L('.') &&
(n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/'))))
/* `*' cannot match a `.' if it is the first character of the
string or if it is the first character following a slash and
we are matching a pathname. */
return FNM_NOMATCH;
/* Collapse multiple consecutive `*' and `?', but make sure that
one character of the string is consumed for each `?'. */
for (c = *p++; (c == L('?') || c == L('*')); c = *p++)
{
if ((flags & FNM_PATHNAME) && sc == L('/'))
/* A slash does not match a wildcard under FNM_PATHNAME. */
return FNM_NOMATCH;
#ifdef EXTENDED_GLOB
else if ((flags & FNM_EXTMATCH) && c == L('?') && *p == L('(')) /* ) */
{
CHAR *newn;
for (newn = n; newn < se; ++newn)
{
if (EXTMATCH (c, newn, se, p, pe, flags) == 0)
return (0);
}
/* We didn't match. If we have a `?(...)', that's failure. */
return FNM_NOMATCH;
}
#endif
else if (c == L('?'))
{
if (sc == L('\0'))
return FNM_NOMATCH;
/* One character of the string is consumed in matching
this ? wildcard, so *??? won't match if there are
fewer than three characters. */
n++;
sc = n < se ? *n : '\0';
}
#ifdef EXTENDED_GLOB
/* Handle ******(patlist) */
if ((flags & FNM_EXTMATCH) && c == L('*') && *p == L('(')) /*)*/
{
CHAR *newn;
/* We need to check whether or not the extended glob
pattern matches the remainder of the string.
If it does, we match the entire pattern. */
for (newn = n; newn < se; ++newn)
{
if (EXTMATCH (c, newn, se, p, pe, flags) == 0)
return (0);
}
/* We didn't match the extended glob pattern, but
that's OK, since we can match 0 or more occurrences.
We need to skip the glob pattern and see if we
match the rest of the string. */
newn = PATSCAN (p + 1, pe, 0);
/* If NEWN is 0, we have an ill-formed pattern. */
p = newn ? newn : pe;
}
#endif
if (p == pe)
break;
}
/* If we've hit the end of the pattern and the last character of
the pattern was handled by the loop above, we've succeeded.
Otherwise, we need to match that last character. */
if (p == pe && (c == L('?') || c == L('*')))
return (0);
/* General case, use recursion. */
{
U_CHAR c1;
c1 = ((flags & FNM_NOESCAPE) == 0 && c == L('\\')) ? *p : c;
c1 = FOLD (c1);
for (--p; n < se; ++n)
{
/* Only call strmatch if the first character indicates a
possible match. We can check the first character if
we're not doing an extended glob match. */
if ((flags & FNM_EXTMATCH) == 0 && c != L('[') && FOLD (*n) != c1) /*]*/
continue;
/* If we're doing an extended glob match and the pattern is not
one of the extended glob patterns, we can check the first
character. */
if ((flags & FNM_EXTMATCH) && p[1] != L('(') && /*)*/
STRCHR (L("?*+@!"), *p) == 0 && c != L('[') && FOLD (*n) != c1) /*]*/
continue;
/* Otherwise, we just recurse. */
if (GMATCH (n, se, p, pe, flags & ~FNM_PERIOD) == 0)
return (0);
}
return FNM_NOMATCH;
}
case L('['):
{
if (sc == L('\0') || n == se)
return FNM_NOMATCH;
/* A character class cannot match a `.' if it is the first
character of the string or if it is the first character
following a slash and we are matching a pathname. */
if ((flags & FNM_PERIOD) && sc == L('.') &&
(n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/'))))
return (FNM_NOMATCH);
p = BRACKMATCH (p, sc, flags);
if (p == 0)
return FNM_NOMATCH;
}
break;
default:
if ((U_CHAR)c != FOLD (sc))
return (FNM_NOMATCH);
}
++n;
}
if (n == se)
return (0);
if ((flags & FNM_LEADING_DIR) && *n == L('/'))
/* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
return 0;
return (FNM_NOMATCH);
}
/* Parse a bracket expression collating symbol ([.sym.]) starting at P, find
the value of the symbol, and move P past the collating symbol expression.
The value is returned in *VP, if VP is not null. */
static CHAR *
PARSE_COLLSYM (p, vp)
CHAR *p;
INT *vp;
{
register int pc;
INT val;
p++; /* move past the `.' */
for (pc = 0; p[pc]; pc++)
if (p[pc] == L('.') && p[pc+1] == L(']'))
break;
val = COLLSYM (p, pc);
if (vp)
*vp = val;
return (p + pc + 2);
}
/* Use prototype definition here because of type promotion. */
static CHAR *
#if defined (PROTOTYPES)
BRACKMATCH (CHAR *p, U_CHAR test, int flags)
#else
BRACKMATCH (p, test, flags)
CHAR *p;
U_CHAR test;
int flags;
#endif
{
register CHAR cstart, cend, c;
register int not; /* Nonzero if the sense of the character class is inverted. */
int brcnt;
INT pc;
CHAR *savep;
test = FOLD (test);
savep = p;
/* POSIX.2 3.13.1 says that an exclamation mark (`!') shall replace the
circumflex (`^') in its role in a `nonmatching list'. A bracket
expression starting with an unquoted circumflex character produces
unspecified results. This implementation treats the two identically. */
if (not = (*p == L('!') || *p == L('^')))
++p;
c = *p++;
for (;;)
{
/* Initialize cstart and cend in case `-' is the last
character of the pattern. */
cstart = cend = c;
/* POSIX.2 equivalence class: [=c=]. See POSIX.2 2.8.3.2. Find
the end of the equivalence class, move the pattern pointer past
it, and check for equivalence. XXX - this handles only
single-character equivalence classes, which is wrong, or at
least incomplete. */
if (c == L('[') && *p == L('=') && p[2] == L('=') && p[3] == L(']'))
{
pc = FOLD (p[1]);
p += 4;
if (COLLEQUIV (test, pc))
{
/*[*/ /* Move past the closing `]', since the first thing we do at
the `matched:' label is back p up one. */
p++;
goto matched;
}
else
{
c = *p++;
if (c == L('\0'))
return ((test == L('[')) ? savep : (CHAR *)0); /*]*/
c = FOLD (c);
continue;
}
}
/* POSIX.2 character class expression. See POSIX.2 2.8.3.2. */
if (c == L('[') && *p == L(':'))
{
CHAR *close, *ccname;
pc = 0; /* make sure invalid char classes don't match. */
/* Find end of character class name */
for (close = p + 1; *close != '\0'; close++)
if (*close == L(':') && *(close+1) == L(']'))
break;
if (*close != L('\0'))
{
ccname = (CHAR *)malloc ((close - p) * sizeof (CHAR));
if (ccname == 0)
pc = 0;
else
{
bcopy (p + 1, ccname, (close - p - 1) * sizeof (CHAR));
*(ccname + (close - p - 1)) = L('\0');
pc = IS_CCLASS (test, ccname);
}
if (pc == -1)
pc = 0;
else
p = close + 2;
free (ccname);
}
if (pc)
{
/*[*/ /* Move past the closing `]', since the first thing we do at
the `matched:' label is back p up one. */
p++;
goto matched;
}
else
{
/* continue the loop here, since this expression can't be
the first part of a range expression. */
c = *p++;
if (c == L('\0'))
return ((test == L('[')) ? savep : (CHAR *)0);
else if (c == L(']'))
break;
c = FOLD (c);
continue;
}
}
/* POSIX.2 collating symbols. See POSIX.2 2.8.3.2. Find the end of
the symbol name, make sure it is terminated by `.]', translate
the name to a character using the external table, and do the
comparison. */
if (c == L('[') && *p == L('.'))
{
p = PARSE_COLLSYM (p, &pc);
/* An invalid collating symbol cannot be the first point of a
range. If it is, we set cstart to one greater than `test',
so any comparisons later will fail. */
cstart = (pc == INVALID) ? test + 1 : pc;
}
if (!(flags & FNM_NOESCAPE) && c == L('\\'))
{
if (*p == '\0')
return (CHAR *)0;
cstart = cend = *p++;
}
cstart = cend = FOLD (cstart);
/* POSIX.2 2.8.3.1.2 says: `An expression containing a `[' that
is not preceded by a backslash and is not part of a bracket
expression produces undefined results.' This implementation
treats the `[' as just a character to be matched if there is
not a closing `]'. */
if (c == L('\0'))
return ((test == L('[')) ? savep : (CHAR *)0);
c = *p++;
c = FOLD (c);
if ((flags & FNM_PATHNAME) && c == L('/'))
/* [/] can never match when matching a pathname. */
return (CHAR *)0;
/* This introduces a range, unless the `-' is the last
character of the class. Find the end of the range
and move past it. */
if (c == L('-') && *p != L(']'))
{
cend = *p++;
if (!(flags & FNM_NOESCAPE) && cend == L('\\'))
cend = *p++;
if (cend == L('\0'))
return (CHAR *)0;
if (cend == L('[') && *p == L('.'))
{
p = PARSE_COLLSYM (p, &pc);
/* An invalid collating symbol cannot be the second part of a
range expression. If we get one, we set cend to one fewer
than the test character to make sure the range test fails. */
cend = (pc == INVALID) ? test - 1 : pc;
}
cend = FOLD (cend);
c = *p++;
/* POSIX.2 2.8.3.2: ``The ending range point shall collate
equal to or higher than the starting range point; otherwise
the expression shall be treated as invalid.'' Note that this
applies to only the range expression; the rest of the bracket
expression is still checked for matches. */
if (RANGECMP (cstart, cend) > 0)
{
if (c == L(']'))
break;
c = FOLD (c);
continue;
}
}
if (RANGECMP (test, cstart) >= 0 && RANGECMP (test, cend) <= 0)
goto matched;
if (c == L(']'))
break;
}
/* No match. */
return (!not ? (CHAR *)0 : p);
matched:
/* Skip the rest of the [...] that already matched. */
c = *--p;
brcnt = 1;
while (brcnt > 0)
{
/* A `[' without a matching `]' is just another character to match. */
if (c == L('\0'))
return ((test == L('[')) ? savep : (CHAR *)0);
c = *p++;
if (c == L('[') && (*p == L('=') || *p == L(':') || *p == L('.')))
brcnt++;
else if (c == L(']'))
brcnt--;
else if (!(flags & FNM_NOESCAPE) && c == L('\\'))
{
if (*p == '\0')
return (CHAR *)0;
/* XXX 1003.2d11 is unclear if this is right. */
++p;
}
}
return (not ? (CHAR *)0 : p);
}
#if defined (EXTENDED_GLOB)
/* ksh-like extended pattern matching:
[?*+@!](pat-list)
where pat-list is a list of one or patterns separated by `|'. Operation
is as follows:
?(patlist) match zero or one of the given patterns
*(patlist) match zero or more of the given patterns
+(patlist) match one or more of the given patterns
@(patlist) match exactly one of the given patterns
!(patlist) match anything except one of the given patterns
*/
/* Scan a pattern starting at STRING and ending at END, keeping track of
embedded () and []. If DELIM is 0, we scan until a matching `)'
because we're scanning a `patlist'. Otherwise, we scan until we see
DELIM. In all cases, we never scan past END. The return value is the
first character after the matching DELIM. */
static CHAR *
PATSCAN (string, end, delim)
CHAR *string, *end;
INT delim;
{
int pnest, bnest;
INT cchar;
CHAR *s, c, *bfirst;
pnest = bnest = 0;
cchar = 0;
bfirst = NULL;
for (s = string; c = *s; s++)
{
if (s >= end)
return (s);
switch (c)
{
case L('\0'):
return ((CHAR *)NULL);
/* `[' is not special inside a bracket expression, but it may
introduce one of the special POSIX bracket expressions
([.SYM.], [=c=], [: ... :]) that needs special handling. */
case L('['):
if (bnest == 0)
{
bfirst = s + 1;
if (*bfirst == L('!') || *bfirst == L('^'))
bfirst++;
bnest++;
}
else if (s[1] == L(':') || s[1] == L('.') || s[1] == L('='))
cchar = s[1];
break;
/* `]' is not special if it's the first char (after a leading `!'
or `^') in a bracket expression or if it's part of one of the
special POSIX bracket expressions ([.SYM.], [=c=], [: ... :]) */
case L(']'):
if (bnest)
{
if (cchar && s[-1] == cchar)
cchar = 0;
else if (s != bfirst)
{
bnest--;
bfirst = 0;
}
}
break;
case L('('):
if (bnest == 0)
pnest++;
break;
case L(')'):
if (bnest == 0 && pnest-- <= 0)
return ++s;
break;
case L('|'):
if (bnest == 0 && pnest == 0 && delim == L('|'))
return ++s;
break;
}
}
return (NULL);
}
/* Return 0 if dequoted pattern matches S in the current locale. */
static int
STRCOMPARE (p, pe, s, se)
CHAR *p, *pe, *s, *se;
{
int ret;
CHAR c1, c2;
c1 = *pe;
c2 = *se;
*pe = *se = '\0';
#if HAVE_MULTIBYTE || defined (HAVE_STRCOLL)
ret = STRCOLL ((XCHAR *)p, (XCHAR *)s);
#else
ret = STRCMP ((XCHAR *)p, (XCHAR *)s);
#endif
*pe = c1;
*se = c2;
return (ret == 0 ? ret : FNM_NOMATCH);
}
/* Match a ksh extended pattern specifier. Return FNM_NOMATCH on failure or
0 on success. This is handed the entire rest of the pattern and string
the first time an extended pattern specifier is encountered, so it calls
gmatch recursively. */
static int
EXTMATCH (xc, s, se, p, pe, flags)
INT xc; /* select which operation */
CHAR *s, *se;
CHAR *p, *pe;
int flags;
{
CHAR *prest; /* pointer to rest of pattern */
CHAR *psub; /* pointer to sub-pattern */
CHAR *pnext; /* pointer to next sub-pattern */
CHAR *srest; /* pointer to rest of string */
int m1, m2;
#if DEBUG_MATCHING
fprintf(stderr, "extmatch: xc = %c\n", xc);
fprintf(stderr, "extmatch: s = %s; se = %s\n", s, se);
fprintf(stderr, "extmatch: p = %s; pe = %s\n", p, pe);
#endif
prest = PATSCAN (p + (*p == L('(')), pe, 0); /* ) */
if (prest == 0)
/* If PREST is 0, we failed to scan a valid pattern. In this
case, we just want to compare the two as strings. */
return (STRCOMPARE (p - 1, pe, s, se));
switch (xc)
{
case L('+'): /* match one or more occurrences */
case L('*'): /* match zero or more occurrences */
/* If we can get away with no matches, don't even bother. Just
call GMATCH on the rest of the pattern and return success if
it succeeds. */
if (xc == L('*') && (GMATCH (s, se, prest, pe, flags) == 0))
return 0;
/* OK, we have to do this the hard way. First, we make sure one of
the subpatterns matches, then we try to match the rest of the
string. */
for (psub = p + 1; ; psub = pnext)
{
pnext = PATSCAN (psub, pe, L('|'));
for (srest = s; srest <= se; srest++)
{
/* Match this substring (S -> SREST) against this
subpattern (psub -> pnext - 1) */
m1 = GMATCH (s, srest, psub, pnext - 1, flags) == 0;
/* OK, we matched a subpattern, so make sure the rest of the
string matches the rest of the pattern. Also handle
multiple matches of the pattern. */
if (m1)
m2 = (GMATCH (srest, se, prest, pe, flags) == 0) ||
(s != srest && GMATCH (srest, se, p - 1, pe, flags) == 0);
if (m1 && m2)
return (0);
}
if (pnext == prest)
break;
}
return (FNM_NOMATCH);
case L('?'): /* match zero or one of the patterns */
case L('@'): /* match exactly one of the patterns */
/* If we can get away with no matches, don't even bother. Just
call gmatch on the rest of the pattern and return success if
it succeeds. */
if (xc == L('?') && (GMATCH (s, se, prest, pe, flags) == 0))
return 0;
/* OK, we have to do this the hard way. First, we see if one of
the subpatterns matches, then, if it does, we try to match the
rest of the string. */
for (psub = p + 1; ; psub = pnext)
{
pnext = PATSCAN (psub, pe, L('|'));
srest = (prest == pe) ? se : s;
for ( ; srest <= se; srest++)
{
if (GMATCH (s, srest, psub, pnext - 1, flags) == 0 &&
GMATCH (srest, se, prest, pe, flags) == 0)
return (0);
}
if (pnext == prest)
break;
}
return (FNM_NOMATCH);
case '!': /* match anything *except* one of the patterns */
for (srest = s; srest <= se; srest++)
{
m1 = 0;
for (psub = p + 1; ; psub = pnext)
{
pnext = PATSCAN (psub, pe, L('|'));
/* If one of the patterns matches, just bail immediately. */
if (m1 = (GMATCH (s, srest, psub, pnext - 1, flags) == 0))
break;
if (pnext == prest)
break;
}
if (m1 == 0 && GMATCH (srest, se, prest, pe, flags) == 0)
return (0);
}
return (FNM_NOMATCH);
}
return (FNM_NOMATCH);
}
#endif /* EXTENDED_GLOB */
#undef IS_CCLASS
#undef FOLD
#undef CHAR
#undef U_CHAR
#undef XCHAR
#undef INT
#undef INVALID
#undef FCT
#undef GMATCH
#undef COLLSYM
#undef PARSE_COLLSYM
#undef PATSCAN
#undef STRCOMPARE
#undef EXTMATCH
#undef BRACKMATCH
#undef STRCHR
#undef STRCOLL
#undef STRLEN
#undef STRCMP
#undef COLLEQUIV
#undef RANGECMP
#undef L
+4 -23
View File
@@ -362,44 +362,25 @@ xstrmatch (pattern, string, flags)
{
#if HANDLE_MULTIBYTE
int ret;
mbstate_t ps;
size_t n;
char *pattern_bak;
wchar_t *wpattern, *wstring;
if (MB_CUR_MAX == 1)
return (internal_strmatch (pattern, string, flags));
pattern_bak = (char *)xmalloc (strlen (pattern) + 1);
strcpy (pattern_bak, pattern);
memset (&ps, '\0', sizeof (mbstate_t));
n = xmbsrtowcs (NULL, (const char **)&pattern, 0, &ps);
n = xdupmbstowcs (&wpattern, NULL, pattern);
if (n == (size_t)-1 || n == (size_t)-2)
{
free (pattern_bak);
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
}
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
wpattern = (wchar_t *)xmalloc ((n + 1) * sizeof (wchar_t));
(void) xmbsrtowcs (wpattern, (const char **)&pattern, n + 1, &ps);
memset (&ps, '\0', sizeof (mbstate_t));
n = xmbsrtowcs (NULL, (const char **)&string, 0, &ps);
n = xdupmbstowcs (&wstring, NULL, string);
if (n == (size_t)-1 || n == (size_t)-2)
{
free (wpattern);
ret = internal_strmatch (pattern_bak, string, flags);
free (pattern_bak);
return ret;
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
}
wstring = (wchar_t *)xmalloc ((n + 1) * sizeof (wchar_t));
(void) xmbsrtowcs (wstring, (const char **)&string, n + 1, &ps);
ret = internal_wstrmatch (wpattern, wstring, flags);
free (pattern_bak);
free (wpattern);
free (wstring);
+410
View File
@@ -0,0 +1,410 @@
/* strmatch.c -- ksh-like extended pattern matching for the shell and filename
globbing. */
/* Copyright (C) 1991-2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#include <config.h>
#include <stdio.h> /* for debugging */
#include "strmatch.h"
#include <chartypes.h>
#include "bashansi.h"
#include "shmbutil.h"
#include "xmalloc.h"
/* First, compile `sm_loop.c' for single-byte characters. */
#define CHAR unsigned char
#define U_CHAR unsigned char
#define XCHAR char
#define INT int
#define L(CS) CS
#define INVALID -1
#undef STREQ
#undef STREQN
#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0)
#define STREQN(a, b, n) ((a)[0] == (b)[0] && strncmp(a, b, n) == 0)
/* We use strcoll(3) for range comparisons in bracket expressions,
even though it can have unwanted side effects in locales
other than POSIX or US. For instance, in the de locale, [A-Z] matches
all characters. */
#if defined (HAVE_STRCOLL)
/* Helper function for collating symbol equivalence. */
static int rangecmp (c1, c2)
int c1, c2;
{
static char s1[2] = { ' ', '\0' };
static char s2[2] = { ' ', '\0' };
int ret;
/* Eight bits only. Period. */
c1 &= 0xFF;
c2 &= 0xFF;
if (c1 == c2)
return (0);
s1[0] = c1;
s2[0] = c2;
if ((ret = strcoll (s1, s2)) != 0)
return ret;
return (c1 - c2);
}
#else /* !HAVE_STRCOLL */
# define rangecmp(c1, c2) ((int)(c1) - (int)(c2))
#endif /* !HAVE_STRCOLL */
#if defined (HAVE_STRCOLL)
static int
collequiv (c1, c2)
int c1, c2;
{
return (rangecmp (c1, c2) == 0);
}
#else
# define collequiv(c1, c2) ((c1) == (c2))
#endif
#define _COLLSYM _collsym
#define __COLLSYM __collsym
#define POSIXCOLL posix_collsyms
#include "collsyms.h"
static int
collsym (s, len)
char *s;
int len;
{
register struct _collsym *csp;
for (csp = posix_collsyms; csp->name; csp++)
{
if (STREQN(csp->name, s, len) && csp->name[len] == '\0')
return (csp->code);
}
if (len == 1)
return s[0];
return INVALID;
}
/* unibyte character classification */
#if !defined (isascii) && !defined (HAVE_ISASCII)
# define isascii(c) ((unsigned int)(c) <= 0177)
#endif
enum char_class
{
CC_NO_CLASS = 0,
CC_ASCII, CC_ALNUM, CC_ALPHA, CC_BLANK, CC_CNTRL, CC_DIGIT, CC_GRAPH,
CC_LOWER, CC_PRINT, CC_PUNCT, CC_SPACE, CC_UPPER, CC_WORD, CC_XDIGIT
};
static char const *const cclass_name[] =
{
"",
"ascii", "alnum", "alpha", "blank", "cntrl", "digit", "graph",
"lower", "print", "punct", "space", "upper", "word", "xdigit"
};
#define N_CHAR_CLASS (sizeof(cclass_name) / sizeof (cclass_name[0]))
static int
is_cclass (c, name)
int c;
const char *name;
{
enum char_class char_class = CC_NO_CLASS;
int i, result;
for (i = 1; i < N_CHAR_CLASS; i++)
{
if (STREQ (name, cclass_name[i]))
{
char_class = (enum char_class)i;
break;
}
}
if (char_class == 0)
return -1;
switch (char_class)
{
case CC_ASCII:
result = isascii (c);
break;
case CC_ALNUM:
result = ISALNUM (c);
break;
case CC_ALPHA:
result = ISALPHA (c);
break;
case CC_BLANK:
result = ISBLANK (c);
break;
case CC_CNTRL:
result = ISCNTRL (c);
break;
case CC_DIGIT:
result = ISDIGIT (c);
break;
case CC_GRAPH:
result = ISGRAPH (c);
break;
case CC_LOWER:
result = ISLOWER (c);
break;
case CC_PRINT:
result = ISPRINT (c);
break;
case CC_PUNCT:
result = ISPUNCT (c);
break;
case CC_SPACE:
result = ISSPACE (c);
break;
case CC_UPPER:
result = ISUPPER (c);
break;
case CC_WORD:
result = (ISALNUM (c) || c == '_');
break;
case CC_XDIGIT:
result = ISXDIGIT (c);
break;
default:
result = -1;
break;
}
return result;
}
/* Now include `sm_loop.c' for single-byte characters. */
/* The result of FOLD is an `unsigned char' */
# define FOLD(c) ((flags & FNM_CASEFOLD) \
? TOLOWER ((unsigned char)c) \
: ((unsigned char)c))
#define FCT internal_strmatch
#define GMATCH gmatch
#define COLLSYM collsym
#define PARSE_COLLSYM parse_collsym
#define BRACKMATCH brackmatch
#define PATSCAN patscan
#define STRCOMPARE strcompare
#define EXTMATCH extmatch
#define STRCHR(S, C) strchr((S), (C))
#define STRCOLL(S1, S2) strcoll((S1), (S2))
#define STRLEN(S) strlen(S)
#define STRCMP(S1, S2) strcmp((S1), (S2))
#define RANGECMP(C1, C2) rangecmp((C1), (C2))
#define COLLEQUIV(C1, C2) collequiv((C1), (C2))
#define CTYPE_T enum char_class
#define IS_CCLASS(C, S) is_cclass((C), (S))
#include "sm_loop.c"
#if HANDLE_MULTIBYTE
# define CHAR wchar_t
# define U_CHAR wint_t
# define XCHAR wchar_t
# define INT wint_t
# define L(CS) L##CS
# define INVALID WEOF
# undef STREQ
# undef STREQN
# define STREQ(s1, s2) ((wcscmp (s1, s2) == 0))
# define STREQN(a, b, n) ((a)[0] == (b)[0] && wcsncmp(a, b, n) == 0)
static int
rangecmp_wc (c1, c2)
wint_t c1, c2;
{
static wchar_t s1[2] = { L' ', L'\0' };
static wchar_t s2[2] = { L' ', L'\0' };
int ret;
if (c1 == c2)
return 0;
s1[0] = c1;
s2[0] = c2;
return (wcscoll (s1, s2));
}
static int
collequiv_wc (c, equiv)
wint_t c, equiv;
{
return (!(c - equiv));
}
/* Helper function for collating symbol. */
# define _COLLSYM _collwcsym
# define __COLLSYM __collwcsym
# define POSIXCOLL posix_collwcsyms
# include "collsyms.h"
static wint_t
collwcsym (s, len)
wchar_t *s;
int len;
{
register struct _collwcsym *csp;
for (csp = posix_collwcsyms; csp->name; csp++)
{
if (STREQN(csp->name, s, len) && csp->name[len] == L'\0')
return (csp->code);
}
if (len == 1)
return s[0];
return INVALID;
}
static int
is_wcclass (wc, name)
wint_t wc;
wchar_t *name;
{
char *mbs;
mbstate_t state;
size_t mbslength;
wctype_t desc;
int want_word;
if ((wctype ("ascii") == (wctype_t)0) && (wcscmp (name, L"ascii") == 0))
{
int c;
if ((c = wctob (wc)) == EOF)
return 0;
else
return (c <= 0x7F);
}
want_word = (wcscmp (name, L"word") == 0);
if (want_word)
name = L"alnum";
memset (&state, '\0', sizeof (mbstate_t));
mbs = (char *) malloc (wcslen(name) * MB_CUR_MAX + 1);
mbslength = wcsrtombs(mbs, (const wchar_t **)&name, (wcslen(name) * MB_CUR_MAX + 1), &state);
if (mbslength == (size_t)-1 || mbslength == (size_t)-2)
{
free (mbs);
return -1;
}
desc = wctype (mbs);
free (mbs);
if (desc == (wctype_t)0)
return -1;
if (want_word)
return (iswctype (wc, desc) || wc == L'_');
else
return (iswctype (wc, desc));
}
/* Now include `sm_loop.c' for multibyte characters. */
#define FOLD(c) ((flags & FNM_CASEFOLD) && iswupper (c) ? towlower (c) : (c))
#define FCT internal_wstrmatch
#define GMATCH gmatch_wc
#define COLLSYM collwcsym
#define PARSE_COLLSYM parse_collwcsym
#define BRACKMATCH brackmatch_wc
#define PATSCAN patscan_wc
#define STRCOMPARE wscompare
#define EXTMATCH extmatch_wc
#define STRCHR(S, C) wcschr((S), (C))
#define STRCOLL(S1, S2) wcscoll((S1), (S2))
#define STRLEN(S) wcslen(S)
#define STRCMP(S1, S2) wcscmp((S1), (S2))
#define RANGECMP(C1, C2) rangecmp_wc((C1), (C2))
#define COLLEQUIV(C1, C2) collequiv_wc((C1), (C2))
#define CTYPE_T enum char_class
#define IS_CCLASS(C, S) is_wcclass((C), (S))
#include "sm_loop.c"
#endif /* HAVE_MULTIBYTE */
int
xstrmatch (pattern, string, flags)
char *pattern;
char *string;
int flags;
{
#if HANDLE_MULTIBYTE
int ret;
mbstate_t ps;
size_t n;
char *pattern_bak;
wchar_t *wpattern, *wstring;
if (MB_CUR_MAX == 1)
return (internal_strmatch (pattern, string, flags));
pattern_bak = (char *)xmalloc (strlen (pattern) + 1);
strcpy (pattern_bak, pattern);
memset (&ps, '\0', sizeof (mbstate_t));
n = xmbsrtowcs (NULL, (const char **)&pattern, 0, &ps);
if (n == (size_t)-1 || n == (size_t)-2)
{
free (pattern_bak);
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
}
wpattern = (wchar_t *)xmalloc ((n + 1) * sizeof (wchar_t));
(void) xmbsrtowcs (wpattern, (const char **)&pattern, n + 1, &ps);
memset (&ps, '\0', sizeof (mbstate_t));
n = xmbsrtowcs (NULL, (const char **)&string, 0, &ps);
if (n == (size_t)-1 || n == (size_t)-2)
{
free (wpattern);
ret = internal_strmatch (pattern_bak, string, flags);
free (pattern_bak);
return ret;
}
wstring = (wchar_t *)xmalloc ((n + 1) * sizeof (wchar_t));
(void) xmbsrtowcs (wstring, (const char **)&string, n + 1, &ps);
ret = internal_wstrmatch (wpattern, wstring, flags);
free (pattern_bak);
free (wpattern);
free (wstring);
return ret;
#else
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
#endif /* !HANDLE_MULTIBYTE */
}
+16 -6
View File
@@ -24,13 +24,9 @@
#include "stdc.h"
#include "strmatch.h"
/* Structured this way so that if HAVE_LIBC_FNM_EXTMATCH is defined, the
matching portion of the library (smatch.c) is not linked into the shell. */
#ifndef HAVE_LIBC_FNM_EXTMATCH
extern int xstrmatch __P((char *, char *, int));
#else
# define xstrmatch fnmatch
#if defined (HAVE_MULTIBYTE)
extern int internal_wstrmatch __P((wchar_t *, wchar_t *, int));
#endif
int
@@ -45,6 +41,20 @@ strmatch (pattern, string, flags)
return (xstrmatch (pattern, string, flags));
}
#if defined (HANDLE_MULTIBYTE)
int
wcsmatch (wpattern, wstring, flags)
wchar_t *wpattern;
wchar_t *wstring;
int flags;
{
if (wstring == 0 || wpattern == 0)
return (FNM_NOMATCH);
return (internal_wstrmatch (wpattern, wstring, flags));
}
#endif
#ifdef TEST
main (c, v)
int c;
+79
View File
@@ -0,0 +1,79 @@
/* strmatch.c -- ksh-like extended pattern matching for the shell and filename
globbing. */
/* Copyright (C) 1991-2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#include <config.h>
#include "stdc.h"
#include "strmatch.h"
extern int xstrmatch __P((char *, char *, int));
#if defined (HAVE_MULTIBYTE)
extern int internal_wstrmatch __P((wchar_t *, wchar_t *, int));
#endif
int
strmatch (pattern, string, flags)
char *pattern;
char *string;
int flags;
{
if (string == 0 || pattern == 0)
return FNM_NOMATCH;
return (xstrmatch (pattern, string, flags));
}
#if defined (HAVE_MULTIBYTE)
int
wcsmatch (wpattern, wstring, flags)
wchar_t *wpattern;
wchar_t *wstring;
int flags;
{
if (wstring == 0 || wpattern == 0)
return (FNM_NOMATCH);
return (internal_wstrmatch (wpattern, wstring, flags));
}
#endif
#ifdef TEST
main (c, v)
int c;
char **v;
{
char *string, *pat;
string = v[1];
pat = v[2];
if (strmatch (pat, string, 0) == 0)
{
printf ("%s matches %s\n", string, pat);
exit (0);
}
else
{
printf ("%s does not match %s\n", string, pat);
exit (1);
}
}
#endif
+5 -7
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 1991 Free Software Foundation, Inc.
/* Copyright (C) 1991-2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -19,11 +19,7 @@ not, write to the Free Software Foundation, Inc.,
#ifndef _STRMATCH_H
#define _STRMATCH_H 1
#ifdef HAVE_LIBC_FNM_EXTMATCH
#include <fnmatch.h>
#else /* !HAVE_LIBC_FNM_EXTMATCH */
#include <config.h>
#include "stdc.h"
@@ -59,6 +55,8 @@ not, write to the Free Software Foundation, Inc.,
returning zero if it matches, FNM_NOMATCH if not. */
extern int strmatch __P((char *, char *, int));
#endif /* !HAVE_LIBC_FNM_EXTMATCH */
#if HANDLE_MULTIBYTE
extern int wcsmatch __P((wchar_t *, wchar_t *, int));
#endif
#endif /* _STRMATCH_H */
+64
View File
@@ -0,0 +1,64 @@
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#ifndef _STRMATCH_H
#define _STRMATCH_H 1
#ifdef HAVE_LIBC_FNM_EXTMATCH
#include <fnmatch.h>
#else /* !HAVE_LIBC_FNM_EXTMATCH */
#include "stdc.h"
/* We #undef these before defining them because some losing systems
(HP-UX A.08.07 for example) define these in <unistd.h>. */
#undef FNM_PATHNAME
#undef FNM_NOESCAPE
#undef FNM_PERIOD
/* Bits set in the FLAGS argument to `strmatch'. */
/* standard flags are like fnmatch(3). */
#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */
/* extended flags not available in most libc fnmatch versions, but we undef
them to avoid any possible warnings. */
#undef FNM_LEADING_DIR
#undef FNM_CASEFOLD
#undef FNM_EXTMATCH
#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
#define FNM_EXTMATCH (1 << 5) /* Use ksh-like extended matching. */
/* Value returned by `strmatch' if STRING does not match PATTERN. */
#undef FNM_NOMATCH
#define FNM_NOMATCH 1
/* Match STRING against the filename pattern PATTERN,
returning zero if it matches, FNM_NOMATCH if not. */
extern int strmatch __P((char *, char *, int));
#endif /* !HAVE_LIBC_FNM_EXTMATCH */
#endif /* _STRMATCH_H */
+136 -7
View File
@@ -54,27 +54,25 @@ xmbsrtowcs (dest, src, len, pstate)
ps = &local_state;
}
n = strlen(*src) + 1;
n = strlen(*src);
if (dest == NULL)
{
wchar_t *wsbuf;
char *mbsbuf, *mbsbuf_top;
const char *mbs;
mbstate_t psbuf;
wsbuf = (wchar_t *) malloc ((n + 1) * sizeof(wchar_t));
mbsbuf_top = mbsbuf = (char *) malloc (n + 1);
memcpy(mbsbuf, *src, n + 1);
mbs = *src;
psbuf = *ps;
wclength = mbsrtowcs (wsbuf, (const char **)&mbsbuf, n, &psbuf);
wclength = mbsrtowcs (wsbuf, &mbs, n, &psbuf);
free (wsbuf);
free (mbsbuf_top);
return wclength;
}
for(wclength = 0; wclength < len; wclength++, dest++)
for (wclength = 0; wclength < len; wclength++, dest++)
{
if(mbsinit(ps))
{
@@ -113,4 +111,135 @@ xmbsrtowcs (dest, src, len, pstate)
return (wclength);
}
/* Convert a multibyte string to a wide character string. Memory for the
new wide character string is obtained with malloc.
The return value is the length of the wide character string. Returns a
pointer to the wide character string in DESTP. If INDICESP is not NULL,
INDICESP stores the pointer to the pointer array. Each pointer is to
the first byte of each multibyte character. Memory for the pointer array
is obtained with malloc, too.
If conversion is failed, the return value is (size_t)-1 and the values
of DESTP and INDICESP are NULL. */
#define WSBUF_INC 32
size_t
xdupmbstowcs (destp, indicesp, src)
wchar_t **destp; /* Store the pointer to the wide character string */
char ***indicesp; /* Store the pointer to the pointer array. */
const char *src; /* Multibyte character string */
{
const char *p; /* Conversion start position of src */
wchar_t wc; /* Created wide character by conversion */
wchar_t *wsbuf; /* Buffer for wide characters. */
char **indices; /* Buffer for indices. */
size_t wsbuf_size; /* Size of WSBUF */
size_t wcnum; /* Number of wide characters in WSBUF */
mbstate_t state; /* Conversion State */
/* In case SRC or DESP is NULL, conversion doesn't take place. */
if (src == NULL || destp == NULL)
{
*destp = NULL;
return (size_t)-1;
}
memset (&state, '\0', sizeof(mbstate_t));
wsbuf_size = WSBUF_INC;
wsbuf = (wchar_t *) malloc (wsbuf_size * sizeof(wchar_t));
if (wsbuf == NULL)
{
*destp = NULL;
return (size_t)-1;
}
indices = (char **) malloc (wsbuf_size * sizeof(char *));
if (indices == NULL)
{
free (wsbuf);
*destp = NULL;
return (size_t)-1;
}
p = src;
wcnum = 0;
do {
size_t mblength; /* Byte length of one multibyte character. */
if(mbsinit (&state))
{
if (*p == '\0')
{
wc = L'\0';
mblength = 1;
}
else if (*p == '\\')
{
wc = L'\\';
mblength = 1;
}
else
mblength = mbrtowc(&wc, p, MB_LEN_MAX, &state);
}
else
mblength = mbrtowc(&wc, p, MB_LEN_MAX, &state);
/* Conversion failed. */
if (MB_INVALIDCH (mblength))
{
free (wsbuf);
free (indices);
*destp = NULL;
return (size_t)-1;
}
++wcnum;
/* Resize buffers when they are not large enough. */
if (wsbuf_size < wcnum)
{
wchar_t *wstmp;
char **idxtmp;
wsbuf_size += WSBUF_INC;
wstmp = (wchar_t *) realloc (wsbuf, wsbuf_size * sizeof (wchar_t));
if (wstmp == NULL)
{
free (wsbuf);
free (indices);
*destp = NULL;
return (size_t)-1;
}
wsbuf = wstmp;
idxtmp = (char **) realloc (indices, wsbuf_size * sizeof (char **));
if (idxtmp == NULL)
{
free (wsbuf);
free (indices);
*destp = NULL;
return (size_t)-1;
}
indices = idxtmp;
}
wsbuf[wcnum - 1] = wc;
indices[wcnum - 1] = (char *)p;
p += mblength;
} while (MB_NULLWCH (wc) == 0);
/* Return the length of the wide character string, not including `\0'. */
*destp = wsbuf;
if (indicesp != NULL)
*indicesp = indices;
else
free (indices);
return (wcnum - 1);
}
#endif /* HANDLE_MULTIBYTE */
+247
View File
@@ -0,0 +1,247 @@
/* xmbsrtowcs.c -- replacement function for mbsrtowcs */
/* Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#include <config.h>
#include <bashansi.h>
/* <wchar.h>, <wctype.h> and <stdlib.h> are included in "shmbutil.h".
If <wchar.h>, <wctype.h>, mbsrtowcs(), exist, HANDLE_MULTIBYTE
is defined as 1. */
#include <shmbutil.h>
#if HANDLE_MULTIBYTE
/* On some locales (ex. ja_JP.sjis), mbsrtowc doesn't convert 0x5c to U<0x5c>.
So, this function is made for converting 0x5c to U<0x5c>. */
static mbstate_t local_state;
static int local_state_use = 0;
size_t
xmbsrtowcs (dest, src, len, pstate)
wchar_t *dest;
const char **src;
size_t len;
mbstate_t *pstate;
{
mbstate_t *ps;
size_t mblength, wclength, n;
ps = pstate;
if (pstate == NULL)
{
if (!local_state_use)
{
memset (&local_state, '\0', sizeof(mbstate_t));
local_state_use = 1;
}
ps = &local_state;
}
n = strlen(*src);
if (dest == NULL)
{
wchar_t *wsbuf;
char *mbsbuf, *mbsbuf_top;
mbstate_t psbuf;
wsbuf = (wchar_t *) malloc ((n + 1) * sizeof(wchar_t));
mbsbuf_top = mbsbuf = (char *) malloc (n + 1);
memcpy(mbsbuf, *src, n + 1);
psbuf = *ps;
wclength = mbsrtowcs (wsbuf, (const char **)&mbsbuf, n, &psbuf);
free (wsbuf);
free (mbsbuf_top);
return wclength;
}
for (wclength = 0; wclength < len; wclength++, dest++)
{
if(mbsinit(ps))
{
if (**src == '\0')
{
*dest = L'\0';
*src = NULL;
return (wclength);
}
else if (**src == '\\')
{
*dest = L'\\';
mblength = 1;
}
else
mblength = mbrtowc(dest, *src, n, ps);
}
else
mblength = mbrtowc(dest, *src, n, ps);
/* Cannot convert multibyte character to wide character. */
if (mblength == (size_t)-1 || mblength == (size_t)-2)
return (size_t)-1;
*src += mblength;
n -= mblength;
/* The multibyte string has been completely converted,
including the terminating '\0'. */
if (*dest == L'\0')
{
*src = NULL;
break;
}
}
return (wclength);
}
/* Convert a multibyte string to a wide character string. Memory for the
new wide character string is obtained with malloc.
The return value is the length of the wide character string. Returns a
pointer to the wide character string in DESTP. If INDICESP is not NULL,
INDICESP stores the pointer to the pointer array. Each pointer is to
the first byte of each multibyte character. Memory for the pointer array
is obtained with malloc, too.
If conversion is failed, the return value is (size_t)-1 and the values
of DESTP and INDICESP are NULL. */
#define WSBUF_INC 32
size_t
xdupmbstowcs (destp, indicesp, src)
wchar_t **destp; /* Store the pointer to the wide character string */
char ***indicesp; /* Store the pointer to the pointer array. */
const char *src; /* Multibyte character string */
{
const char *p; /* Conversion start position of src */
wchar_t wc; /* Created wide character by conversion */
wchar_t *wsbuf; /* Buffer for wide characters. */
char **indices; /* Buffer for indices. */
size_t wsbuf_size; /* Size of WSBUF */
size_t wcnum; /* Number of wide characters in WSBUF */
mbstate_t state; /* Conversion State */
/* In case SRC or DESP is NULL, conversion doesn't take place. */
if (src == NULL || destp == NULL)
{
*destp = NULL;
return (size_t)-1;
}
memset (&state, '\0', sizeof(mbstate_t));
wsbuf_size = WSBUF_INC;
wsbuf = (wchar_t *) malloc (wsbuf_size * sizeof(wchar_t));
if (wsbuf == NULL)
{
*destp = NULL;
return (size_t)-1;
}
indices = (char **) malloc (wsbuf_size * sizeof(char *));
if (indices == NULL)
{
free (wsbuf);
*destp = NULL;
return (size_t)-1;
}
p = src;
wcnum = 0;
do {
size_t mblength; /* Byte length of one multibyte character. */
if(mbsinit (&state))
{
if (*p == '\0')
{
wc = L'\0';
mblength = 1;
}
else if (*p == '\\')
{
wc = L'\\';
mblength = 1;
}
else
mblength = mbrtowc(&wc, p, MB_LEN_MAX, &state);
}
else
mblength = mbrtowc(&wc, p, MB_LEN_MAX, &state);
/* Conversion failed. */
if (MB_INVALIDCH (mblength))
{
free (wsbuf);
free (indices);
*destp = NULL;
return (size_t)-1;
}
++wcnum;
/* Resize buffers when they are not large enough. */
if (wsbuf_size < wcnum)
{
wchar_t *wstmp;
char **idxtmp;
wsbuf_size += WSBUF_INC;
wstmp = (wchar_t *) realloc (wsbuf, wsbuf_size * sizeof (wchar_t));
if (wstmp == NULL)
{
free (wsbuf);
free (indices);
*destp = NULL;
return (size_t)-1;
}
wsbuf = wstmp;
idxtmp = (char **) realloc (indices, wsbuf_size * sizeof (char **));
if (idxtmp == NULL)
{
free (wsbuf);
free (indices);
*destp = NULL;
return (size_t)-1;
}
indices = idxtmp;
}
wsbuf[wcnum - 1] = wc;
indices[wcnum - 1] = (char *)p;
p += mblength;
} while (MB_NULLWCH (wc) == 0);
/* Return the length of the wide character string, not including `\0'. */
*destp = wsbuf;
if (indicesp != NULL)
*indicesp = indices;
else
free (indices);
return (wcnum - 1);
}
#endif /* HANDLE_MULTIBYTE */
+12 -1
View File
@@ -1528,7 +1528,18 @@ history_tokenize_internal (string, wind, indp)
start = i;
i = history_tokenize_word (string, start);
i = history_tokenize_word (string, start);
/* If we have a non-whitespace delimiter character (which would not be
skipped by the loop above), use it and any adjacent delimiters to
make a separate field. Any adjacent white space will be skipped the
next time through the loop. */
if (i == start && history_word_delimiters)
{
i++;
while (string[i] && member (string[i], history_word_delimiters))
i++;
}
/* If we are looking for the word in which the character at a
particular index falls, remember it. */
+364 -178
View File
@@ -212,8 +212,19 @@ static char *pos_params __P((char *, int, int, int));
static unsigned char *mb_getcharlens __P((char *, int));
static char *remove_upattern __P((char *, char *, int));
#if defined (HANDLE_MULTIBYTE)
static wchar_t *wcsdup __P((wchar_t *));
static wchar_t *remove_wpattern __P((wchar_t *, size_t, wchar_t *, int));
#endif
static char *remove_pattern __P((char *, char *, int));
static int match_pattern_char __P((char *, char *));
static int match_upattern __P((char *, char *, int, char **, char **));
#if defined (HANDLE_MULTIBYTE)
static int match_pattern_wchar __P((wchar_t *, wchar_t *));
static int match_wpattern __P((wchar_t *, char **, size_t, wchar_t *, int, char **, char **));
#endif
static int match_pattern __P((char *, char *, int, char **, char **));
static int getpatspec __P((int, char *));
static char *getpattern __P((char *, int, int));
@@ -1171,9 +1182,9 @@ de_backslash (string)
prev_i = i;
ADVANCE_CHAR (string, slen, i);
if (j < prev_i)
do string[j++] = string[prev_i++]; while (prev_i < i);
do string[j++] = string[prev_i++]; while (prev_i < i);
else
j = i;
j = i;
}
string[j] = '\0';
@@ -2799,17 +2810,17 @@ remove_quoted_nulls (string)
while (i < slen)
{
if (string[i] == CTLESC)
{
{
/* Old code had j++, but we cannot assume that i == j at this
point -- what if a CTLNUL has already been removed from the
string? We don't want to drop the CTLESC or recopy characters
that we've already copied down. */
i++; string[j++] = CTLESC;
if (i == slen)
break;
}
if (i == slen)
break;
}
else if (string[i] == CTLNUL)
i++;
i++;
prev_i = i;
ADVANCE_CHAR (string, slen, i);
@@ -2844,13 +2855,14 @@ word_list_remove_quoted_nulls (list)
/* **************************************************************** */
#if defined (HANDLE_MULTIBYTE)
#if 0 /* Currently unused */
static unsigned char *
mb_getcharlens (string, len)
char *string;
int len;
{
int i, offset;
unsigned char last, *ret;
int i, offset, last;
unsigned char *ret;
char *p;
DECLARE_MBSTATE;
@@ -2867,6 +2879,7 @@ mb_getcharlens (string, len)
return ret;
}
#endif
#endif
/* Remove the portion of PARAM matched by PATTERN according to OP, where OP
can have one of 4 values:
@@ -2882,130 +2895,205 @@ mb_getcharlens (string, len)
#define RP_SHORT_RIGHT 4
static char *
remove_pattern (param, pattern, op)
remove_upattern (param, pattern, op)
char *param, *pattern;
int op;
{
register int len;
register char *end;
register char *p, *ret, c;
int offset;
unsigned char *mblen;
DECLARE_MBSTATE;
len = STRLEN (param);
end = param + len;
switch (op)
{
case RP_LONG_LEFT: /* remove longest match at start */
for (p = end; p >= param; p--)
{
c = *p; *p = '\0';
if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
*p = c;
return (savestring (p));
}
*p = c;
}
break;
case RP_SHORT_LEFT: /* remove shortest match at start */
for (p = param; p <= end; p++)
{
c = *p; *p = '\0';
if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
*p = c;
return (savestring (p));
}
*p = c;
}
break;
case RP_LONG_RIGHT: /* remove longest match at end */
for (p = param; p <= end; p++)
{
if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
c = *p; *p = '\0';
ret = savestring (param);
*p = c;
return (ret);
}
}
break;
case RP_SHORT_RIGHT: /* remove shortest match at end */
for (p = end; p >= param; p--)
{
if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
c = *p; *p = '\0';
ret = savestring (param);
*p = c;
return (ret);
}
}
break;
}
return (savestring (param)); /* no match, return original string */
}
#if defined (HANDLE_MULTIBYTE)
static wchar_t *
wcsdup (ws)
wchar_t *ws;
{
wchar_t *ret;
size_t len;
len = wcslen (ws);
ret = xmalloc ((len + 1) * sizeof (wchar_t));
if (ret == 0)
return ret;
return (wcscpy (ret, ws));
}
static wchar_t *
remove_wpattern (wparam, wstrlen, wpattern, op)
wchar_t *wparam;
size_t wstrlen;
wchar_t *wpattern;
int op;
{
wchar_t wc;
int n, n1;
wchar_t *ret;
switch (op)
{
case RP_LONG_LEFT: /* remove longest match at start */
for (n = wstrlen; n >= 0; n--)
{
wc = wparam[n]; wparam[n] = L'\0';
if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
wparam[n] = wc;
return (wcsdup (wparam + n));
}
wparam[n] = wc;
}
break;
case RP_SHORT_LEFT: /* remove shortest match at start */
for (n = 0; n <= wstrlen; n++)
{
wc = wparam[n]; wparam[n] = L'\0';
if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
wparam[n] = wc;
return (wcsdup (wparam + n));
}
wparam[n] = wc;
}
break;
case RP_LONG_RIGHT: /* remove longest match at end */
for (n = 0; n <= wstrlen; n++)
{
if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
wc = wparam[n]; wparam[n] = L'\0';
ret = wcsdup (wparam);
wparam[n] = wc;
return (ret);
}
}
break;
case RP_SHORT_RIGHT: /* remove shortest match at end */
for (n = wstrlen; n >= 0; n--)
{
if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
wc = wparam[n]; wparam[n] = L'\0';
ret = wcsdup (wparam);
wparam[n] = wc;
return (ret);
}
}
break;
}
return (wcsdup (wparam)); /* no match, return original string */
}
#endif /* HANDLE_MULTIBYTE */
static char *
remove_pattern (param, pattern, op)
char *param, *pattern;
int op;
{
if (param == NULL)
return (param);
if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */
return (savestring (param));
len = STRLEN (param);
end = param + len;
mblen = (unsigned char *)0;
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && (op == RP_LONG_LEFT || op == RP_SHORT_RIGHT))
mblen = mb_getcharlens (param, len);
#endif
switch (op)
if (MB_CUR_MAX > 1)
{
case RP_LONG_LEFT: /* remove longest match at start */
p = end;
while (p >= param)
{
c = *p; *p = '\0';
if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
*p = c;
FREE (mblen);
return (savestring (p));
}
*p = c;
wchar_t *ret, *oret;
size_t n;
wchar_t *wparam, *wpattern;
mbstate_t ps;
char *xret;
if (MB_CUR_MAX > 1)
{
while (p >= param)
if (mblen[--p - param])
break;
}
else
p--;
}
break;
n = xdupmbstowcs (&wpattern, NULL, pattern);
if (n == (size_t)-1)
return (remove_upattern (param, pattern, op));
n = xdupmbstowcs (&wparam, NULL, param);
if (n == (size_t)-1)
{
free (wpattern);
return (remove_upattern (param, pattern, op));
}
oret = ret = remove_wpattern (wparam, n, wpattern, op);
case RP_SHORT_LEFT: /* remove shortest match at start */
p = param;
offset = 0;
while (p <= end)
{
c = *p; *p = '\0';
if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
*p = c;
return (savestring (p));
}
*p = c;
free (wparam);
free (wpattern);
if (MB_CUR_MAX > 1)
{
ADVANCE_CHAR (param, len, offset);
p = param + offset;
}
else
p++;
}
break;
case RP_LONG_RIGHT: /* remove longest match at end */
p = param;
offset = 0;
while (p <= end)
{
if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
c = *p; *p = '\0';
ret = savestring (param);
*p = c;
return (ret);
}
if (MB_CUR_MAX > 1)
{
ADVANCE_CHAR (param, len, offset);
p = param + offset;
}
else
p++;
}
break;
case RP_SHORT_RIGHT: /* remove shortest match at end */
p = end;
while (p >= param)
{
if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
c = *p; *p = '\0';
ret = savestring (param);
*p = c;
FREE (mblen);
return (ret);
}
if (MB_CUR_MAX > 1)
{
while (p >= param)
if (mblen[--p - param])
break;
}
else
p--;
}
break;
n = strlen (param);
xret = xmalloc (n + 1);
memset (&ps, '\0', sizeof (mbstate_t));
n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps);
xret[n] = '\0'; /* just to make sure */
free (oret);
return xret;
}
FREE (mblen);
return (savestring (param)); /* no match, return original string */
else
#endif
return (remove_upattern (param, pattern, op));
}
/* Return 1 of the first character of STRING could match the first
@@ -3045,7 +3133,7 @@ match_pattern_char (pat, string)
MATCH_BEG and MATCH_END anchor the match at the beginning and end
of the string, respectively. The longest match is returned. */
static int
match_pattern (string, pat, mtype, sp, ep)
match_upattern (string, pat, mtype, sp, ep)
char *string, *pat;
int mtype;
char **sp, **ep;
@@ -3053,33 +3141,18 @@ match_pattern (string, pat, mtype, sp, ep)
int c, len;
register char *p, *p1;
char *end;
int offset;
unsigned char *mblen;
DECLARE_MBSTATE;
if (string == 0 || *string == 0 || pat == 0 || *pat == 0)
return (0);
len = STRLEN (string);
end = string + len;
mblen = (unsigned char *)0;
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && (mtype == MATCH_ANY || mtype == MATCH_BEG))
mblen = mb_getcharlens (string, len);
#endif
switch (mtype)
{
case MATCH_ANY:
p = string;
offset = 0;
while (p <= end)
for (p = string; p <= end; p++)
{
if (match_pattern_char (pat, p))
{
p1 = end;
while (p1 >= p)
for (p1 = end; p1 >= p; p1--)
{
c = *p1; *p1 = '\0';
if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
@@ -3087,40 +3160,20 @@ match_pattern (string, pat, mtype, sp, ep)
*p1 = c;
*sp = p;
*ep = p1;
FREE (mblen);
return 1;
}
*p1 = c;
if (MB_CUR_MAX > 1)
{
while (p1 >= p)
if (mblen[--p1 - string])
break;
}
else
p1--;
}
}
if (MB_CUR_MAX > 1)
{
ADVANCE_CHAR (string, len, offset);
p = string + offset;
}
else
p++;
}
FREE (mblen);
return (0);
case MATCH_BEG:
if (match_pattern_char (pat, string) == 0)
return (0);
p = end;
while (p >= string)
for (p = end; p >= string; p--)
{
c = *p; *p = '\0';
if (strmatch (pat, string, FNMATCH_EXTFLAG) == 0)
@@ -3128,28 +3181,15 @@ match_pattern (string, pat, mtype, sp, ep)
*p = c;
*sp = string;
*ep = p;
FREE (mblen);
return 1;
}
*p = c;
if (MB_CUR_MAX > 1)
{
while (p >= string)
if (mblen[--p - string])
break;
}
else
p--;
}
FREE (mblen);
return (0);
case MATCH_END:
p = string;
offset = 0;
while (p <= end)
for (p = string; p <= end; p++)
{
if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
{
@@ -3158,21 +3198,167 @@ match_pattern (string, pat, mtype, sp, ep)
return 1;
}
if (MB_CUR_MAX > 1)
{
ADVANCE_CHAR (string, len, offset);
p = string + offset;
}
else
p++;
}
return (0);
}
FREE (mblen);
return (0);
}
#if defined (HANDLE_MULTIBYTE)
/* Return 1 of the first character of WSTRING could match the first
character of pattern WPAT. Wide character version. */
static int
match_pattern_wchar (wpat, wstring)
wchar_t *wpat, *wstring;
{
wchar_t wc;
if (*wstring == 0)
return (0);
switch (wc = *wpat++)
{
default:
return (*wstring == wc);
case L'\\':
return (*wstring == *wpat);
case L'?':
return (*wpat == LPAREN ? 1 : (*wstring != L'\0'));
case L'*':
return (1);
case L'+':
case L'!':
case L'@':
return (*wpat == LPAREN ? 1 : (*wstring == wc));
case L'[':
return (*wstring != L'\0');
}
}
/* Match WPAT anywhere in WSTRING and return the match boundaries.
This returns 1 in case of a successful match, 0 otherwise. Wide
character version. */
static int
match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
wchar_t *wstring;
char **indices;
size_t wstrlen;
wchar_t *wpat;
int mtype;
char **sp, **ep;
{
wchar_t wc;
int len;
#if 0
size_t n, n1; /* Apple's gcc seems to miscompile this badly */
#else
int n, n1;
#endif
switch (mtype)
{
case MATCH_ANY:
for (n = 0; n <= wstrlen; n++)
{
if (match_pattern_wchar (wpat, wstring + n))
{
for (n1 = wstrlen; n1 >= n; n1--)
{
wc = wstring[n1]; wstring[n1] = L'\0';
if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0)
{
wstring[n1] = wc;
*sp = indices[n];
*ep = indices[n1];
return 1;
}
wstring[n1] = wc;
}
}
}
return (0);
case MATCH_BEG:
if (match_pattern_wchar (wpat, wstring) == 0)
return (0);
for (n = wstrlen; n >= 0; n--)
{
wc = wstring[n]; wstring[n] = L'\0';
if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG) == 0)
{
wstring[n] = wc;
*sp = indices[0];
*ep = indices[n];
return 1;
}
wstring[n] = wc;
}
return (0);
case MATCH_END:
for (n = 0; n <= wstrlen; n++)
{
if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0)
{
*sp = indices[n];
*ep = indices[wstrlen];
return 1;
}
}
return (0);
}
return (0);
}
#endif /* HANDLE_MULTIBYTE */
static int
match_pattern (string, pat, mtype, sp, ep)
char *string, *pat;
int mtype;
char **sp, **ep;
{
#if defined (HANDLE_MULTIBYTE)
int ret;
size_t n;
wchar_t *wstring, *wpat;
char **indices;
#endif
if (string == 0 || *string == 0 || pat == 0 || *pat == 0)
return (0);
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1)
{
n = xdupmbstowcs (&wpat, NULL, pat);
if (n == (size_t)-1)
return (match_upattern (string, pat, mtype, sp, ep));
n = xdupmbstowcs (&wstring, &indices, string);
if (n == (size_t)-1)
{
free (wpat);
return (match_upattern (string, pat, mtype, sp, ep));
}
ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep);
free (wpat);
free (wstring);
free (indices);
return (ret);
}
else
#endif
return (match_upattern (string, pat, mtype, sp, ep));
}
static int
getpatspec (c, value)
int c;
@@ -4854,8 +5040,8 @@ parameter_brace_substring (varname, value, substr, quoted)
#if defined (ARRAY_VARS)
case VT_ARRAYVAR:
/* We want E2 to be the number of elements desired (arrays can be sparse,
so verify_substring_values just returns the numbers specified and we
rely on array_subrange to understand how to deal with them). */
so verify_substring_values just returns the numbers specified and we
rely on array_subrange to understand how to deal with them). */
tt = array_subrange (array_cell (v), e1, e2, starsub, quoted);
if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
{
+7293
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -0,0 +1 @@
$
+1 -1
View File
@@ -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
Executable
BIN
View File
Binary file not shown.
+26
View File
@@ -0,0 +1,26 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
main()
{
size_t wstrlen, n, n1;
#ifdef BUG
size_t n, n1;
#else
int n, n1;
#endif
wstrlen = 4;
for (n = 0; n < wstrlen; n++) {
for (n1 = wstrlen; n1 >= n; n1--) {
fprintf(stderr, "n = %lu n1 = %lu wstrlen = %lu\n", n, n1, wstrlen);
if (n1 > wstrlen) {
fprintf(stderr, "n1 (%lu) > wstrlen (%lu)\n", n1, wstrlen);
break;
}
}
}
exit (0);
}
BIN
View File
Binary file not shown.
Executable
BIN
View File
Binary file not shown.
+22
View File
@@ -0,0 +1,22 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
main()
{
size_t wstrlen;
int n, n1;
wstrlen = 4;
for (n = 0; n < wstrlen; n++) {
for (n1 = wstrlen; n1 >= n; n1--) {
fprintf(stderr, "n = %lu n1 = %lu wstrlen = %lu\n", n, n1, wstrlen);
if (n1 > wstrlen) {
fprintf(stderr, "n1 (%lu) > wstrlen (%lu)\n", n1, wstrlen);
break;
}
}
}
exit (0);
}
BIN
View File
Binary file not shown.