mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-28 07:59:50 +02:00
commit bash-20040129 snapshot
This commit is contained in:
@@ -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 \?.
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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,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
@@ -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
@@ -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])
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
@@ -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. */
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user