mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-27 15:43:18 +02:00
commit bash-20101124 snapshot
This commit is contained in:
@@ -260,7 +260,7 @@ u. History expansion no longer expands the `$!' variable expansion.
|
||||
v. Posix mode shells no longer exit if a variable assignment error occurs
|
||||
with an assignment preceding a command that is not a special builtin.
|
||||
|
||||
w. Non-interactive mode shells exit if -u is enabled an an attempt is made
|
||||
w. Non-interactive mode shells exit if -u is enabled and an attempt is made
|
||||
to use an unset variable with the % or # expansions, the `//', `^', or
|
||||
`,' expansions, or the parameter length expansion.
|
||||
|
||||
|
||||
+1
-1
@@ -260,7 +260,7 @@ u. History expansion no longer expands the `$!' variable expansion.
|
||||
v. Posix mode shells no longer exit if a variable assignment error occurs
|
||||
with an assignment preceding a command that is not a special builtin.
|
||||
|
||||
w. Non-interactive mode shells exit if -u is enabled an an attempt is made
|
||||
w. Non-interactive mode shells exit if -u is enabled and an attempt is made
|
||||
to use an unset variable with the % or # expansions, the `//', `^', or
|
||||
`,' expansions, or the parameter length expansion.
|
||||
|
||||
|
||||
+138
@@ -10640,3 +10640,141 @@ lib/readline/complete.c
|
||||
users_dirname gets tacked back onto the beginning of the possible
|
||||
completions and then requoted. Bug reported by Andreas Schwab
|
||||
<schwab@linux-m68k.org>
|
||||
|
||||
11/22
|
||||
-----
|
||||
lib/readline/parens.c
|
||||
- the `blink-matching-paren' variable should default to off
|
||||
|
||||
11/23
|
||||
-----
|
||||
subst.h
|
||||
- add extern declaration for close_new_fifos()
|
||||
|
||||
lib/sh/fnxform.c
|
||||
- fix curencoding to return the character past the `.', not a string
|
||||
beginning with `.'
|
||||
|
||||
lib/sh/unicode.c
|
||||
- fix stub_charset to do the same cut-off at `@' as curencoding().
|
||||
These two functions should be combined
|
||||
|
||||
builtins/printf.def
|
||||
- document new %(datefmt)T modifier in help text
|
||||
|
||||
11/24
|
||||
-----
|
||||
parse.y
|
||||
- fix `W' case in decode_prompt_string: memmove was copying one too
|
||||
few bytes and missed the closing NUL. Bug report from Tim Mooney
|
||||
<Tim.Mooney@ndsu.edu>
|
||||
|
||||
11/26
|
||||
-----
|
||||
subst.c
|
||||
- in expand_word_internal, don't add quoted nulls to partially-
|
||||
quoted strings if the word will not be subjected to word splitting
|
||||
later (which will remove the quoted null). Fixes bug reported by
|
||||
Rocky Bernstein <rocky.bernstein@gmail.com>
|
||||
|
||||
11/28
|
||||
-----
|
||||
subst.c
|
||||
- change multibyte case of match_pattern to revert to match_upattern
|
||||
if neither the pattern nor the string has any multibyte characters
|
||||
|
||||
alias.c
|
||||
- fix tests of backslash-escaped characters in skipquotes, skipws,
|
||||
rd_token to check for backslash at EOS and not go past the end.
|
||||
Fixes debian bug 603696 reported by Tim Small <tim@buttersideup.com>
|
||||
|
||||
include/shmbchar.h
|
||||
- new file, mbchar.h from gnulib minus the <stdbool.h> include
|
||||
|
||||
lib/sh/shmbchar.c
|
||||
- new file, mbchar.c from gnulib with additions
|
||||
- moved mbstrlen from subst.c to here, changed initialization of mbs
|
||||
- change mbstrlen to use is_basic to avoid calls to mbrlen for ASCII
|
||||
chars; code hints from gnulib
|
||||
- don't copy mbs and mbsbak if we're not calling mbrlen
|
||||
|
||||
11/29
|
||||
-----
|
||||
lib/glob/smatch.c
|
||||
- change xstrmatch to use internal_strmatch() if the pattern and
|
||||
string don't have any multibyte characters
|
||||
|
||||
11/30
|
||||
-----
|
||||
include/shmbutil.h
|
||||
- change ADVANCE_CHAR and ADVANCE_CHAR_P macros to use is_basic and
|
||||
only call mbrlen and copy state and state_bak if is_basic returns
|
||||
false (non-ASCII). Called all over the place.
|
||||
- change rest of macros except BACKUP_CHAR and BACKUP_CHAR_P in the
|
||||
same way
|
||||
|
||||
12/2
|
||||
----
|
||||
subst.c
|
||||
- audit all calls to string_list and make sure caller can handle a
|
||||
NULL return value. Fixes bug reported by David Rochberg
|
||||
<rochberg@google.com>
|
||||
|
||||
general.h
|
||||
- change sh_wassign_func_t to take an additional argument: an int
|
||||
flags word
|
||||
|
||||
subst.c
|
||||
- change do_word_assignment to take an additional argument to match
|
||||
wassign_func_t; change callers
|
||||
- change call to (*assign_func) in expand_word_list_internal to match
|
||||
new wassign_func_t prototype
|
||||
- (*assign_func) passes 1 as additional arg if the simple command is
|
||||
a builtin or function, in which case the assignment to the
|
||||
temporary env should take effect
|
||||
|
||||
variables.c
|
||||
- change assign_in_env to take an additional argument to match
|
||||
wassign_func_t; change callers
|
||||
- move call to sv_ifs from dispose_temporary_env to
|
||||
dispose_used_env_vars; we don't need to do it if called from
|
||||
merge_temporary_env
|
||||
|
||||
12/3
|
||||
----
|
||||
variables.c
|
||||
- change dispose_temporary_env to maintain a list (tempvar_list) of
|
||||
variables that need to be handled specially. If a variable that
|
||||
gets freed by push_temp_var or propagate_temp_var is one of the
|
||||
variables that the shell handles specially (IFS, LANG, etc.), it's
|
||||
stored on the list. For each variable in this list,
|
||||
dispose_temp_var calls stupidly_hack_special_variables.
|
||||
- assign_in_env calls stupidly_hack_special_variables if flags arg
|
||||
is non-zero, so variable assignments affect current shell
|
||||
execution environment if a builtin or function is being executed.
|
||||
Fixes bug reported by Bruno Haible <bruno@clisp.org>
|
||||
|
||||
12/5
|
||||
----
|
||||
subst.c
|
||||
- use mbsmbchar on both string and pattern in match_pattern instead
|
||||
of strlen and mbstrlen; only go through the strings once
|
||||
|
||||
12/6
|
||||
----
|
||||
lib/readline/kill.c
|
||||
- in rl_yank_last_arg, only switch directions if the `count'
|
||||
argument is < 0, not < 1. This makes explicit count arguments of
|
||||
0 work as expected. Fixes bug reported by Dennis Williamson
|
||||
<dennistwilliamson@gmail.com>
|
||||
|
||||
doc/bash.1,lib/readline/doc/{readline.3,rluser.texi}
|
||||
- fix documentation for yank-last-arg to make it clear how the count
|
||||
argument is set and how second and subsequent calls treat any
|
||||
numeric argument
|
||||
|
||||
doc/{bash.1,bashref.texi}
|
||||
- slight changes to the description of test
|
||||
- change \(bv to `|'; it seems that many `internationalized' versions
|
||||
of groff don't render that as a vertical bar. Fixes Debian bug
|
||||
603805
|
||||
|
||||
@@ -10633,3 +10633,142 @@ lib/glob/gmisc.c
|
||||
fix from Andreas Schwab <schwab@linux-m68k.org>
|
||||
- use WLPAREN and WRPAREN in multibyte character environments
|
||||
- fixed typos using L'cc' in a non-wide-char environment
|
||||
|
||||
lib/readline/complete.c
|
||||
- fix rl_filename_completion_function to dequote users_dirname if
|
||||
there is a filename dequoting function (as well as dirname), since
|
||||
users_dirname gets tacked back onto the beginning of the possible
|
||||
completions and then requoted. Bug reported by Andreas Schwab
|
||||
<schwab@linux-m68k.org>
|
||||
|
||||
11/22
|
||||
-----
|
||||
lib/readline/parens.c
|
||||
- the `blink-matching-paren' variable should default to off
|
||||
|
||||
11/23
|
||||
-----
|
||||
subst.h
|
||||
- add extern declaration for close_new_fifos()
|
||||
|
||||
lib/sh/fnxform.c
|
||||
- fix curencoding to return the character past the `.', not a string
|
||||
beginning with `.'
|
||||
|
||||
lib/sh/unicode.c
|
||||
- fix stub_charset to do the same cut-off at `@' as curencoding().
|
||||
These two functions should be combined
|
||||
|
||||
builtins/printf.def
|
||||
- document new %(datefmt)T modifier in help text
|
||||
|
||||
11/24
|
||||
-----
|
||||
parse.y
|
||||
- fix `W' case in decode_prompt_string: memmove was copying one too
|
||||
few bytes and missed the closing NUL. Bug report from Tim Mooney
|
||||
<Tim.Mooney@ndsu.edu>
|
||||
|
||||
11/26
|
||||
-----
|
||||
subst.c
|
||||
- in expand_word_internal, don't add quoted nulls to partially-
|
||||
quoted strings if the word will not be subjected to word splitting
|
||||
later (which will remove the quoted null). Fixes bug reported by
|
||||
Rocky Bernstein <rocky.bernstein@gmail.com>
|
||||
|
||||
11/28
|
||||
-----
|
||||
subst.c
|
||||
- change multibyte case of match_pattern to revert to match_upattern
|
||||
if neither the pattern nor the string has any multibyte characters
|
||||
|
||||
alias.c
|
||||
- fix tests of backslash-escaped characters in skipquotes, skipws,
|
||||
rd_token to check for backslash at EOS and not go past the end.
|
||||
Fixes debian bug 603696 reported by Tim Small <tim@buttersideup.com>
|
||||
|
||||
include/shmbchar.h
|
||||
- new file, mbchar.h from gnulib minus the <stdbool.h> include
|
||||
|
||||
lib/sh/shmbchar.c
|
||||
- new file, mbchar.c from gnulib with additions
|
||||
- moved mbstrlen from subst.c to here, changed initialization of mbs
|
||||
- change mbstrlen to use is_basic to avoid calls to mbrlen for ASCII
|
||||
chars; code hints from gnulib
|
||||
- don't copy mbs and mbsbak if we're not calling mbrlen
|
||||
|
||||
11/29
|
||||
-----
|
||||
lib/glob/smatch.c
|
||||
- change xstrmatch to use internal_strmatch() if the pattern and
|
||||
string don't have any multibyte characters
|
||||
|
||||
11/30
|
||||
-----
|
||||
include/shmbutil.h
|
||||
- change ADVANCE_CHAR and ADVANCE_CHAR_P macros to use is_basic and
|
||||
only call mbrlen and copy state and state_bak if is_basic returns
|
||||
false (non-ASCII). Called all over the place.
|
||||
- change rest of macros except BACKUP_CHAR and BACKUP_CHAR_P in the
|
||||
same way
|
||||
|
||||
12/2
|
||||
----
|
||||
subst.c
|
||||
- audit all calls to string_list and make sure caller can handle a
|
||||
NULL return value. Fixes bug reported by David Rochberg
|
||||
<rochberg@google.com>
|
||||
|
||||
general.h
|
||||
- change sh_wassign_func_t to take an additional argument: an int
|
||||
flags word
|
||||
|
||||
subst.c
|
||||
- change do_word_assignment to take an additional argument to match
|
||||
wassign_func_t; change callers
|
||||
- change call to (*assign_func) in expand_word_list_internal to match
|
||||
new wassign_func_t prototype
|
||||
- (*assign_func) passes 1 as additional arg if the simple command is
|
||||
a builtin or function, in which case the assignment to the
|
||||
temporary env should take effect
|
||||
|
||||
variables.c
|
||||
- change assign_in_env to take an additional argument to match
|
||||
wassign_func_t; change callers
|
||||
- move call to sv_ifs from dispose_temporary_env to
|
||||
dispose_used_env_vars; we don't need to do it if called from
|
||||
merge_temporary_env
|
||||
|
||||
12/3
|
||||
----
|
||||
variables.c
|
||||
- change dispose_temporary_env to maintain a list (tempvar_list) of
|
||||
variables that need to be handled specially. If a variable that
|
||||
gets freed by push_temp_var or propagate_temp_var is one of the
|
||||
variables that the shell handles specially (IFS, LANG, etc.), it's
|
||||
stored on the list. For each variable in this list,
|
||||
dispose_temp_var calls stupidly_hack_special_variables.
|
||||
- assign_in_env calls stupidly_hack_special_variables if flags arg
|
||||
is non-zero, so variable assignments affect current shell
|
||||
execution environment if a builtin or function is being executed.
|
||||
Fixes bug reported by Bruno Haible <bruno@clisp.org>
|
||||
|
||||
12/5
|
||||
----
|
||||
subst.c
|
||||
- use mbsmbchar on both string and pattern in match_pattern instead
|
||||
of strlen and mbstrlen; only go through the strings once
|
||||
|
||||
12/6
|
||||
----
|
||||
lib/readline/kill.c
|
||||
- in rl_yank_last_arg, only switch directions if the `count'
|
||||
argument is < 0, not < 1. This makes explicit count arguments of
|
||||
0 work as expected. Fixes bug reported by Dennis Williamson
|
||||
<dennistwilliamson@gmail.com>
|
||||
|
||||
doc/bash.1,lib/readline/doc/{readline.3,rluser.texi}
|
||||
- fix documentation for yank-last-arg to make it clear how the count
|
||||
argument is set and how second and subsequent calls treat any
|
||||
numeric argument
|
||||
|
||||
@@ -220,6 +220,7 @@ include/posixselect.h f
|
||||
include/posixstat.h f
|
||||
include/posixtime.h f
|
||||
include/posixwait.h f
|
||||
include/shmbchar.h f
|
||||
include/shmbutil.h f
|
||||
include/shtty.h f
|
||||
include/stdc.h f
|
||||
@@ -411,6 +412,7 @@ lib/sh/pathphys.c f
|
||||
lib/sh/rename.c f
|
||||
lib/sh/setlinebuf.c f
|
||||
lib/sh/shmatch.c f
|
||||
lib/sh/shmbchar.c f
|
||||
lib/sh/shquote.c f
|
||||
lib/sh/shtty.c f
|
||||
lib/sh/snprintf.c f
|
||||
@@ -852,6 +854,7 @@ tests/exp.right f
|
||||
tests/exp1.sub f
|
||||
tests/exp2.sub f
|
||||
tests/exp3.sub f
|
||||
tests/exp4.sub f
|
||||
tests/extglob.tests f
|
||||
tests/extglob.right f
|
||||
tests/extglob1.sub f
|
||||
@@ -901,6 +904,7 @@ tests/input-line.sub f
|
||||
tests/input.right f
|
||||
tests/intl.tests f
|
||||
tests/intl1.sub f
|
||||
tests/intl2.sub f
|
||||
tests/intl.right f
|
||||
tests/iquote.tests f
|
||||
tests/iquote.right f
|
||||
|
||||
@@ -220,6 +220,7 @@ include/posixselect.h f
|
||||
include/posixstat.h f
|
||||
include/posixtime.h f
|
||||
include/posixwait.h f
|
||||
include/shmbchar.h f
|
||||
include/shmbutil.h f
|
||||
include/shtty.h f
|
||||
include/stdc.h f
|
||||
@@ -411,6 +412,7 @@ lib/sh/pathphys.c f
|
||||
lib/sh/rename.c f
|
||||
lib/sh/setlinebuf.c f
|
||||
lib/sh/shmatch.c f
|
||||
lib/sh/shmbchar.c f
|
||||
lib/sh/shquote.c f
|
||||
lib/sh/shtty.c f
|
||||
lib/sh/snprintf.c f
|
||||
@@ -852,6 +854,7 @@ tests/exp.right f
|
||||
tests/exp1.sub f
|
||||
tests/exp2.sub f
|
||||
tests/exp3.sub f
|
||||
tests/exp4.sub f
|
||||
tests/extglob.tests f
|
||||
tests/extglob.right f
|
||||
tests/extglob1.sub f
|
||||
@@ -950,6 +953,8 @@ tests/posixexp.tests f
|
||||
tests/posixexp.right f
|
||||
tests/posixexp1.sub f
|
||||
tests/posixexp2.sub f
|
||||
tests/posixexp2.tests f
|
||||
tests/posixexp2.right f
|
||||
tests/posixpat.tests f
|
||||
tests/posixpat.right f
|
||||
tests/posixpipe.tests f
|
||||
@@ -1045,6 +1050,7 @@ tests/run-nquote4 f
|
||||
tests/run-nquote5 f
|
||||
tests/run-posix2 f
|
||||
tests/run-posixexp f
|
||||
tests/run-posixexp2 f
|
||||
tests/run-posixpat f
|
||||
tests/run-posixpipe f
|
||||
tests/run-precedence f
|
||||
|
||||
+6
-6
@@ -215,7 +215,7 @@ SHLIB_SOURCE = ${SH_LIBSRC}/clktck.c ${SH_LIBSRC}/getcwd.c \
|
||||
${SH_LIBSRC}/ufuncs.c ${SH_LIBSRC}/dprintf.c \
|
||||
${SH_LIBSRC}/input_avail.c ${SH_LIBSRC}/mbscasecmp.c \
|
||||
${SH_LIBSRC}/fnxform.c ${SH_LIBSRC}/unicode.c \
|
||||
${SH_LIBSRC}/wcswidth.c
|
||||
${SH_LIBSRC}/wcswidth.c ${SH_LIBSRC}/shmbchar.c
|
||||
|
||||
SHLIB_LIB = -lsh
|
||||
SHLIB_LIBNAME = libsh.a
|
||||
@@ -973,7 +973,7 @@ make_cmd.o: config.h bashtypes.h ${BASHINCDIR}/filecntl.h bashansi.h
|
||||
make_cmd.o: command.h ${BASHINCDIR}/stdc.h general.h xmalloc.h error.h flags.h make_cmd.h
|
||||
make_cmd.o: variables.h arrayfunc.h conftypes.h array.h hashlib.h subst.h input.h externs.h
|
||||
make_cmd.o: jobs.h quit.h siglist.h syntax.h dispose_cmd.h parser.h
|
||||
make_cmd.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/ocache.h
|
||||
make_cmd.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/shmbchar.h ${BASHINCDIR}/ocache.h
|
||||
y.tab.o: config.h bashtypes.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/memalloc.h
|
||||
y.tab.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h
|
||||
y.tab.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h
|
||||
@@ -988,7 +988,7 @@ pathexp.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h
|
||||
pathexp.o: make_cmd.h subst.h sig.h pathnames.h externs.h
|
||||
pathexp.o: pathexp.h flags.h
|
||||
pathexp.o: $(GLOB_LIBSRC)/glob.h $(GLOB_LIBSRC)/strmatch.h
|
||||
pathexp.o: ${BASHINCDIR}/shmbutil.h
|
||||
pathexp.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/shmbchar.h
|
||||
print_cmd.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h
|
||||
print_cmd.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h
|
||||
print_cmd.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h
|
||||
@@ -1030,7 +1030,7 @@ subst.o: flags.h jobs.h siglist.h execute_cmd.h ${BASHINCDIR}/filecntl.h trap.h
|
||||
subst.o: mailcheck.h input.h $(DEFSRC)/getopt.h $(DEFSRC)/common.h
|
||||
subst.o: bashline.h bashhist.h ${GLOB_LIBSRC}/strmatch.h
|
||||
subst.o: ${BASHINCDIR}/chartypes.h
|
||||
subst.o: ${BASHINCDIR}/shmbutil.h
|
||||
subst.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/shmbchar.h
|
||||
subst.o: ${DEFDIR}/builtext.h
|
||||
test.o: bashtypes.h ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/filecntl.h
|
||||
test.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h
|
||||
@@ -1089,7 +1089,7 @@ arrayfunc.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h
|
||||
arrayfunc.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h
|
||||
arrayfunc.o: make_cmd.h subst.h sig.h pathnames.h externs.h pathexp.h
|
||||
arrayfunc.o: $(DEFSRC)/common.h
|
||||
arrayfunc.o: ${BASHINCDIR}/shmbutil.h
|
||||
arrayfunc.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/shmbchar.h
|
||||
assoc.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h
|
||||
assoc.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h
|
||||
assoc.o: command.h ${BASHINCDIR}/stdc.h error.h
|
||||
@@ -1103,7 +1103,7 @@ braces.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h
|
||||
braces.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h
|
||||
braces.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h
|
||||
braces.o: make_cmd.h subst.h sig.h pathnames.h externs.h
|
||||
braces.o: ${BASHINCDIR}/shmbutil.h
|
||||
braces.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/shmbchar.h
|
||||
alias.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h command.h ${BASHINCDIR}/stdc.h
|
||||
alias.o: general.h xmalloc.h bashtypes.h externs.h alias.h
|
||||
alias.o: pcomplete.h
|
||||
|
||||
+2
-2
@@ -215,7 +215,7 @@ SHLIB_SOURCE = ${SH_LIBSRC}/clktck.c ${SH_LIBSRC}/getcwd.c \
|
||||
${SH_LIBSRC}/ufuncs.c ${SH_LIBSRC}/dprintf.c \
|
||||
${SH_LIBSRC}/input_avail.c ${SH_LIBSRC}/mbscasecmp.c \
|
||||
${SH_LIBSRC}/fnxform.c ${SH_LIBSRC}/unicode.c \
|
||||
${SH_LIBSRC}/wcswidth.c
|
||||
${SH_LIBSRC}/wcswidth.c ${SH_LIBSRC}/shmbchar.c
|
||||
|
||||
SHLIB_LIB = -lsh
|
||||
SHLIB_LIBNAME = libsh.a
|
||||
@@ -522,7 +522,7 @@ CREATED_SUPPORT = signames.h recho$(EXEEXT) zecho$(EXEEXT) printenv$(EXEEXT) \
|
||||
mksyntax${EXEEXT} syntax.c $(VERSPROG) $(VERSOBJ) \
|
||||
buildversion.o mksignames.o signames.o buildsignames.o
|
||||
CREATED_CONFIGURE = config.h config.cache config.status config.log \
|
||||
stamp-h po/POTFILES
|
||||
stamp-h po/POTFILES config.status.lineno
|
||||
CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \
|
||||
lib/readline/Makefile lib/glob/Makefile \
|
||||
lib/sh/Makefile lib/tilde/Makefile lib/malloc/Makefile \
|
||||
|
||||
@@ -67,7 +67,7 @@ u. History expansion no longer expands the `$!' variable expansion.
|
||||
v. Posix mode shells no longer exit if a variable assignment error occurs
|
||||
with an assignment preceding a command that is not a special builtin.
|
||||
|
||||
w. Non-interactive mode shells exit if -u is enabled an an attempt is made
|
||||
w. Non-interactive mode shells exit if -u is enabled and an attempt is made
|
||||
to use an unset variable with the % or # expansions, the `//', `^', or
|
||||
`,' expansions, or the parameter length expansion.
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ u. History expansion no longer expands the `$!' variable expansion.
|
||||
v. Posix mode shells no longer exit if a variable assignment error occurs
|
||||
with an assignment preceding a command that is not a special builtin.
|
||||
|
||||
w. Non-interactive mode shells exit if -u is enabled an an attempt is made
|
||||
w. Non-interactive mode shells exit if -u is enabled and an attempt is made
|
||||
to use an unset variable with the % or # expansions, the `//', `^', or
|
||||
`,' expansions, or the parameter length expansion.
|
||||
|
||||
|
||||
@@ -319,6 +319,8 @@ skipquotes (string, start)
|
||||
if (string[i] == '\\')
|
||||
{
|
||||
i++; /* skip backslash-quoted quote characters, too */
|
||||
if (string[i] == 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -364,6 +366,8 @@ skipws (string, start)
|
||||
if (string[i] == '\\')
|
||||
{
|
||||
peekc = string[i+1];
|
||||
if (peekc == 0)
|
||||
break;
|
||||
if (ISLETTER (peekc))
|
||||
backslash_quoted_word++; /* this is a backslash-quoted word */
|
||||
else
|
||||
@@ -429,6 +433,8 @@ rd_token (string, start)
|
||||
if (string[i] == '\\')
|
||||
{
|
||||
i++; /* skip backslash-escaped character */
|
||||
if (string[i] == 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,576 @@
|
||||
/* alias.c -- Not a full alias, but just the kind that we use in the
|
||||
shell. Csh style alias is somewhere else (`over there, in a box'). */
|
||||
|
||||
/* Copyright (C) 1987-2009 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (ALIAS)
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "chartypes.h"
|
||||
#include "bashansi.h"
|
||||
#include "command.h"
|
||||
#include "general.h"
|
||||
#include "externs.h"
|
||||
#include "alias.h"
|
||||
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
# include "pcomplete.h"
|
||||
#endif
|
||||
|
||||
#define ALIAS_HASH_BUCKETS 16 /* must be power of two */
|
||||
|
||||
typedef int sh_alias_map_func_t __P((alias_t *));
|
||||
|
||||
static void free_alias_data __P((PTR_T));
|
||||
static alias_t **map_over_aliases __P((sh_alias_map_func_t *));
|
||||
static void sort_aliases __P((alias_t **));
|
||||
static int qsort_alias_compare __P((alias_t **, alias_t **));
|
||||
|
||||
#if defined (READLINE)
|
||||
static int skipquotes __P((char *, int));
|
||||
static int skipws __P((char *, int));
|
||||
static int rd_token __P((char *, int));
|
||||
#endif
|
||||
|
||||
/* Non-zero means expand all words on the line. Otherwise, expand
|
||||
after first expansion if the expansion ends in a space. */
|
||||
int alias_expand_all = 0;
|
||||
|
||||
/* The list of aliases that we have. */
|
||||
HASH_TABLE *aliases = (HASH_TABLE *)NULL;
|
||||
|
||||
void
|
||||
initialize_aliases ()
|
||||
{
|
||||
if (aliases == 0)
|
||||
aliases = hash_create (ALIAS_HASH_BUCKETS);
|
||||
}
|
||||
|
||||
/* Scan the list of aliases looking for one with NAME. Return NULL
|
||||
if the alias doesn't exist, else a pointer to the alias_t. */
|
||||
alias_t *
|
||||
find_alias (name)
|
||||
char *name;
|
||||
{
|
||||
BUCKET_CONTENTS *al;
|
||||
|
||||
if (aliases == 0)
|
||||
return ((alias_t *)NULL);
|
||||
|
||||
al = hash_search (name, aliases, 0);
|
||||
return (al ? (alias_t *)al->data : (alias_t *)NULL);
|
||||
}
|
||||
|
||||
/* Return the value of the alias for NAME, or NULL if there is none. */
|
||||
char *
|
||||
get_alias_value (name)
|
||||
char *name;
|
||||
{
|
||||
alias_t *alias;
|
||||
|
||||
if (aliases == 0)
|
||||
return ((char *)NULL);
|
||||
|
||||
alias = find_alias (name);
|
||||
return (alias ? alias->value : (char *)NULL);
|
||||
}
|
||||
|
||||
/* Make a new alias from NAME and VALUE. If NAME can be found,
|
||||
then replace its value. */
|
||||
void
|
||||
add_alias (name, value)
|
||||
char *name, *value;
|
||||
{
|
||||
BUCKET_CONTENTS *elt;
|
||||
alias_t *temp;
|
||||
int n;
|
||||
|
||||
if (!aliases)
|
||||
{
|
||||
initialize_aliases ();
|
||||
temp = (alias_t *)NULL;
|
||||
}
|
||||
else
|
||||
temp = find_alias (name);
|
||||
|
||||
if (temp)
|
||||
{
|
||||
free (temp->value);
|
||||
temp->value = savestring (value);
|
||||
temp->flags &= ~AL_EXPANDNEXT;
|
||||
n = value[strlen (value) - 1];
|
||||
if (n == ' ' || n == '\t')
|
||||
temp->flags |= AL_EXPANDNEXT;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = (alias_t *)xmalloc (sizeof (alias_t));
|
||||
temp->name = savestring (name);
|
||||
temp->value = savestring (value);
|
||||
temp->flags = 0;
|
||||
|
||||
n = value[strlen (value) - 1];
|
||||
if (n == ' ' || n == '\t')
|
||||
temp->flags |= AL_EXPANDNEXT;
|
||||
|
||||
elt = hash_insert (savestring (name), aliases, HASH_NOSRCH);
|
||||
elt->data = temp;
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
set_itemlist_dirty (&it_aliases);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete a single alias structure. */
|
||||
static void
|
||||
free_alias_data (data)
|
||||
PTR_T data;
|
||||
{
|
||||
register alias_t *a;
|
||||
|
||||
a = (alias_t *)data;
|
||||
free (a->value);
|
||||
free (a->name);
|
||||
free (data);
|
||||
}
|
||||
|
||||
/* Remove the alias with name NAME from the alias table. Returns
|
||||
the number of aliases left in the table, or -1 if the alias didn't
|
||||
exist. */
|
||||
int
|
||||
remove_alias (name)
|
||||
char *name;
|
||||
{
|
||||
BUCKET_CONTENTS *elt;
|
||||
|
||||
if (aliases == 0)
|
||||
return (-1);
|
||||
|
||||
elt = hash_remove (name, aliases, 0);
|
||||
if (elt)
|
||||
{
|
||||
free_alias_data (elt->data);
|
||||
free (elt->key); /* alias name */
|
||||
free (elt); /* XXX */
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
set_itemlist_dirty (&it_aliases);
|
||||
#endif
|
||||
return (aliases->nentries);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Delete all aliases. */
|
||||
void
|
||||
delete_all_aliases ()
|
||||
{
|
||||
if (aliases == 0)
|
||||
return;
|
||||
|
||||
hash_flush (aliases, free_alias_data);
|
||||
hash_dispose (aliases);
|
||||
aliases = (HASH_TABLE *)NULL;
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
set_itemlist_dirty (&it_aliases);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return an array of aliases that satisfy the conditions tested by FUNCTION.
|
||||
If FUNCTION is NULL, return all aliases. */
|
||||
static alias_t **
|
||||
map_over_aliases (function)
|
||||
sh_alias_map_func_t *function;
|
||||
{
|
||||
register int i;
|
||||
register BUCKET_CONTENTS *tlist;
|
||||
alias_t *alias, **list;
|
||||
int list_index;
|
||||
|
||||
i = HASH_ENTRIES (aliases);
|
||||
if (i == 0)
|
||||
return ((alias_t **)NULL);
|
||||
|
||||
list = (alias_t **)xmalloc ((i + 1) * sizeof (alias_t *));
|
||||
for (i = list_index = 0; i < aliases->nbuckets; i++)
|
||||
{
|
||||
for (tlist = hash_items (i, aliases); tlist; tlist = tlist->next)
|
||||
{
|
||||
alias = (alias_t *)tlist->data;
|
||||
|
||||
if (!function || (*function) (alias))
|
||||
{
|
||||
list[list_index++] = alias;
|
||||
list[list_index] = (alias_t *)NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (list);
|
||||
}
|
||||
|
||||
static void
|
||||
sort_aliases (array)
|
||||
alias_t **array;
|
||||
{
|
||||
qsort (array, strvec_len ((char **)array), sizeof (alias_t *), (QSFUNC *)qsort_alias_compare);
|
||||
}
|
||||
|
||||
static int
|
||||
qsort_alias_compare (as1, as2)
|
||||
alias_t **as1, **as2;
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((result = (*as1)->name[0] - (*as2)->name[0]) == 0)
|
||||
result = strcmp ((*as1)->name, (*as2)->name);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Return a sorted list of all defined aliases */
|
||||
alias_t **
|
||||
all_aliases ()
|
||||
{
|
||||
alias_t **list;
|
||||
|
||||
if (aliases == 0 || HASH_ENTRIES (aliases) == 0)
|
||||
return ((alias_t **)NULL);
|
||||
|
||||
list = map_over_aliases ((sh_alias_map_func_t *)NULL);
|
||||
if (list)
|
||||
sort_aliases (list);
|
||||
return (list);
|
||||
}
|
||||
|
||||
char *
|
||||
alias_expand_word (s)
|
||||
char *s;
|
||||
{
|
||||
alias_t *r;
|
||||
|
||||
r = find_alias (s);
|
||||
return (r ? savestring (r->value) : (char *)NULL);
|
||||
}
|
||||
|
||||
/* Readline support functions -- expand all aliases in a line. */
|
||||
|
||||
#if defined (READLINE)
|
||||
|
||||
/* Return non-zero if CHARACTER is a member of the class of characters
|
||||
that are self-delimiting in the shell (this really means that these
|
||||
characters delimit tokens). */
|
||||
#define self_delimiting(character) (member ((character), " \t\n\r;|&()"))
|
||||
|
||||
/* Return non-zero if CHARACTER is a member of the class of characters
|
||||
that delimit commands in the shell. */
|
||||
#define command_separator(character) (member ((character), "\r\n;|&("))
|
||||
|
||||
/* If this is 1, we are checking the next token read for alias expansion
|
||||
because it is the first word in a command. */
|
||||
static int command_word;
|
||||
|
||||
/* This is for skipping quoted strings in alias expansions. */
|
||||
#define quote_char(c) (((c) == '\'') || ((c) == '"'))
|
||||
|
||||
/* Consume a quoted string from STRING, starting at string[START] (so
|
||||
string[START] is the opening quote character), and return the index
|
||||
of the closing quote character matching the opening quote character.
|
||||
This handles single matching pairs of unquoted quotes; it could afford
|
||||
to be a little smarter... This skips words between balanced pairs of
|
||||
quotes, words where the first character is quoted with a `\', and other
|
||||
backslash-escaped characters. */
|
||||
|
||||
static int
|
||||
skipquotes (string, start)
|
||||
char *string;
|
||||
int start;
|
||||
{
|
||||
register int i;
|
||||
int delimiter = string[start];
|
||||
|
||||
/* i starts at START + 1 because string[START] is the opening quote
|
||||
character. */
|
||||
for (i = start + 1 ; string[i] ; i++)
|
||||
{
|
||||
if (string[i] == '\\')
|
||||
{
|
||||
i++; /* skip backslash-quoted quote characters, too */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string[i] == delimiter)
|
||||
return i;
|
||||
}
|
||||
return (i);
|
||||
}
|
||||
|
||||
/* Skip the white space and any quoted characters in STRING, starting at
|
||||
START. Return the new index into STRING, after zero or more characters
|
||||
have been skipped. */
|
||||
static int
|
||||
skipws (string, start)
|
||||
char *string;
|
||||
int start;
|
||||
{
|
||||
register int i;
|
||||
int pass_next, backslash_quoted_word;
|
||||
unsigned char peekc;
|
||||
|
||||
/* skip quoted strings, in ' or ", and words in which a character is quoted
|
||||
with a `\'. */
|
||||
i = backslash_quoted_word = pass_next = 0;
|
||||
|
||||
/* Skip leading whitespace (or separator characters), and quoted words.
|
||||
But save it in the output. */
|
||||
|
||||
for (i = start; string[i]; i++)
|
||||
{
|
||||
if (pass_next)
|
||||
{
|
||||
pass_next = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (whitespace (string[i]))
|
||||
{
|
||||
backslash_quoted_word = 0; /* we are no longer in a backslash-quoted word */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string[i] == '\\')
|
||||
{
|
||||
peekc = string[i+1];
|
||||
if (peekc == 0)
|
||||
break;
|
||||
if (ISLETTER (peekc))
|
||||
backslash_quoted_word++; /* this is a backslash-quoted word */
|
||||
else
|
||||
pass_next++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This only handles single pairs of non-escaped quotes. This
|
||||
overloads backslash_quoted_word to also mean that a word like
|
||||
""f is being scanned, so that the quotes will inhibit any expansion
|
||||
of the word. */
|
||||
if (quote_char(string[i]))
|
||||
{
|
||||
i = skipquotes (string, i);
|
||||
/* This could be a line that contains a single quote character,
|
||||
in which case skipquotes () terminates with string[i] == '\0'
|
||||
(the end of the string). Check for that here. */
|
||||
if (string[i] == '\0')
|
||||
break;
|
||||
|
||||
peekc = string[i + 1];
|
||||
if (ISLETTER (peekc))
|
||||
backslash_quoted_word++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we're in the middle of some kind of quoted word, let it
|
||||
pass through. */
|
||||
if (backslash_quoted_word)
|
||||
continue;
|
||||
|
||||
/* If this character is a shell command separator, then set a hint for
|
||||
alias_expand that the next token is the first word in a command. */
|
||||
|
||||
if (command_separator (string[i]))
|
||||
{
|
||||
command_word++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return (i);
|
||||
}
|
||||
|
||||
/* Characters that may appear in a token. Basically, anything except white
|
||||
space and a token separator. */
|
||||
#define token_char(c) (!((whitespace (string[i]) || self_delimiting (string[i]))))
|
||||
|
||||
/* Read from START in STRING until the next separator character, and return
|
||||
the index of that separator. Skip backslash-quoted characters. Call
|
||||
skipquotes () for quoted strings in the middle or at the end of tokens,
|
||||
so all characters show up (e.g. foo'' and foo""bar) */
|
||||
static int
|
||||
rd_token (string, start)
|
||||
char *string;
|
||||
int start;
|
||||
{
|
||||
register int i;
|
||||
|
||||
/* From here to next separator character is a token. */
|
||||
for (i = start; string[i] && token_char (string[i]); i++)
|
||||
{
|
||||
if (string[i] == '\\')
|
||||
{
|
||||
i++; /* skip backslash-escaped character */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If this character is a quote character, we want to call skipquotes
|
||||
to get the whole quoted portion as part of this word. That word
|
||||
will not generally match an alias, even if te unquoted word would
|
||||
have. The presence of the quotes in the token serves then to
|
||||
inhibit expansion. */
|
||||
if (quote_char (string[i]))
|
||||
{
|
||||
i = skipquotes (string, i);
|
||||
/* This could be a line that contains a single quote character,
|
||||
in which case skipquotes () terminates with string[i] == '\0'
|
||||
(the end of the string). Check for that here. */
|
||||
if (string[i] == '\0')
|
||||
break;
|
||||
|
||||
/* Now string[i] is the matching quote character, and the
|
||||
quoted portion of the token has been scanned. */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return (i);
|
||||
}
|
||||
|
||||
/* Return a new line, with any aliases substituted. */
|
||||
char *
|
||||
alias_expand (string)
|
||||
char *string;
|
||||
{
|
||||
register int i, j, start;
|
||||
char *line, *token;
|
||||
int line_len, tl, real_start, expand_next, expand_this_token;
|
||||
alias_t *alias;
|
||||
|
||||
line_len = strlen (string) + 1;
|
||||
line = (char *)xmalloc (line_len);
|
||||
token = (char *)xmalloc (line_len);
|
||||
|
||||
line[0] = i = 0;
|
||||
expand_next = 0;
|
||||
command_word = 1; /* initialized to expand the first word on the line */
|
||||
|
||||
/* Each time through the loop we find the next word in line. If it
|
||||
has an alias, substitute the alias value. If the value ends in ` ',
|
||||
then try again with the next word. Else, if there is no value, or if
|
||||
the value does not end in space, we are done. */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
||||
token[0] = 0;
|
||||
start = i;
|
||||
|
||||
/* Skip white space and quoted characters */
|
||||
i = skipws (string, start);
|
||||
|
||||
if (start == i && string[i] == '\0')
|
||||
{
|
||||
free (token);
|
||||
return (line);
|
||||
}
|
||||
|
||||
/* copy the just-skipped characters into the output string,
|
||||
expanding it if there is not enough room. */
|
||||
j = strlen (line);
|
||||
tl = i - start; /* number of characters just skipped */
|
||||
RESIZE_MALLOCED_BUFFER (line, j, (tl + 1), line_len, (tl + 50));
|
||||
strncpy (line + j, string + start, tl);
|
||||
line[j + tl] = '\0';
|
||||
|
||||
real_start = i;
|
||||
|
||||
command_word = command_word || (command_separator (string[i]));
|
||||
expand_this_token = (command_word || expand_next);
|
||||
expand_next = 0;
|
||||
|
||||
/* Read the next token, and copy it into TOKEN. */
|
||||
start = i;
|
||||
i = rd_token (string, start);
|
||||
|
||||
tl = i - start; /* token length */
|
||||
|
||||
/* If tl == 0, but we're not at the end of the string, then we have a
|
||||
single-character token, probably a delimiter */
|
||||
if (tl == 0 && string[i] != '\0')
|
||||
{
|
||||
tl = 1;
|
||||
i++; /* move past it */
|
||||
}
|
||||
|
||||
strncpy (token, string + start, tl);
|
||||
token [tl] = '\0';
|
||||
|
||||
/* If there is a backslash-escaped character quoted in TOKEN,
|
||||
then we don't do alias expansion. This should check for all
|
||||
other quoting characters, too. */
|
||||
if (mbschr (token, '\\'))
|
||||
expand_this_token = 0;
|
||||
|
||||
/* If we should be expanding here, if we are expanding all words, or if
|
||||
we are in a location in the string where an expansion is supposed to
|
||||
take place, see if this word has a substitution. If it does, then do
|
||||
the expansion. Note that we defer the alias value lookup until we
|
||||
are sure we are expanding this token. */
|
||||
|
||||
if ((token[0]) &&
|
||||
(expand_this_token || alias_expand_all) &&
|
||||
(alias = find_alias (token)))
|
||||
{
|
||||
char *v;
|
||||
int vlen, llen;
|
||||
|
||||
v = alias->value;
|
||||
vlen = strlen (v);
|
||||
llen = strlen (line);
|
||||
|
||||
/* +3 because we possibly add one more character below. */
|
||||
RESIZE_MALLOCED_BUFFER (line, llen, (vlen + 3), line_len, (vlen + 50));
|
||||
|
||||
strcpy (line + llen, v);
|
||||
|
||||
if ((expand_this_token && vlen && whitespace (v[vlen - 1])) ||
|
||||
alias_expand_all)
|
||||
expand_next = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int llen, tlen;
|
||||
|
||||
llen = strlen (line);
|
||||
tlen = i - real_start; /* tlen == strlen(token) */
|
||||
|
||||
RESIZE_MALLOCED_BUFFER (line, llen, (tlen + 1), line_len, (llen + tlen + 50));
|
||||
|
||||
strncpy (line + llen, string + real_start, tlen);
|
||||
line[llen + tlen] = '\0';
|
||||
}
|
||||
command_word = 0;
|
||||
}
|
||||
}
|
||||
#endif /* READLINE */
|
||||
#endif /* ALIAS */
|
||||
@@ -1,4 +1,4 @@
|
||||
/* evalstring.c - evaluate a string as one or more shell commands.
|
||||
/* evalstring.c - evaluate a string as one or more shell commands. */
|
||||
|
||||
/* Copyright (C) 1996-2010 Free Software Foundation, Inc.
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@ and printf(3), printf interprets:
|
||||
|
||||
%b expand backslash escape sequences in the corresponding argument
|
||||
%q quote the argument in a way that can be reused as shell input
|
||||
%(fmt)T output the date-time string resulting from using FMT as a format
|
||||
string for strftime(3)
|
||||
|
||||
Exit Status:
|
||||
Returns success unless an invalid option is given or a write or assignment
|
||||
|
||||
+4
-1
@@ -28,7 +28,10 @@ Evaluate conditional expression.
|
||||
Exits with a status of 0 (true) or 1 (false) depending on
|
||||
the evaluation of EXPR. Expressions may be unary or binary. Unary
|
||||
expressions are often used to examine the status of a file. There
|
||||
are string operators as well, and numeric comparison operators.
|
||||
are string operators and numeric comparison operators as well.
|
||||
|
||||
The behavior of test depends on the number of arguments. Read the
|
||||
bash manual page for the complete specification.
|
||||
|
||||
File operators:
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
This file is test.def, from which is created test.c.
|
||||
It implements the builtin "test" in Bash.
|
||||
|
||||
Copyright (C) 1987-2009 Free Software Foundation, Inc.
|
||||
Copyright (C) 1987-2010 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
|
||||
+20
-18
@@ -5,12 +5,12 @@
|
||||
.\" Case Western Reserve University
|
||||
.\" chet@po.cwru.edu
|
||||
.\"
|
||||
.\" Last Change: Mon Sep 6 22:07:38 EDT 2010
|
||||
.\" Last Change: Mon Dec 6 22:25:10 EST 2010
|
||||
.\"
|
||||
.\" bash_builtins, strip all but Built-Ins section
|
||||
.if \n(zZ=1 .ig zZ
|
||||
.if \n(zY=1 .ig zY
|
||||
.TH BASH 1 "2010 September 6" "GNU Bash-4.2"
|
||||
.TH BASH 1 "2010 December 6" "GNU Bash-4.2"
|
||||
.\"
|
||||
.\" There's some problem with having a `@'
|
||||
.\" in a tagged paragraph with the BSD man macros.
|
||||
@@ -476,7 +476,7 @@ A \fItoken\fP that performs a control function. It is one of the following
|
||||
symbols:
|
||||
.RS
|
||||
.PP
|
||||
.if t \fB\(bv\(bv & && ; ;; ( ) | |& <newline>\fP
|
||||
.if t \fB|| & && ; ;; ( ) | |& <newline>\fP
|
||||
.if n \fB|| & && ; ;; ( ) | |& <newline>\fP
|
||||
.RE
|
||||
.PD
|
||||
@@ -586,7 +586,7 @@ of the operators
|
||||
.BR & ,
|
||||
.BR && ,
|
||||
or
|
||||
.BR \(bv\(bv ,
|
||||
.BR || ,
|
||||
and optionally terminated by one of
|
||||
.BR ; ,
|
||||
.BR & ,
|
||||
@@ -596,7 +596,7 @@ or
|
||||
Of these list operators,
|
||||
.B &&
|
||||
and
|
||||
.B \(bv\(bv
|
||||
.B ||
|
||||
have equal precedence, followed by
|
||||
.B ;
|
||||
and
|
||||
@@ -617,7 +617,7 @@ command to terminate in turn. The return status is the
|
||||
exit status of the last command executed.
|
||||
.PP
|
||||
AND and OR lists are sequences of one of more pipelines separated by the
|
||||
\fB&&\fP and \fB\(bv\(bv\fP control operators, respectively.
|
||||
\fB&&\fP and \fB||\fP control operators, respectively.
|
||||
AND and OR lists are executed with left associativity.
|
||||
An AND list has the form
|
||||
.RS
|
||||
@@ -633,7 +633,7 @@ returns an exit status of zero.
|
||||
An OR list has the form
|
||||
.RS
|
||||
.PP
|
||||
\fIcommand1\fP \fB\(bv\(bv\fP \fIcommand2\fP
|
||||
\fIcommand1\fP \fB||\fP \fIcommand2\fP
|
||||
.PP
|
||||
.RE
|
||||
.PP
|
||||
@@ -763,8 +763,7 @@ and
|
||||
.I expression2
|
||||
are true.
|
||||
.TP
|
||||
.if t \fIexpression1\fP \fB\(bv\(bv\fP \fIexpression2\fP
|
||||
.if n \fIexpression1\fP \fB||\fP \fIexpression2\fP
|
||||
\fIexpression1\fP \fB||\fP \fIexpression2\fP
|
||||
True if either
|
||||
.I expression1
|
||||
or
|
||||
@@ -772,9 +771,7 @@ or
|
||||
is true.
|
||||
.PD
|
||||
.LP
|
||||
The \fB&&\fP and
|
||||
.if t \fB\(bv\(bv\fP
|
||||
.if n \fB||\fP
|
||||
The \fB&&\fP and \fB||\fP
|
||||
operators do not evaluate \fIexpression2\fP if the value of
|
||||
\fIexpression1\fP is sufficient to determine the return value of
|
||||
the entire conditional expression.
|
||||
@@ -5508,10 +5505,14 @@ as if the "!\fIn\fP" history expansion had been specified.
|
||||
.B
|
||||
yank\-last\-arg (M\-.\^, M\-_\^)
|
||||
Insert the last argument to the previous command (the last word of
|
||||
the previous history entry). With an argument,
|
||||
behave exactly like \fByank\-nth\-arg\fP.
|
||||
the previous history entry).
|
||||
With a numeric argument, behave exactly like \fByank\-nth\-arg\fP.
|
||||
Successive calls to \fByank\-last\-arg\fP move back through the history
|
||||
list, inserting the last argument of each line in turn.
|
||||
list, inserting the last word (or the word specified by the argument to
|
||||
the first call) of each line in turn.
|
||||
Any numeric argument supplied to these successive calls determines
|
||||
the direction to move through the history. A negative argument switches
|
||||
the direction through the history (back or forward).
|
||||
The history expansion facilities are used to extract the last argument,
|
||||
as if the "!$" history expansion had been specified.
|
||||
.TP
|
||||
@@ -8476,8 +8477,8 @@ or
|
||||
reserved words, part of any command executed in a
|
||||
.B &&
|
||||
or
|
||||
.B \(bv\(bv
|
||||
list except the command following the final \fB&&\fP or \fB\(bv\(bv\fP,
|
||||
.B ||
|
||||
list except the command following the final \fB&&\fP or \fB||\fP,
|
||||
any command in a pipeline but the last,
|
||||
or if the command's return value is
|
||||
being inverted with
|
||||
@@ -9262,6 +9263,7 @@ If the first argument is not a valid unary conditional operator, the expression
|
||||
is false.
|
||||
.TP
|
||||
3 arguments
|
||||
The following conditions are applied in the order listed.
|
||||
If the second argument is one of the binary conditional operators listed above
|
||||
under
|
||||
.SM
|
||||
@@ -9394,7 +9396,7 @@ part of the test in an
|
||||
statement, part of a command executed in a
|
||||
.B &&
|
||||
or
|
||||
.B \(bv\(bv
|
||||
.B ||
|
||||
list, or if the command's return value is
|
||||
being inverted via
|
||||
.BR ! .
|
||||
|
||||
+10
-5
@@ -5508,10 +5508,14 @@ as if the "!\fIn\fP" history expansion had been specified.
|
||||
.B
|
||||
yank\-last\-arg (M\-.\^, M\-_\^)
|
||||
Insert the last argument to the previous command (the last word of
|
||||
the previous history entry). With an argument,
|
||||
behave exactly like \fByank\-nth\-arg\fP.
|
||||
the previous history entry).
|
||||
With a numeric argument, behave exactly like \fByank\-nth\-arg\fP.
|
||||
Successive calls to \fByank\-last\-arg\fP move back through the history
|
||||
list, inserting the last argument of each line in turn.
|
||||
list, inserting the last word (or the word specified by the argument to
|
||||
the first call) of each line in turn.
|
||||
Any numeric argument supplied to these successive calls determines
|
||||
the direction to move through the history. A negative argument switches
|
||||
the direction through the history (back or forward).
|
||||
The history expansion facilities are used to extract the last argument,
|
||||
as if the "!$" history expansion had been specified.
|
||||
.TP
|
||||
@@ -9210,6 +9214,7 @@ an argument of \fB\-\-\fP as signifying the end of options.
|
||||
Expressions may be combined using the following operators, listed
|
||||
in decreasing order of precedence.
|
||||
The evaluation depends on the number of arguments; see below.
|
||||
Operator precedence is used when there are five or more arguments.
|
||||
.RS
|
||||
.PD 0
|
||||
.TP
|
||||
@@ -9366,8 +9371,8 @@ is
|
||||
.BR RETURN ,
|
||||
the command
|
||||
.I arg
|
||||
is executed each time a shell function or a script executed with the
|
||||
\fB.\fP or \fBsource\fP builtins finishes executing.
|
||||
is executed each time a shell function or a script executed with
|
||||
the \fB.\fP or \fBsource\fP builtins finishes executing.
|
||||
.if t .sp 0.5
|
||||
.if n .sp 1
|
||||
If a
|
||||
|
||||
@@ -3239,6 +3239,7 @@ If the first argument is not a valid unary operator, the expression is
|
||||
false.
|
||||
|
||||
@item 3 arguments
|
||||
The following conditions are applied in the order listed.
|
||||
If the second argument is one of the binary conditional
|
||||
operators (@pxref{Bash Conditional Expressions}), the
|
||||
result of the expression is the result of the binary test using the
|
||||
|
||||
+7
-13
@@ -1717,7 +1717,7 @@ Bash uses the value of the variable formed from the rest of
|
||||
expanded and that value is used in the rest of the substitution, rather
|
||||
than the value of @var{parameter} itself.
|
||||
This is known as @code{indirect expansion}.
|
||||
The exceptions to this are the expansions of $@{!@var{prefix}@*}
|
||||
The exceptions to this are the expansions of $@{!@var{prefix}@*@}
|
||||
and $@{!@var{name}[@@]@}
|
||||
described below.
|
||||
The exclamation point must immediately follow the left brace in order to
|
||||
@@ -3202,6 +3202,7 @@ be a @code{]}.
|
||||
Expressions may be combined using the following operators, listed in
|
||||
decreasing order of precedence.
|
||||
The evaluation depends on the number of arguments; see below.
|
||||
Operator precedence is used when there are five or more arguments.
|
||||
|
||||
@table @code
|
||||
@item ! @var{expr}
|
||||
@@ -6694,14 +6695,6 @@ the @sc{posix} standard, and include things like passing incorrect options,
|
||||
redirection errors, variable assignment errors for assignments preceding
|
||||
the command name, and so on.
|
||||
|
||||
@item
|
||||
If @env{CDPATH} is set, the @code{cd} builtin will not implicitly
|
||||
append the current directory to it. This means that @code{cd} will
|
||||
fail if no valid directory name can be constructed from
|
||||
any of the entries in @env{$CDPATH}, even if the a directory with
|
||||
the same name as the name given as an argument to @code{cd} exists
|
||||
in the current directory.
|
||||
|
||||
@item
|
||||
A non-interactive shell exits with an error status if a variable
|
||||
assignment error occurs when no command name follows the assignment
|
||||
@@ -6709,6 +6702,11 @@ statements.
|
||||
A variable assignment error occurs, for example, when trying to assign
|
||||
a value to a readonly variable.
|
||||
|
||||
@item
|
||||
A non-interactive shell exists with an error status if a variable
|
||||
assignment error occurs in an assignment statement preceding a special
|
||||
builtin, but not with any other simple command.
|
||||
|
||||
@item
|
||||
A non-interactive shell exits with an error status if the iteration
|
||||
variable in a @code{for} statement or the selection variable in a
|
||||
@@ -6774,10 +6772,6 @@ constructed from @code{$PWD} and the directory name supplied as an argument
|
||||
does not refer to an existing directory, @code{cd} will fail instead of
|
||||
falling back to @var{physical} mode.
|
||||
|
||||
@item
|
||||
When the @code{pwd} builtin is supplied the @option{-P} option, it resets
|
||||
@code{$PWD} to a pathname containing no symlinks.
|
||||
|
||||
@item
|
||||
The @code{pwd} builtin verifies that the value it prints is the same as the
|
||||
current directory, even if it is not asked to check the file system with the
|
||||
|
||||
@@ -303,6 +303,10 @@ extern int sh_regmatch __P((const char *, const char *, int));
|
||||
#define SHMAT_SUBEXP 0x001 /* save subexpressions in SH_REMATCH */
|
||||
#define SHMAT_PWARN 0x002 /* print a warning message on invalid regexp */
|
||||
|
||||
/* declarations for functions defined in lib/sh/shmbchar.c */
|
||||
extern size_t mbstrlen __P((const char *));
|
||||
extern char *mbsmbchar __P((const char *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/shquote.c */
|
||||
extern char *sh_single_quote __P((const char *));
|
||||
extern char *sh_double_quote __P((const char *));
|
||||
|
||||
+5
-2
@@ -303,9 +303,12 @@ extern int sh_regmatch __P((const char *, const char *, int));
|
||||
#define SHMAT_SUBEXP 0x001 /* save subexpressions in SH_REMATCH */
|
||||
#define SHMAT_PWARN 0x002 /* print a warning message on invalid regexp */
|
||||
|
||||
/* declarations for functions defined in lib/sh/shmbchar.c */
|
||||
extern size_t mbstrlen __P((const char *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/shquote.c */
|
||||
extern char *sh_single_quote __P((char *));
|
||||
extern char *sh_double_quote __P((char *));
|
||||
extern char *sh_single_quote __P((const char *));
|
||||
extern char *sh_double_quote __P((const char *));
|
||||
extern char *sh_mkdoublequoted __P((const char *, int, int));
|
||||
extern char *sh_un_double_quote __P((char *));
|
||||
extern char *sh_backslash_quote __P((char *));
|
||||
|
||||
@@ -216,8 +216,8 @@ typedef void sh_resetsig_func_t __P((int)); /* sh_vintfunc_t */
|
||||
|
||||
typedef int sh_ignore_func_t __P((const char *)); /* sh_icpfunc_t */
|
||||
|
||||
typedef int sh_assign_func_t __P((const char *)); /* sh_icpfunc_t */
|
||||
typedef int sh_wassign_func_t __P((WORD_DESC *));
|
||||
typedef int sh_assign_func_t __P((const char *));
|
||||
typedef int sh_wassign_func_t __P((WORD_DESC *, int));
|
||||
|
||||
typedef int sh_builtin_func_t __P((WORD_LIST *)); /* sh_wlist_func_t */
|
||||
|
||||
|
||||
+325
@@ -0,0 +1,325 @@
|
||||
/* general.h -- defines that everybody likes to use. */
|
||||
|
||||
/* Copyright (C) 1993-2009 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_GENERAL_H_)
|
||||
#define _GENERAL_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include "chartypes.h"
|
||||
|
||||
#if defined (HAVE_SYS_RESOURCE_H) && defined (RLIMTYPE)
|
||||
# if defined (HAVE_SYS_TIME_H)
|
||||
# include <sys/time.h>
|
||||
# endif
|
||||
# include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRING_H */
|
||||
|
||||
#if defined (HAVE_LIMITS_H)
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* NULL pointer type. */
|
||||
#if !defined (NULL)
|
||||
# if defined (__STDC__)
|
||||
# define NULL ((void *) 0)
|
||||
# else
|
||||
# define NULL 0x0
|
||||
# endif /* !__STDC__ */
|
||||
#endif /* !NULL */
|
||||
|
||||
/* Hardly used anymore */
|
||||
#define pointer_to_int(x) (int)((char *)x - (char *)0)
|
||||
|
||||
#if defined (alpha) && defined (__GNUC__) && !defined (strchr) && !defined (__STDC__)
|
||||
extern char *strchr (), *strrchr ();
|
||||
#endif
|
||||
|
||||
#if !defined (strcpy) && (defined (HAVE_DECL_STRCPY) && !HAVE_DECL_STRCPY)
|
||||
extern char *strcpy __P((char *, const char *));
|
||||
#endif
|
||||
|
||||
#if !defined (savestring)
|
||||
# define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x))
|
||||
#endif
|
||||
|
||||
#ifndef member
|
||||
# define member(c, s) ((c) ? ((char *)mbschr ((s), (c)) != (char *)NULL) : 0)
|
||||
#endif
|
||||
|
||||
#ifndef whitespace
|
||||
#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
|
||||
#endif
|
||||
|
||||
#ifndef CHAR_MAX
|
||||
# ifdef __CHAR_UNSIGNED__
|
||||
# define CHAR_MAX 0xff
|
||||
# else
|
||||
# define CHAR_MAX 0x7f
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef CHAR_BIT
|
||||
# define CHAR_BIT 8
|
||||
#endif
|
||||
|
||||
/* Nonzero if the integer type T is signed. */
|
||||
#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
|
||||
|
||||
/* Bound on length of the string representing an integer value of type T.
|
||||
Subtract one for the sign bit if T is signed;
|
||||
302 / 1000 is log10 (2) rounded up;
|
||||
add one for integer division truncation;
|
||||
add one more for a minus sign if t is signed. */
|
||||
#define INT_STRLEN_BOUND(t) \
|
||||
((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 \
|
||||
+ 1 + TYPE_SIGNED (t))
|
||||
|
||||
|
||||
/* Define exactly what a legal shell identifier consists of. */
|
||||
#define legal_variable_starter(c) (ISALPHA(c) || (c == '_'))
|
||||
#define legal_variable_char(c) (ISALNUM(c) || c == '_')
|
||||
|
||||
/* Definitions used in subst.c and by the `read' builtin for field
|
||||
splitting. */
|
||||
#define spctabnl(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
|
||||
|
||||
/* All structs which contain a `next' field should have that field
|
||||
as the first field in the struct. This means that functions
|
||||
can be written to handle the general case for linked lists. */
|
||||
typedef struct g_list {
|
||||
struct g_list *next;
|
||||
} GENERIC_LIST;
|
||||
|
||||
/* Here is a generic structure for associating character strings
|
||||
with integers. It is used in the parser for shell tokenization. */
|
||||
typedef struct {
|
||||
char *word;
|
||||
int token;
|
||||
} STRING_INT_ALIST;
|
||||
|
||||
/* A macro to avoid making an uneccessary function call. */
|
||||
#define REVERSE_LIST(list, type) \
|
||||
((list && list->next) ? (type)list_reverse ((GENERIC_LIST *)list) \
|
||||
: (type)(list))
|
||||
|
||||
#if __GNUC__ > 1
|
||||
# define FASTCOPY(s, d, n) __builtin_memcpy ((d), (s), (n))
|
||||
#else /* !__GNUC__ */
|
||||
# if !defined (HAVE_BCOPY)
|
||||
# if !defined (HAVE_MEMMOVE)
|
||||
# define FASTCOPY(s, d, n) memcpy ((d), (s), (n))
|
||||
# else
|
||||
# define FASTCOPY(s, d, n) memmove ((d), (s), (n))
|
||||
# endif /* !HAVE_MEMMOVE */
|
||||
# else /* HAVE_BCOPY */
|
||||
# define FASTCOPY(s, d, n) bcopy ((s), (d), (n))
|
||||
# endif /* HAVE_BCOPY */
|
||||
#endif /* !__GNUC__ */
|
||||
|
||||
/* String comparisons that possibly save a function call each. */
|
||||
#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0)
|
||||
#define STREQN(a, b, n) ((n == 0) ? (1) \
|
||||
: ((a)[0] == (b)[0] && strncmp(a, b, n) == 0))
|
||||
|
||||
/* More convenience definitions that possibly save system or libc calls. */
|
||||
#define STRLEN(s) (((s) && (s)[0]) ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0)
|
||||
#define FREE(s) do { if (s) free (s); } while (0)
|
||||
#define MEMBER(c, s) (((c) && c == (s)[0] && !(s)[1]) || (member(c, s)))
|
||||
|
||||
/* A fairly hairy macro to check whether an allocated string has more room,
|
||||
and to resize it using xrealloc if it does not.
|
||||
STR is the string (char *)
|
||||
CIND is the current index into the string (int)
|
||||
ROOM is the amount of additional room we need in the string (int)
|
||||
CSIZE is the currently-allocated size of STR (int)
|
||||
SINCR is how much to increment CSIZE before calling xrealloc (int) */
|
||||
|
||||
#define RESIZE_MALLOCED_BUFFER(str, cind, room, csize, sincr) \
|
||||
do { \
|
||||
if ((cind) + (room) >= csize) \
|
||||
{ \
|
||||
while ((cind) + (room) >= csize) \
|
||||
csize += (sincr); \
|
||||
str = xrealloc (str, csize); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Function pointers can be declared as (Function *)foo. */
|
||||
#if !defined (_FUNCTION_DEF)
|
||||
# define _FUNCTION_DEF
|
||||
typedef int Function ();
|
||||
typedef void VFunction ();
|
||||
typedef char *CPFunction (); /* no longer used */
|
||||
typedef char **CPPFunction (); /* no longer used */
|
||||
#endif /* _FUNCTION_DEF */
|
||||
|
||||
#ifndef SH_FUNCTION_TYPEDEF
|
||||
# define SH_FUNCTION_TYPEDEF
|
||||
|
||||
/* Shell function typedefs with prototypes */
|
||||
/* `Generic' function pointer typedefs */
|
||||
|
||||
typedef int sh_intfunc_t __P((int));
|
||||
typedef int sh_ivoidfunc_t __P((void));
|
||||
typedef int sh_icpfunc_t __P((char *));
|
||||
typedef int sh_icppfunc_t __P((char **));
|
||||
typedef int sh_iptrfunc_t __P((PTR_T));
|
||||
|
||||
typedef void sh_voidfunc_t __P((void));
|
||||
typedef void sh_vintfunc_t __P((int));
|
||||
typedef void sh_vcpfunc_t __P((char *));
|
||||
typedef void sh_vcppfunc_t __P((char **));
|
||||
typedef void sh_vptrfunc_t __P((PTR_T));
|
||||
|
||||
typedef int sh_wdesc_func_t __P((WORD_DESC *));
|
||||
typedef int sh_wlist_func_t __P((WORD_LIST *));
|
||||
|
||||
typedef int sh_glist_func_t __P((GENERIC_LIST *));
|
||||
|
||||
typedef char *sh_string_func_t __P((char *)); /* like savestring, et al. */
|
||||
|
||||
typedef int sh_msg_func_t __P((const char *, ...)); /* printf(3)-like */
|
||||
typedef void sh_vmsg_func_t __P((const char *, ...)); /* printf(3)-like */
|
||||
|
||||
/* Specific function pointer typedefs. Most of these could be done
|
||||
with #defines. */
|
||||
typedef void sh_sv_func_t __P((char *)); /* sh_vcpfunc_t */
|
||||
typedef void sh_free_func_t __P((PTR_T)); /* sh_vptrfunc_t */
|
||||
typedef void sh_resetsig_func_t __P((int)); /* sh_vintfunc_t */
|
||||
|
||||
typedef int sh_ignore_func_t __P((const char *)); /* sh_icpfunc_t */
|
||||
|
||||
typedef int sh_assign_func_t __P((const char *, int));
|
||||
typedef int sh_wassign_func_t __P((WORD_DESC *));
|
||||
|
||||
typedef int sh_builtin_func_t __P((WORD_LIST *)); /* sh_wlist_func_t */
|
||||
|
||||
#endif /* SH_FUNCTION_TYPEDEF */
|
||||
|
||||
#define NOW ((time_t) time ((time_t *) 0))
|
||||
|
||||
/* Some defines for calling file status functions. */
|
||||
#define FS_EXISTS 0x1
|
||||
#define FS_EXECABLE 0x2
|
||||
#define FS_EXEC_PREFERRED 0x4
|
||||
#define FS_EXEC_ONLY 0x8
|
||||
#define FS_DIRECTORY 0x10
|
||||
#define FS_NODIRS 0x20
|
||||
#define FS_READABLE 0x40
|
||||
|
||||
/* Default maximum for move_to_high_fd */
|
||||
#define HIGH_FD_MAX 256
|
||||
|
||||
/* The type of function passed as the fourth argument to qsort(3). */
|
||||
#ifdef __STDC__
|
||||
typedef int QSFUNC (const void *, const void *);
|
||||
#else
|
||||
typedef int QSFUNC ();
|
||||
#endif
|
||||
|
||||
/* Some useful definitions for Unix pathnames. Argument convention:
|
||||
x == string, c == character */
|
||||
|
||||
#if !defined (__CYGWIN__)
|
||||
# define ABSPATH(x) ((x)[0] == '/')
|
||||
# define RELPATH(x) ((x)[0] != '/')
|
||||
#else /* __CYGWIN__ */
|
||||
# define ABSPATH(x) (((x)[0] && ISALPHA((unsigned char)(x)[0]) && (x)[1] == ':') || ISDIRSEP((x)[0]))
|
||||
# define RELPATH(x) (ABSPATH(x) == 0)
|
||||
#endif /* __CYGWIN__ */
|
||||
|
||||
#define ROOTEDPATH(x) (ABSPATH(x))
|
||||
|
||||
#define DIRSEP '/'
|
||||
#if !defined (__CYGWIN__)
|
||||
# define ISDIRSEP(c) ((c) == '/')
|
||||
#else
|
||||
# define ISDIRSEP(c) ((c) == '/' || (c) == '\\')
|
||||
#endif /* __CYGWIN__ */
|
||||
#define PATHSEP(c) (ISDIRSEP(c) || (c) == 0)
|
||||
|
||||
#if 0
|
||||
/* Declarations for functions defined in xmalloc.c */
|
||||
extern PTR_T xmalloc __P((size_t));
|
||||
extern PTR_T xrealloc __P((void *, size_t));
|
||||
extern void xfree __P((void *));
|
||||
#endif
|
||||
|
||||
/* Declarations for functions defined in general.c */
|
||||
extern void posix_initialize __P((int));
|
||||
|
||||
#if defined (RLIMTYPE)
|
||||
extern RLIMTYPE string_to_rlimtype __P((char *));
|
||||
extern void print_rlimtype __P((RLIMTYPE, int));
|
||||
#endif
|
||||
|
||||
extern int all_digits __P((char *));
|
||||
extern int legal_number __P((const char *, intmax_t *));
|
||||
extern int legal_identifier __P((char *));
|
||||
extern int check_identifier __P((WORD_DESC *, int));
|
||||
extern int legal_alias_name __P((char *, int));
|
||||
extern int assignment __P((const char *, int));
|
||||
|
||||
extern int sh_unset_nodelay_mode __P((int));
|
||||
extern int sh_validfd __P((int));
|
||||
extern void check_dev_tty __P((void));
|
||||
extern int move_to_high_fd __P((int, int, int));
|
||||
extern int check_binary_file __P((char *, int));
|
||||
|
||||
#ifdef _POSIXSTAT_H_
|
||||
extern int same_file __P((char *, char *, struct stat *, struct stat *));
|
||||
#endif
|
||||
|
||||
extern int sh_openpipe __P((int *));
|
||||
extern int sh_closepipe __P((int *));
|
||||
|
||||
extern int file_exists __P((char *));
|
||||
extern int file_isdir __P((char *));
|
||||
extern int file_iswdir __P((char *));
|
||||
extern int absolute_pathname __P((const char *));
|
||||
extern int absolute_program __P((const char *));
|
||||
|
||||
extern char *make_absolute __P((char *, char *));
|
||||
extern char *base_pathname __P((char *));
|
||||
extern char *full_pathname __P((char *));
|
||||
extern char *polite_directory_format __P((char *));
|
||||
extern char *trim_pathname __P((char *, int));
|
||||
|
||||
extern char *extract_colon_unit __P((char *, int *));
|
||||
|
||||
extern void tilde_initialize __P((void));
|
||||
extern char *bash_tilde_find_word __P((const char *, int, int *));
|
||||
extern char *bash_tilde_expand __P((const char *, int));
|
||||
|
||||
extern int group_member __P((gid_t));
|
||||
extern char **get_group_list __P((int *));
|
||||
extern int *get_group_array __P((int *));
|
||||
|
||||
#endif /* _GENERAL_H_ */
|
||||
@@ -0,0 +1,350 @@
|
||||
/* Multibyte character data type.
|
||||
Copyright (C) 2001, 2005-2007, 2009-2010 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Bruno Haible <bruno@clisp.org>. */
|
||||
|
||||
/* A multibyte character is a short subsequence of a char* string,
|
||||
representing a single wide character.
|
||||
|
||||
We use multibyte characters instead of wide characters because of
|
||||
the following goals:
|
||||
1) correct multibyte handling, i.e. operate according to the LC_CTYPE
|
||||
locale,
|
||||
2) ease of maintenance, i.e. the maintainer needs not know all details
|
||||
of the ISO C 99 standard,
|
||||
3) don't fail grossly if the input is not in the encoding set by the
|
||||
locale, because often different encodings are in use in the same
|
||||
countries (ISO-8859-1/UTF-8, EUC-JP/Shift_JIS, ...),
|
||||
4) fast in the case of ASCII characters,
|
||||
5) portability, i.e. don't make unportable assumptions about wchar_t.
|
||||
|
||||
Multibyte characters are only accessed through the mb* macros.
|
||||
|
||||
mb_ptr (mbc)
|
||||
return a pointer to the beginning of the multibyte sequence.
|
||||
|
||||
mb_len (mbc)
|
||||
returns the number of bytes occupied by the multibyte sequence.
|
||||
Always > 0.
|
||||
|
||||
mb_iseq (mbc, sc)
|
||||
returns true if mbc is the standard ASCII character sc.
|
||||
|
||||
mb_isnul (mbc)
|
||||
returns true if mbc is the nul character.
|
||||
|
||||
mb_cmp (mbc1, mbc2)
|
||||
returns a positive, zero, or negative value depending on whether mbc1
|
||||
sorts after, same or before mbc2.
|
||||
|
||||
mb_casecmp (mbc1, mbc2)
|
||||
returns a positive, zero, or negative value depending on whether mbc1
|
||||
sorts after, same or before mbc2, modulo upper/lowercase conversion.
|
||||
|
||||
mb_equal (mbc1, mbc2)
|
||||
returns true if mbc1 and mbc2 are equal.
|
||||
|
||||
mb_caseequal (mbc1, mbc2)
|
||||
returns true if mbc1 and mbc2 are equal modulo upper/lowercase conversion.
|
||||
|
||||
mb_isalnum (mbc)
|
||||
returns true if mbc is alphanumeric.
|
||||
|
||||
mb_isalpha (mbc)
|
||||
returns true if mbc is alphabetic.
|
||||
|
||||
mb_isascii(mbc)
|
||||
returns true if mbc is plain ASCII.
|
||||
|
||||
mb_isblank (mbc)
|
||||
returns true if mbc is a blank.
|
||||
|
||||
mb_iscntrl (mbc)
|
||||
returns true if mbc is a control character.
|
||||
|
||||
mb_isdigit (mbc)
|
||||
returns true if mbc is a decimal digit.
|
||||
|
||||
mb_isgraph (mbc)
|
||||
returns true if mbc is a graphic character.
|
||||
|
||||
mb_islower (mbc)
|
||||
returns true if mbc is lowercase.
|
||||
|
||||
mb_isprint (mbc)
|
||||
returns true if mbc is a printable character.
|
||||
|
||||
mb_ispunct (mbc)
|
||||
returns true if mbc is a punctuation character.
|
||||
|
||||
mb_isspace (mbc)
|
||||
returns true if mbc is a space character.
|
||||
|
||||
mb_isupper (mbc)
|
||||
returns true if mbc is uppercase.
|
||||
|
||||
mb_isxdigit (mbc)
|
||||
returns true if mbc is a hexadecimal digit.
|
||||
|
||||
mb_width (mbc)
|
||||
returns the number of columns on the output device occupied by mbc.
|
||||
Always >= 0.
|
||||
|
||||
mb_putc (mbc, stream)
|
||||
outputs mbc on stream, a byte oriented FILE stream opened for output.
|
||||
|
||||
mb_setascii (&mbc, sc)
|
||||
assigns the standard ASCII character sc to mbc.
|
||||
|
||||
mb_copy (&destmbc, &srcmbc)
|
||||
copies srcmbc to destmbc.
|
||||
|
||||
Here are the function prototypes of the macros.
|
||||
|
||||
typedef int bool;
|
||||
extern const char * mb_ptr (const mbchar_t mbc);
|
||||
extern size_t mb_len (const mbchar_t mbc);
|
||||
extern bool mb_iseq (const mbchar_t mbc, char sc);
|
||||
extern bool mb_isnul (const mbchar_t mbc);
|
||||
extern int mb_cmp (const mbchar_t mbc1, const mbchar_t mbc2);
|
||||
extern int mb_casecmp (const mbchar_t mbc1, const mbchar_t mbc2);
|
||||
extern bool mb_equal (const mbchar_t mbc1, const mbchar_t mbc2);
|
||||
extern bool mb_caseequal (const mbchar_t mbc1, const mbchar_t mbc2);
|
||||
extern bool mb_isalnum (const mbchar_t mbc);
|
||||
extern bool mb_isalpha (const mbchar_t mbc);
|
||||
extern bool mb_isascii (const mbchar_t mbc);
|
||||
extern bool mb_isblank (const mbchar_t mbc);
|
||||
extern bool mb_iscntrl (const mbchar_t mbc);
|
||||
extern bool mb_isdigit (const mbchar_t mbc);
|
||||
extern bool mb_isgraph (const mbchar_t mbc);
|
||||
extern bool mb_islower (const mbchar_t mbc);
|
||||
extern bool mb_isprint (const mbchar_t mbc);
|
||||
extern bool mb_ispunct (const mbchar_t mbc);
|
||||
extern bool mb_isspace (const mbchar_t mbc);
|
||||
extern bool mb_isupper (const mbchar_t mbc);
|
||||
extern bool mb_isxdigit (const mbchar_t mbc);
|
||||
extern int mb_width (const mbchar_t mbc);
|
||||
extern void mb_putc (const mbchar_t mbc, FILE *stream);
|
||||
extern void mb_setascii (mbchar_t *new, char sc);
|
||||
extern void mb_copy (mbchar_t *new, const mbchar_t *old);
|
||||
*/
|
||||
|
||||
#ifndef _SHMBCHAR_H
|
||||
#define _SHMBCHAR_H 1
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
|
||||
<wchar.h>.
|
||||
BSD/OS 4.1 has a bug: <stdio.h> and <time.h> must be included before
|
||||
<wchar.h>. */
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
|
||||
#define MBCHAR_BUF_SIZE 24
|
||||
|
||||
struct mbchar
|
||||
{
|
||||
const char *ptr; /* pointer to current character */
|
||||
size_t bytes; /* number of bytes of current character, > 0 */
|
||||
int wc_valid; /* true if wc is a valid wide character */
|
||||
wchar_t wc; /* if wc_valid: the current character */
|
||||
char buf[MBCHAR_BUF_SIZE]; /* room for the bytes, used for file input only */
|
||||
};
|
||||
|
||||
/* EOF (not a real character) is represented with bytes = 0 and
|
||||
wc_valid = false. */
|
||||
|
||||
typedef struct mbchar mbchar_t;
|
||||
|
||||
/* Access the current character. */
|
||||
#define mb_ptr(mbc) ((mbc).ptr)
|
||||
#define mb_len(mbc) ((mbc).bytes)
|
||||
|
||||
/* Comparison of characters. */
|
||||
#define mb_iseq(mbc, sc) ((mbc).wc_valid && (mbc).wc == (sc))
|
||||
#define mb_isnul(mbc) ((mbc).wc_valid && (mbc).wc == 0)
|
||||
#define mb_cmp(mbc1, mbc2) \
|
||||
((mbc1).wc_valid \
|
||||
? ((mbc2).wc_valid \
|
||||
? (int) (mbc1).wc - (int) (mbc2).wc \
|
||||
: -1) \
|
||||
: ((mbc2).wc_valid \
|
||||
? 1 \
|
||||
: (mbc1).bytes == (mbc2).bytes \
|
||||
? memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) \
|
||||
: (mbc1).bytes < (mbc2).bytes \
|
||||
? (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) > 0 ? 1 : -1) \
|
||||
: (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc2).bytes) >= 0 ? 1 : -1)))
|
||||
#define mb_casecmp(mbc1, mbc2) \
|
||||
((mbc1).wc_valid \
|
||||
? ((mbc2).wc_valid \
|
||||
? (int) towlower ((mbc1).wc) - (int) towlower ((mbc2).wc) \
|
||||
: -1) \
|
||||
: ((mbc2).wc_valid \
|
||||
? 1 \
|
||||
: (mbc1).bytes == (mbc2).bytes \
|
||||
? memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) \
|
||||
: (mbc1).bytes < (mbc2).bytes \
|
||||
? (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) > 0 ? 1 : -1) \
|
||||
: (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc2).bytes) >= 0 ? 1 : -1)))
|
||||
#define mb_equal(mbc1, mbc2) \
|
||||
((mbc1).wc_valid && (mbc2).wc_valid \
|
||||
? (mbc1).wc == (mbc2).wc \
|
||||
: (mbc1).bytes == (mbc2).bytes \
|
||||
&& memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) == 0)
|
||||
#define mb_caseequal(mbc1, mbc2) \
|
||||
((mbc1).wc_valid && (mbc2).wc_valid \
|
||||
? towlower ((mbc1).wc) == towlower ((mbc2).wc) \
|
||||
: (mbc1).bytes == (mbc2).bytes \
|
||||
&& memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) == 0)
|
||||
|
||||
/* <ctype.h>, <wctype.h> classification. */
|
||||
#define mb_isascii(mbc) \
|
||||
((mbc).wc_valid && (mbc).wc >= 0 && (mbc).wc <= 127)
|
||||
#define mb_isalnum(mbc) ((mbc).wc_valid && iswalnum ((mbc).wc))
|
||||
#define mb_isalpha(mbc) ((mbc).wc_valid && iswalpha ((mbc).wc))
|
||||
#define mb_isblank(mbc) ((mbc).wc_valid && iswblank ((mbc).wc))
|
||||
#define mb_iscntrl(mbc) ((mbc).wc_valid && iswcntrl ((mbc).wc))
|
||||
#define mb_isdigit(mbc) ((mbc).wc_valid && iswdigit ((mbc).wc))
|
||||
#define mb_isgraph(mbc) ((mbc).wc_valid && iswgraph ((mbc).wc))
|
||||
#define mb_islower(mbc) ((mbc).wc_valid && iswlower ((mbc).wc))
|
||||
#define mb_isprint(mbc) ((mbc).wc_valid && iswprint ((mbc).wc))
|
||||
#define mb_ispunct(mbc) ((mbc).wc_valid && iswpunct ((mbc).wc))
|
||||
#define mb_isspace(mbc) ((mbc).wc_valid && iswspace ((mbc).wc))
|
||||
#define mb_isupper(mbc) ((mbc).wc_valid && iswupper ((mbc).wc))
|
||||
#define mb_isxdigit(mbc) ((mbc).wc_valid && iswxdigit ((mbc).wc))
|
||||
|
||||
/* Extra <wchar.h> function. */
|
||||
|
||||
/* Unprintable characters appear as a small box of width 1. */
|
||||
#define MB_UNPRINTABLE_WIDTH 1
|
||||
|
||||
static inline int
|
||||
mb_width_aux (wint_t wc)
|
||||
{
|
||||
int w = wcwidth (wc);
|
||||
/* For unprintable characters, arbitrarily return 0 for control characters
|
||||
and MB_UNPRINTABLE_WIDTH otherwise. */
|
||||
return (w >= 0 ? w : iswcntrl (wc) ? 0 : MB_UNPRINTABLE_WIDTH);
|
||||
}
|
||||
|
||||
#define mb_width(mbc) \
|
||||
((mbc).wc_valid ? mb_width_aux ((mbc).wc) : MB_UNPRINTABLE_WIDTH)
|
||||
|
||||
/* Output. */
|
||||
#define mb_putc(mbc, stream) fwrite ((mbc).ptr, 1, (mbc).bytes, (stream))
|
||||
|
||||
/* Assignment. */
|
||||
#define mb_setascii(mbc, sc) \
|
||||
((mbc)->ptr = (mbc)->buf, (mbc)->bytes = 1, (mbc)->wc_valid = 1, \
|
||||
(mbc)->wc = (mbc)->buf[0] = (sc))
|
||||
|
||||
/* Copying a character. */
|
||||
static inline void
|
||||
mb_copy (mbchar_t *new_mbc, const mbchar_t *old_mbc)
|
||||
{
|
||||
if (old_mbc->ptr == &old_mbc->buf[0])
|
||||
{
|
||||
memcpy (&new_mbc->buf[0], &old_mbc->buf[0], old_mbc->bytes);
|
||||
new_mbc->ptr = &new_mbc->buf[0];
|
||||
}
|
||||
else
|
||||
new_mbc->ptr = old_mbc->ptr;
|
||||
new_mbc->bytes = old_mbc->bytes;
|
||||
if ((new_mbc->wc_valid = old_mbc->wc_valid))
|
||||
new_mbc->wc = old_mbc->wc;
|
||||
}
|
||||
|
||||
|
||||
/* is_basic(c) tests whether the single-byte character c is in the
|
||||
ISO C "basic character set".
|
||||
This is a convenience function, and is in this file only to share code
|
||||
between mbiter_multi.h and mbfile_multi.h. */
|
||||
#if (' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
||||
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
|
||||
&& (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
|
||||
&& ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
|
||||
&& ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
|
||||
&& ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
|
||||
&& ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
|
||||
&& ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
|
||||
&& ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
|
||||
&& ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
|
||||
&& ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
|
||||
&& ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
|
||||
&& ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
|
||||
&& ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
|
||||
&& ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
|
||||
&& ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
|
||||
&& ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
|
||||
&& ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
|
||||
&& ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
|
||||
&& ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
|
||||
&& ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
|
||||
&& ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
|
||||
&& ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)
|
||||
/* The character set is ISO-646, not EBCDIC. */
|
||||
# define IS_BASIC_ASCII 1
|
||||
|
||||
extern const unsigned int is_basic_table[];
|
||||
|
||||
static inline int
|
||||
is_basic (char c)
|
||||
{
|
||||
return (is_basic_table [(unsigned char) c >> 5] >> ((unsigned char) c & 31))
|
||||
& 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int
|
||||
is_basic (char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '\t': case '\v': case '\f':
|
||||
case ' ': case '!': case '"': case '#': case '%':
|
||||
case '&': case '\'': case '(': case ')': case '*':
|
||||
case '+': case ',': case '-': case '.': case '/':
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
case ':': case ';': case '<': case '=': case '>':
|
||||
case '?':
|
||||
case 'A': case 'B': case 'C': case 'D': case 'E':
|
||||
case 'F': case 'G': case 'H': case 'I': case 'J':
|
||||
case 'K': case 'L': case 'M': case 'N': case 'O':
|
||||
case 'P': case 'Q': case 'R': case 'S': case 'T':
|
||||
case 'U': case 'V': case 'W': case 'X': case 'Y':
|
||||
case 'Z':
|
||||
case '[': case '\\': case ']': case '^': case '_':
|
||||
case 'a': case 'b': case 'c': case 'd': case 'e':
|
||||
case 'f': case 'g': case 'h': case 'i': case 'j':
|
||||
case 'k': case 'l': case 'm': case 'n': case 'o':
|
||||
case 'p': case 'q': case 'r': case 's': case 't':
|
||||
case 'u': case 'v': case 'w': case 'x': case 'y':
|
||||
case 'z': case '{': case '|': case '}': case '~':
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _SHMBCHAR_H */
|
||||
@@ -0,0 +1,350 @@
|
||||
/* Multibyte character data type.
|
||||
Copyright (C) 2001, 2005-2007, 2009-2010 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Bruno Haible <bruno@clisp.org>. */
|
||||
|
||||
/* A multibyte character is a short subsequence of a char* string,
|
||||
representing a single wide character.
|
||||
|
||||
We use multibyte characters instead of wide characters because of
|
||||
the following goals:
|
||||
1) correct multibyte handling, i.e. operate according to the LC_CTYPE
|
||||
locale,
|
||||
2) ease of maintenance, i.e. the maintainer needs not know all details
|
||||
of the ISO C 99 standard,
|
||||
3) don't fail grossly if the input is not in the encoding set by the
|
||||
locale, because often different encodings are in use in the same
|
||||
countries (ISO-8859-1/UTF-8, EUC-JP/Shift_JIS, ...),
|
||||
4) fast in the case of ASCII characters,
|
||||
5) portability, i.e. don't make unportable assumptions about wchar_t.
|
||||
|
||||
Multibyte characters are only accessed through the mb* macros.
|
||||
|
||||
mb_ptr (mbc)
|
||||
return a pointer to the beginning of the multibyte sequence.
|
||||
|
||||
mb_len (mbc)
|
||||
returns the number of bytes occupied by the multibyte sequence.
|
||||
Always > 0.
|
||||
|
||||
mb_iseq (mbc, sc)
|
||||
returns true if mbc is the standard ASCII character sc.
|
||||
|
||||
mb_isnul (mbc)
|
||||
returns true if mbc is the nul character.
|
||||
|
||||
mb_cmp (mbc1, mbc2)
|
||||
returns a positive, zero, or negative value depending on whether mbc1
|
||||
sorts after, same or before mbc2.
|
||||
|
||||
mb_casecmp (mbc1, mbc2)
|
||||
returns a positive, zero, or negative value depending on whether mbc1
|
||||
sorts after, same or before mbc2, modulo upper/lowercase conversion.
|
||||
|
||||
mb_equal (mbc1, mbc2)
|
||||
returns true if mbc1 and mbc2 are equal.
|
||||
|
||||
mb_caseequal (mbc1, mbc2)
|
||||
returns true if mbc1 and mbc2 are equal modulo upper/lowercase conversion.
|
||||
|
||||
mb_isalnum (mbc)
|
||||
returns true if mbc is alphanumeric.
|
||||
|
||||
mb_isalpha (mbc)
|
||||
returns true if mbc is alphabetic.
|
||||
|
||||
mb_isascii(mbc)
|
||||
returns true if mbc is plain ASCII.
|
||||
|
||||
mb_isblank (mbc)
|
||||
returns true if mbc is a blank.
|
||||
|
||||
mb_iscntrl (mbc)
|
||||
returns true if mbc is a control character.
|
||||
|
||||
mb_isdigit (mbc)
|
||||
returns true if mbc is a decimal digit.
|
||||
|
||||
mb_isgraph (mbc)
|
||||
returns true if mbc is a graphic character.
|
||||
|
||||
mb_islower (mbc)
|
||||
returns true if mbc is lowercase.
|
||||
|
||||
mb_isprint (mbc)
|
||||
returns true if mbc is a printable character.
|
||||
|
||||
mb_ispunct (mbc)
|
||||
returns true if mbc is a punctuation character.
|
||||
|
||||
mb_isspace (mbc)
|
||||
returns true if mbc is a space character.
|
||||
|
||||
mb_isupper (mbc)
|
||||
returns true if mbc is uppercase.
|
||||
|
||||
mb_isxdigit (mbc)
|
||||
returns true if mbc is a hexadecimal digit.
|
||||
|
||||
mb_width (mbc)
|
||||
returns the number of columns on the output device occupied by mbc.
|
||||
Always >= 0.
|
||||
|
||||
mb_putc (mbc, stream)
|
||||
outputs mbc on stream, a byte oriented FILE stream opened for output.
|
||||
|
||||
mb_setascii (&mbc, sc)
|
||||
assigns the standard ASCII character sc to mbc.
|
||||
|
||||
mb_copy (&destmbc, &srcmbc)
|
||||
copies srcmbc to destmbc.
|
||||
|
||||
Here are the function prototypes of the macros.
|
||||
|
||||
extern const char * mb_ptr (const mbchar_t mbc);
|
||||
extern size_t mb_len (const mbchar_t mbc);
|
||||
extern bool mb_iseq (const mbchar_t mbc, char sc);
|
||||
extern bool mb_isnul (const mbchar_t mbc);
|
||||
extern int mb_cmp (const mbchar_t mbc1, const mbchar_t mbc2);
|
||||
extern int mb_casecmp (const mbchar_t mbc1, const mbchar_t mbc2);
|
||||
extern bool mb_equal (const mbchar_t mbc1, const mbchar_t mbc2);
|
||||
extern bool mb_caseequal (const mbchar_t mbc1, const mbchar_t mbc2);
|
||||
extern bool mb_isalnum (const mbchar_t mbc);
|
||||
extern bool mb_isalpha (const mbchar_t mbc);
|
||||
extern bool mb_isascii (const mbchar_t mbc);
|
||||
extern bool mb_isblank (const mbchar_t mbc);
|
||||
extern bool mb_iscntrl (const mbchar_t mbc);
|
||||
extern bool mb_isdigit (const mbchar_t mbc);
|
||||
extern bool mb_isgraph (const mbchar_t mbc);
|
||||
extern bool mb_islower (const mbchar_t mbc);
|
||||
extern bool mb_isprint (const mbchar_t mbc);
|
||||
extern bool mb_ispunct (const mbchar_t mbc);
|
||||
extern bool mb_isspace (const mbchar_t mbc);
|
||||
extern bool mb_isupper (const mbchar_t mbc);
|
||||
extern bool mb_isxdigit (const mbchar_t mbc);
|
||||
extern int mb_width (const mbchar_t mbc);
|
||||
extern void mb_putc (const mbchar_t mbc, FILE *stream);
|
||||
extern void mb_setascii (mbchar_t *new, char sc);
|
||||
extern void mb_copy (mbchar_t *new, const mbchar_t *old);
|
||||
*/
|
||||
|
||||
#ifndef _MBCHAR_H
|
||||
#define _MBCHAR_H 1
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
|
||||
<wchar.h>.
|
||||
BSD/OS 4.1 has a bug: <stdio.h> and <time.h> must be included before
|
||||
<wchar.h>. */
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
|
||||
#define MBCHAR_BUF_SIZE 24
|
||||
|
||||
struct mbchar
|
||||
{
|
||||
const char *ptr; /* pointer to current character */
|
||||
size_t bytes; /* number of bytes of current character, > 0 */
|
||||
bool wc_valid; /* true if wc is a valid wide character */
|
||||
wchar_t wc; /* if wc_valid: the current character */
|
||||
char buf[MBCHAR_BUF_SIZE]; /* room for the bytes, used for file input only */
|
||||
};
|
||||
|
||||
/* EOF (not a real character) is represented with bytes = 0 and
|
||||
wc_valid = false. */
|
||||
|
||||
typedef struct mbchar mbchar_t;
|
||||
|
||||
/* Access the current character. */
|
||||
#define mb_ptr(mbc) ((mbc).ptr)
|
||||
#define mb_len(mbc) ((mbc).bytes)
|
||||
|
||||
/* Comparison of characters. */
|
||||
#define mb_iseq(mbc, sc) ((mbc).wc_valid && (mbc).wc == (sc))
|
||||
#define mb_isnul(mbc) ((mbc).wc_valid && (mbc).wc == 0)
|
||||
#define mb_cmp(mbc1, mbc2) \
|
||||
((mbc1).wc_valid \
|
||||
? ((mbc2).wc_valid \
|
||||
? (int) (mbc1).wc - (int) (mbc2).wc \
|
||||
: -1) \
|
||||
: ((mbc2).wc_valid \
|
||||
? 1 \
|
||||
: (mbc1).bytes == (mbc2).bytes \
|
||||
? memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) \
|
||||
: (mbc1).bytes < (mbc2).bytes \
|
||||
? (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) > 0 ? 1 : -1) \
|
||||
: (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc2).bytes) >= 0 ? 1 : -1)))
|
||||
#define mb_casecmp(mbc1, mbc2) \
|
||||
((mbc1).wc_valid \
|
||||
? ((mbc2).wc_valid \
|
||||
? (int) towlower ((mbc1).wc) - (int) towlower ((mbc2).wc) \
|
||||
: -1) \
|
||||
: ((mbc2).wc_valid \
|
||||
? 1 \
|
||||
: (mbc1).bytes == (mbc2).bytes \
|
||||
? memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) \
|
||||
: (mbc1).bytes < (mbc2).bytes \
|
||||
? (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) > 0 ? 1 : -1) \
|
||||
: (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc2).bytes) >= 0 ? 1 : -1)))
|
||||
#define mb_equal(mbc1, mbc2) \
|
||||
((mbc1).wc_valid && (mbc2).wc_valid \
|
||||
? (mbc1).wc == (mbc2).wc \
|
||||
: (mbc1).bytes == (mbc2).bytes \
|
||||
&& memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) == 0)
|
||||
#define mb_caseequal(mbc1, mbc2) \
|
||||
((mbc1).wc_valid && (mbc2).wc_valid \
|
||||
? towlower ((mbc1).wc) == towlower ((mbc2).wc) \
|
||||
: (mbc1).bytes == (mbc2).bytes \
|
||||
&& memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) == 0)
|
||||
|
||||
/* <ctype.h>, <wctype.h> classification. */
|
||||
#define mb_isascii(mbc) \
|
||||
((mbc).wc_valid && (mbc).wc >= 0 && (mbc).wc <= 127)
|
||||
#define mb_isalnum(mbc) ((mbc).wc_valid && iswalnum ((mbc).wc))
|
||||
#define mb_isalpha(mbc) ((mbc).wc_valid && iswalpha ((mbc).wc))
|
||||
#define mb_isblank(mbc) ((mbc).wc_valid && iswblank ((mbc).wc))
|
||||
#define mb_iscntrl(mbc) ((mbc).wc_valid && iswcntrl ((mbc).wc))
|
||||
#define mb_isdigit(mbc) ((mbc).wc_valid && iswdigit ((mbc).wc))
|
||||
#define mb_isgraph(mbc) ((mbc).wc_valid && iswgraph ((mbc).wc))
|
||||
#define mb_islower(mbc) ((mbc).wc_valid && iswlower ((mbc).wc))
|
||||
#define mb_isprint(mbc) ((mbc).wc_valid && iswprint ((mbc).wc))
|
||||
#define mb_ispunct(mbc) ((mbc).wc_valid && iswpunct ((mbc).wc))
|
||||
#define mb_isspace(mbc) ((mbc).wc_valid && iswspace ((mbc).wc))
|
||||
#define mb_isupper(mbc) ((mbc).wc_valid && iswupper ((mbc).wc))
|
||||
#define mb_isxdigit(mbc) ((mbc).wc_valid && iswxdigit ((mbc).wc))
|
||||
|
||||
/* Extra <wchar.h> function. */
|
||||
|
||||
/* Unprintable characters appear as a small box of width 1. */
|
||||
#define MB_UNPRINTABLE_WIDTH 1
|
||||
|
||||
static inline int
|
||||
mb_width_aux (wint_t wc)
|
||||
{
|
||||
int w = wcwidth (wc);
|
||||
/* For unprintable characters, arbitrarily return 0 for control characters
|
||||
and MB_UNPRINTABLE_WIDTH otherwise. */
|
||||
return (w >= 0 ? w : iswcntrl (wc) ? 0 : MB_UNPRINTABLE_WIDTH);
|
||||
}
|
||||
|
||||
#define mb_width(mbc) \
|
||||
((mbc).wc_valid ? mb_width_aux ((mbc).wc) : MB_UNPRINTABLE_WIDTH)
|
||||
|
||||
/* Output. */
|
||||
#define mb_putc(mbc, stream) fwrite ((mbc).ptr, 1, (mbc).bytes, (stream))
|
||||
|
||||
/* Assignment. */
|
||||
#define mb_setascii(mbc, sc) \
|
||||
((mbc)->ptr = (mbc)->buf, (mbc)->bytes = 1, (mbc)->wc_valid = 1, \
|
||||
(mbc)->wc = (mbc)->buf[0] = (sc))
|
||||
|
||||
/* Copying a character. */
|
||||
static inline void
|
||||
mb_copy (mbchar_t *new_mbc, const mbchar_t *old_mbc)
|
||||
{
|
||||
if (old_mbc->ptr == &old_mbc->buf[0])
|
||||
{
|
||||
memcpy (&new_mbc->buf[0], &old_mbc->buf[0], old_mbc->bytes);
|
||||
new_mbc->ptr = &new_mbc->buf[0];
|
||||
}
|
||||
else
|
||||
new_mbc->ptr = old_mbc->ptr;
|
||||
new_mbc->bytes = old_mbc->bytes;
|
||||
if ((new_mbc->wc_valid = old_mbc->wc_valid))
|
||||
new_mbc->wc = old_mbc->wc;
|
||||
}
|
||||
|
||||
|
||||
/* is_basic(c) tests whether the single-byte character c is in the
|
||||
ISO C "basic character set".
|
||||
This is a convenience function, and is in this file only to share code
|
||||
between mbiter_multi.h and mbfile_multi.h. */
|
||||
#if (' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
||||
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
|
||||
&& (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
|
||||
&& ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
|
||||
&& ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
|
||||
&& ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
|
||||
&& ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
|
||||
&& ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
|
||||
&& ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
|
||||
&& ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
|
||||
&& ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
|
||||
&& ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
|
||||
&& ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
|
||||
&& ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
|
||||
&& ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
|
||||
&& ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
|
||||
&& ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
|
||||
&& ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
|
||||
&& ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
|
||||
&& ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
|
||||
&& ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
|
||||
&& ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
|
||||
&& ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)
|
||||
/* The character set is ISO-646, not EBCDIC. */
|
||||
# define IS_BASIC_ASCII 1
|
||||
|
||||
extern const unsigned int is_basic_table[];
|
||||
|
||||
static inline bool
|
||||
is_basic (char c)
|
||||
{
|
||||
return (is_basic_table [(unsigned char) c >> 5] >> ((unsigned char) c & 31))
|
||||
& 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline bool
|
||||
is_basic (char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '\t': case '\v': case '\f':
|
||||
case ' ': case '!': case '"': case '#': case '%':
|
||||
case '&': case '\'': case '(': case ')': case '*':
|
||||
case '+': case ',': case '-': case '.': case '/':
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
case ':': case ';': case '<': case '=': case '>':
|
||||
case '?':
|
||||
case 'A': case 'B': case 'C': case 'D': case 'E':
|
||||
case 'F': case 'G': case 'H': case 'I': case 'J':
|
||||
case 'K': case 'L': case 'M': case 'N': case 'O':
|
||||
case 'P': case 'Q': case 'R': case 'S': case 'T':
|
||||
case 'U': case 'V': case 'W': case 'X': case 'Y':
|
||||
case 'Z':
|
||||
case '[': case '\\': case ']': case '^': case '_':
|
||||
case 'a': case 'b': case 'c': case 'd': case 'e':
|
||||
case 'f': case 'g': case 'h': case 'i': case 'j':
|
||||
case 'k': case 'l': case 'm': case 'n': case 'o':
|
||||
case 'p': case 'q': case 'r': case 's': case 't':
|
||||
case 'u': case 'v': case 'w': case 'x': case 'y':
|
||||
case 'z': case '{': case '|': case '}': case '~':
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _MBCHAR_H */
|
||||
+68
-16
@@ -25,6 +25,7 @@
|
||||
|
||||
/* Include config.h for HANDLE_MULTIBYTE */
|
||||
#include <config.h>
|
||||
#include "shmbchar.h"
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
|
||||
@@ -101,9 +102,16 @@ extern char *xstrchr __P((const char *, int));
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _f; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_str) + (_i), (_strsize) - (_i), &state); \
|
||||
_f = is_basic ((_str)[_i]); \
|
||||
if (_f) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_str) + (_i), (_strsize) - (_i), &state); \
|
||||
} \
|
||||
\
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
@@ -134,9 +142,16 @@ extern char *xstrchr __P((const char *, int));
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _f; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_str), (_strsize), &state); \
|
||||
_f = is_basic (*(_str)); \
|
||||
if (_f) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_str), (_strsize), &state); \
|
||||
} \
|
||||
\
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
@@ -247,8 +262,14 @@ extern char *xstrchr __P((const char *, int));
|
||||
size_t mblength; \
|
||||
int _k; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src), (_srcend) - (_src), &state); \
|
||||
_k = is_basic (*(_src)); \
|
||||
if (_k) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src), (_srcend) - (_src), &state); \
|
||||
} \
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
@@ -280,8 +301,14 @@ extern char *xstrchr __P((const char *, int));
|
||||
size_t mblength; \
|
||||
int _k; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcend) - ((_src)+(_si)), &state); \
|
||||
_k = is_basic (*((_src) + (_si))); \
|
||||
if (_k) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcend) - ((_src)+(_si)), &state); \
|
||||
} \
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
@@ -317,8 +344,14 @@ extern char *xstrchr __P((const char *, int));
|
||||
size_t mblength; \
|
||||
int _i; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_slen) - (_si), &state); \
|
||||
_i = is_basic (*((_src) + (_si))); \
|
||||
if (_i) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_slen) - (_si), &state); \
|
||||
} \
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
@@ -356,9 +389,16 @@ extern char *xstrchr __P((const char *, int));
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _i; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcend) - ((_src) + (_si)), &state); \
|
||||
_i = is_basic (*((_src) + (_si))); \
|
||||
if (_i) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcend) - ((_src) + (_si)), &state); \
|
||||
} \
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
@@ -395,8 +435,14 @@ extern char *xstrchr __P((const char *, int));
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcsize) - (_si), &state); \
|
||||
i = is_basic (*((_src) + (_si))); \
|
||||
if (i) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcsize) - (_si), &state); \
|
||||
} \
|
||||
if (mblength == (size_t)-1 || mblength == (size_t)-2) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
@@ -427,8 +473,14 @@ extern char *xstrchr __P((const char *, int));
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcsize) - (_si), &state); \
|
||||
i = is_basic (*((_src) + (_si))); \
|
||||
if (i) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcsize) - (_si), &state); \
|
||||
} \
|
||||
if (mblength == (size_t)-1 || mblength == (size_t)-2) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
|
||||
@@ -0,0 +1,470 @@
|
||||
/* shmbutil.h -- utility functions for multibyte characters. */
|
||||
|
||||
/* Copyright (C) 2002-2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_SH_MBUTIL_H_)
|
||||
#define _SH_MBUTIL_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
/* Include config.h for HANDLE_MULTIBYTE */
|
||||
#include <config.h>
|
||||
#include "shmbchar.h"
|
||||
|
||||
#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 size_t mbstrlen __P((const char *));
|
||||
|
||||
extern char *xstrchr __P((const char *, int));
|
||||
|
||||
#ifndef MB_INVALIDCH
|
||||
#define MB_INVALIDCH(x) ((x) == (size_t)-1 || (x) == (size_t)-2)
|
||||
#define MB_NULLWCH(x) ((x) == 0)
|
||||
#endif
|
||||
|
||||
#define MBSLEN(s) (((s) && (s)[0]) ? ((s)[1] ? mbstrlen (s) : 1) : 0)
|
||||
#define MB_STRLEN(s) ((MB_CUR_MAX > 1) ? MBSLEN (s) : STRLEN (s))
|
||||
|
||||
#define MBLEN(s, n) ((MB_CUR_MAX > 1) ? mblen ((s), (n)) : 1)
|
||||
#define MBRLEN(s, n, p) ((MB_CUR_MAX > 1) ? mbrlen ((s), (n), (p)) : 1)
|
||||
|
||||
#else /* !HANDLE_MULTIBYTE */
|
||||
|
||||
#undef MB_LEN_MAX
|
||||
#undef MB_CUR_MAX
|
||||
|
||||
#define MB_LEN_MAX 1
|
||||
#define MB_CUR_MAX 1
|
||||
|
||||
#undef xstrchr
|
||||
#define xstrchr(s, c) strchr(s, c)
|
||||
|
||||
#ifndef MB_INVALIDCH
|
||||
#define MB_INVALIDCH(x) (0)
|
||||
#define MB_NULLWCH(x) (0)
|
||||
#endif
|
||||
|
||||
#define MB_STRLEN(s) (STRLEN(s))
|
||||
|
||||
#define MBLEN(s, n) 1
|
||||
#define MBRLEN(s, n, p) 1
|
||||
|
||||
#ifndef wchar_t
|
||||
# define wchar_t int
|
||||
#endif
|
||||
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Declare and initialize a multibyte state. Call must be terminated
|
||||
with `;'. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define DECLARE_MBSTATE \
|
||||
mbstate_t state; \
|
||||
memset (&state, '\0', sizeof (mbstate_t))
|
||||
#else
|
||||
# define DECLARE_MBSTATE
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Initialize or reinitialize a multibyte state named `state'. Call must be
|
||||
terminated with `;'. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define INITIALIZE_MBSTATE memset (&state, '\0', sizeof (mbstate_t))
|
||||
#else
|
||||
# define INITIALIZE_MBSTATE
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Advance one (possibly multi-byte) character in string _STR of length
|
||||
_STRSIZE, starting at index _I. STATE must have already been declared. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define ADVANCE_CHAR(_str, _strsize, _i) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _f; \
|
||||
\
|
||||
_f = is_basic ((_str)[_i]); \
|
||||
if (_f) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_str) + (_i), (_strsize) - (_i), &state); \
|
||||
} \
|
||||
\
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
(_i)++; \
|
||||
} \
|
||||
else if (mblength == 0) \
|
||||
(_i)++; \
|
||||
else \
|
||||
(_i) += mblength; \
|
||||
} \
|
||||
else \
|
||||
(_i)++; \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define ADVANCE_CHAR(_str, _strsize, _i) (_i)++
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Advance one (possibly multibyte) character in the string _STR of length
|
||||
_STRSIZE.
|
||||
SPECIAL: assume that _STR will be incremented by 1 after this call. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define ADVANCE_CHAR_P(_str, _strsize) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _f; \
|
||||
\
|
||||
_f = is_basic (*(_str)); \
|
||||
if (_f) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_str), (_strsize), &state); \
|
||||
} \
|
||||
\
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
else \
|
||||
(_str) += (mblength < 1) ? 0 : (mblength - 1); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define ADVANCE_CHAR_P(_str, _strsize)
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Back up one (possibly multi-byte) character in string _STR of length
|
||||
_STRSIZE, starting at index _I. STATE must have already been declared. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define BACKUP_CHAR(_str, _strsize, _i) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _x, _p; /* _x == temp index into string, _p == prev index */ \
|
||||
\
|
||||
_x = _p = 0; \
|
||||
while (_x < (_i)) \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_str) + (_x), (_strsize) - (_x), &state); \
|
||||
\
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
_x++; \
|
||||
} \
|
||||
else if (mblength == 0) \
|
||||
_x++; \
|
||||
else \
|
||||
{ \
|
||||
_p = _x; /* _p == start of prev mbchar */ \
|
||||
_x += mblength; \
|
||||
} \
|
||||
} \
|
||||
(_i) = _p; \
|
||||
} \
|
||||
else \
|
||||
(_i)--; \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define BACKUP_CHAR(_str, _strsize, _i) (_i)--
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Back up one (possibly multibyte) character in the string _BASE of length
|
||||
_STRSIZE starting at _STR (_BASE <= _STR <= (_BASE + _STRSIZE) ).
|
||||
SPECIAL: DO NOT assume that _STR will be decremented by 1 after this call. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define BACKUP_CHAR_P(_base, _strsize, _str) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
char *_x, _p; /* _x == temp pointer into string, _p == prev pointer */ \
|
||||
\
|
||||
_x = _p = _base; \
|
||||
while (_x < (_str)) \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen (_x, (_strsize) - _x, &state); \
|
||||
\
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
_x++; \
|
||||
} \
|
||||
else if (mblength == 0) \
|
||||
_x++; \
|
||||
else \
|
||||
{ \
|
||||
_p = _x; /* _p == start of prev mbchar */ \
|
||||
_x += mblength; \
|
||||
} \
|
||||
} \
|
||||
(_str) = _p; \
|
||||
} \
|
||||
else \
|
||||
(_str)--; \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define BACKUP_CHAR_P(_base, _strsize, _str) (_str)--
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Copy a single character from the string _SRC to the string _DST.
|
||||
_SRCEND is a pointer to the end of _SRC. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define COPY_CHAR_P(_dst, _src, _srcend) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _k; \
|
||||
\
|
||||
_k = is_basic (*(_src)); \
|
||||
if (_k) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src), (_srcend) - (_src), &state); \
|
||||
} \
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
else \
|
||||
mblength = (mblength < 1) ? 1 : mblength; \
|
||||
\
|
||||
for (_k = 0; _k < mblength; _k++) \
|
||||
*(_dst)++ = *(_src)++; \
|
||||
} \
|
||||
else \
|
||||
*(_dst)++ = *(_src)++; \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define COPY_CHAR_P(_dst, _src, _srcend) *(_dst)++ = *(_src)++
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Copy a single character from the string _SRC at index _SI to the string
|
||||
_DST at index _DI. _SRCEND is a pointer to the end of _SRC. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define COPY_CHAR_I(_dst, _di, _src, _srcend, _si) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _k; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcend) - ((_src)+(_si)), &state); \
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
else \
|
||||
mblength = (mblength < 1) ? 1 : mblength; \
|
||||
\
|
||||
for (_k = 0; _k < mblength; _k++) \
|
||||
_dst[_di++] = _src[_si++]; \
|
||||
} \
|
||||
else \
|
||||
_dst[_di++] = _src[_si++]; \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define COPY_CHAR_I(_dst, _di, _src, _srcend, _si) _dst[_di++] = _src[_si++]
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/****************************************************************
|
||||
* *
|
||||
* The following are only guaranteed to work in subst.c *
|
||||
* *
|
||||
****************************************************************/
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define SCOPY_CHAR_I(_dst, _escchar, _sc, _src, _si, _slen) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _i; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_slen) - (_si), &state); \
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
else \
|
||||
mblength = (mblength < 1) ? 1 : mblength; \
|
||||
\
|
||||
temp = xmalloc (mblength + 2); \
|
||||
temp[0] = _escchar; \
|
||||
for (_i = 0; _i < mblength; _i++) \
|
||||
temp[_i + 1] = _src[_si++]; \
|
||||
temp[mblength + 1] = '\0'; \
|
||||
\
|
||||
goto add_string; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
_dst[0] = _escchar; \
|
||||
_dst[1] = _sc; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define SCOPY_CHAR_I(_dst, _escchar, _sc, _src, _si, _slen) \
|
||||
_dst[0] = _escchar; \
|
||||
_dst[1] = _sc
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define SCOPY_CHAR_M(_dst, _src, _srcend, _si) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcend) - ((_src) + (_si)), &state); \
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
else \
|
||||
mblength = (mblength < 1) ? 1 : mblength; \
|
||||
\
|
||||
FASTCOPY(((_src) + (_si)), (_dst), mblength); \
|
||||
\
|
||||
(_dst) += mblength; \
|
||||
(_si) += mblength; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
*(_dst)++ = _src[(_si)]; \
|
||||
(_si)++; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define SCOPY_CHAR_M(_dst, _src, _srcend, _si) \
|
||||
*(_dst)++ = _src[(_si)]; \
|
||||
(_si)++
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
#if HANDLE_MULTIBYTE
|
||||
# define SADD_MBCHAR(_dst, _src, _si, _srcsize) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
int i; \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcsize) - (_si), &state); \
|
||||
if (mblength == (size_t)-1 || mblength == (size_t)-2) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
if (mblength < 1) \
|
||||
mblength = 1; \
|
||||
\
|
||||
_dst = (char *)xmalloc (mblength + 1); \
|
||||
for (i = 0; i < mblength; i++) \
|
||||
(_dst)[i] = (_src)[(_si)++]; \
|
||||
(_dst)[mblength] = '\0'; \
|
||||
\
|
||||
goto add_string; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#else
|
||||
# define SADD_MBCHAR(_dst, _src, _si, _srcsize)
|
||||
#endif
|
||||
|
||||
/* 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; \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcsize) - (_si), &state); \
|
||||
if (mblength == (size_t)-1 || mblength == (size_t)-2) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
if (mblength < 1) \
|
||||
mblength = 1; \
|
||||
\
|
||||
(_dst) = (char *)xmalloc (mblength + 2); \
|
||||
(_dst)[0] = CTLESC; \
|
||||
for (i = 0; i < mblength; i++) \
|
||||
(_dst)[i+1] = (_src)[(_si)++]; \
|
||||
(_dst)[mblength+1] = '\0'; \
|
||||
\
|
||||
goto add_string
|
||||
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
#endif /* _SH_MBUTIL_H_ */
|
||||
@@ -365,6 +365,16 @@ xstrmatch (pattern, string, flags)
|
||||
int ret;
|
||||
size_t n;
|
||||
wchar_t *wpattern, *wstring;
|
||||
size_t plen, slen, mplen, mslen;
|
||||
|
||||
#if 0
|
||||
plen = strlen (pattern);
|
||||
mplen = mbstrlen (pattern);
|
||||
if (plen == mplen && strlen (string) == mbstrlen (string))
|
||||
#else
|
||||
if (mbsmbchar (string) == 0 && mbsmbchar (pattern) == 0)
|
||||
#endif
|
||||
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
|
||||
|
||||
if (MB_CUR_MAX == 1)
|
||||
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
|
||||
|
||||
@@ -0,0 +1,398 @@
|
||||
/* strmatch.c -- ksh-like extended pattern matching for the shell and filename
|
||||
globbing. */
|
||||
|
||||
/* Copyright (C) 1991-2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
char *x;
|
||||
|
||||
x = (char *)s;
|
||||
for (csp = posix_collsyms; csp->name; csp++)
|
||||
{
|
||||
if (STREQN(csp->name, x, 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' };
|
||||
|
||||
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;
|
||||
size_t n;
|
||||
wchar_t *wpattern, *wstring;
|
||||
size_t plen, slen, mplen, mslen;
|
||||
|
||||
plen = strlen (pattern);
|
||||
mplen = mbstrlen (pattern);
|
||||
if (plen == mplen && strlen (string) == mbstrlen (string))
|
||||
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
|
||||
|
||||
if (MB_CUR_MAX == 1)
|
||||
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
|
||||
|
||||
n = xdupmbstowcs (&wpattern, NULL, pattern);
|
||||
if (n == (size_t)-1 || n == (size_t)-2)
|
||||
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
|
||||
|
||||
n = xdupmbstowcs (&wstring, NULL, string);
|
||||
if (n == (size_t)-1 || n == (size_t)-2)
|
||||
{
|
||||
free (wpattern);
|
||||
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
|
||||
}
|
||||
|
||||
ret = internal_wstrmatch (wpattern, wstring, flags);
|
||||
|
||||
free (wpattern);
|
||||
free (wstring);
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
}
|
||||
@@ -763,10 +763,14 @@ as if the "!\fIn\fP" history expansion had been specified.
|
||||
.B
|
||||
yank\-last\-arg (M\-.\^, M\-_\^)
|
||||
Insert the last argument to the previous command (the last word of
|
||||
the previous history entry). With an argument,
|
||||
behave exactly like \fByank\-nth\-arg\fP.
|
||||
the previous history entry).
|
||||
With a numeric argument, behave exactly like \fByank\-nth\-arg\fP.
|
||||
Successive calls to \fByank\-last\-arg\fP move back through the history
|
||||
list, inserting the last argument of each line in turn.
|
||||
list, inserting the last word (or the word specified by the argument to
|
||||
the first call) of each line in turn.
|
||||
Any numeric argument supplied to these successive calls determines
|
||||
the direction to move through the history. A negative argument switches
|
||||
the direction through the history (back or forward).
|
||||
The history expansion facilities are used to extract the last argument,
|
||||
as if the "!$" history expansion had been specified.
|
||||
.PD
|
||||
|
||||
@@ -492,6 +492,11 @@ completion.
|
||||
If set to \fBOff\fP, the leading `.' must be
|
||||
supplied by the user in the filename to be completed.
|
||||
.TP
|
||||
.B menu\-complete\-display\-prefix (Off)
|
||||
If set to \fBOn\fP, menu completion displays the common prefix of the
|
||||
list of possible completions (which may be empty) before cycling through
|
||||
the list.
|
||||
.TP
|
||||
.B output\-meta (Off)
|
||||
If set to \fBOn\fP, readline will display characters with the
|
||||
eighth bit set directly rather than as a meta-prefixed escape
|
||||
|
||||
@@ -1120,10 +1120,14 @@ as if the @samp{!@var{n}} history expansion had been specified.
|
||||
|
||||
@item yank-last-arg (M-. or M-_)
|
||||
Insert last argument to the previous command (the last word of the
|
||||
previous history entry). With an
|
||||
argument, behave exactly like @code{yank-nth-arg}.
|
||||
previous history entry).
|
||||
With a numeric argument, behave exactly like @code{yank-nth-arg}.
|
||||
Successive calls to @code{yank-last-arg} move back through the history
|
||||
list, inserting the last argument of each line in turn.
|
||||
list, inserting the last word (or the word specified by the argument to
|
||||
the first call) of each line in turn.
|
||||
Any numeric argument supplied to these successive calls determines
|
||||
the direction to move through the history. A negative argument switches
|
||||
the direction through the history (back or forward).
|
||||
The history expansion facilities are used to extract the last argument,
|
||||
as if the @samp{!$} history expansion had been specified.
|
||||
|
||||
|
||||
@@ -591,6 +591,12 @@ If set to @samp{off}, the leading @samp{.} must be
|
||||
supplied by the user in the filename to be completed.
|
||||
This variable is @samp{on} by default.
|
||||
|
||||
@item menu-complete-display-prefix
|
||||
@vindex menu-complete-display-prefix
|
||||
If set to @samp{on}, menu completion displays the common prefix of the
|
||||
list of possible completions (which may be empty) before cycling through
|
||||
the list. The default is @samp{off}.
|
||||
|
||||
@item output-meta
|
||||
@vindex output-meta
|
||||
If set to @samp{on}, Readline will display characters with the
|
||||
@@ -1114,10 +1120,14 @@ as if the @samp{!@var{n}} history expansion had been specified.
|
||||
|
||||
@item yank-last-arg (M-. or M-_)
|
||||
Insert last argument to the previous command (the last word of the
|
||||
previous history entry). With an
|
||||
argument, behave exactly like @code{yank-nth-arg}.
|
||||
previous history entry).
|
||||
With a numeric argument, behave exactly like @code{yank-nth-arg}.
|
||||
Successive calls to @code{yank-last-arg} move back through the history
|
||||
list, inserting the last argument of each line in turn.
|
||||
list, inserting the last word (or the word specified by the argument to
|
||||
the first call) of each line in turn.
|
||||
Any numeric argument supplied to these successive calls determines
|
||||
the direction to move through the history. A negative argument switches
|
||||
the direction through the history (back or forward).
|
||||
The history expansion facilities are used to extract the last argument,
|
||||
as if the @samp{!$} history expansion had been specified.
|
||||
|
||||
@@ -1229,7 +1239,7 @@ Kill from point to the end of the current word, or if between
|
||||
words, to the end of the next word.
|
||||
Word boundaries are the same as @code{shell-forward-word}.
|
||||
|
||||
@item backward-kill-word ()
|
||||
@item shell-backward-kill-word ()
|
||||
Kill the word behind point.
|
||||
Word boundaries are the same as @code{shell-backward-word}.
|
||||
@end ifset
|
||||
|
||||
+1
-1
@@ -640,7 +640,7 @@ rl_yank_last_arg (count, key)
|
||||
{
|
||||
if (undo_needed)
|
||||
rl_do_undo ();
|
||||
if (count < 1)
|
||||
if (count < 0) /* XXX - was < 1 */
|
||||
direction = -direction;
|
||||
history_skip += direction;
|
||||
if (history_skip < 0)
|
||||
|
||||
@@ -147,7 +147,7 @@ _rl_copy_to_kill_ring (text, append)
|
||||
strcat (new, old);
|
||||
}
|
||||
xfree (old);
|
||||
free (text);
|
||||
xfree (text);
|
||||
rl_kill_ring[slot] = new;
|
||||
}
|
||||
else
|
||||
@@ -601,7 +601,7 @@ rl_yank_nth_arg_internal (count, ignore, history_skip)
|
||||
#endif /* VI_MODE */
|
||||
|
||||
rl_insert_text (arg);
|
||||
free (arg);
|
||||
xfree (arg);
|
||||
|
||||
rl_end_undo_group ();
|
||||
return 0;
|
||||
|
||||
+8
-4
@@ -92,7 +92,7 @@ CSOURCES = clktck.c clock.c getcwd.c getenv.c oslib.c setlinebuf.c \
|
||||
mktime.c strftime.c mbschr.c zcatfd.c zmapfd.c winsize.c eaccess.c \
|
||||
wcsdup.c fpurge.c zgetline.c mbscmp.c uconvert.c ufuncs.c \
|
||||
casemod.c dprintf.c input_avail.c mbscasecmp.c fnxform.c \
|
||||
strchrnul.c unicode.c wcswidth.c
|
||||
strchrnul.c unicode.c wcswidth.c shmbchar.c
|
||||
|
||||
# The header files for this library.
|
||||
HSOURCES =
|
||||
@@ -106,7 +106,7 @@ OBJECTS = clktck.o clock.o getenv.o oslib.o setlinebuf.o strnlen.o \
|
||||
strtrans.o snprintf.o mailstat.o fmtulong.o \
|
||||
fmtullong.o fmtumax.o zcatfd.o zmapfd.o winsize.o wcsdup.o \
|
||||
fpurge.o zgetline.o mbscmp.o uconvert.o ufuncs.o casemod.o \
|
||||
input_avail.o mbscasecmp.o fnxform.o unicode.o ${LIBOBJS}
|
||||
input_avail.o mbscasecmp.o fnxform.o unicode.o shmbchar.o ${LIBOBJS}
|
||||
|
||||
SUPPORT = Makefile
|
||||
|
||||
@@ -169,6 +169,7 @@ pathcanon.o: pathcanon.c
|
||||
pathphys.o: pathphys.c
|
||||
rename.o: rename.c
|
||||
setlinebuf.o: setlinebuf.c
|
||||
shmbchar.o: shmbchar.c
|
||||
shquote.o: shquote.c
|
||||
shtty.o: shtty.c
|
||||
snprintf.o: snprintf.c
|
||||
@@ -240,6 +241,7 @@ pathcanon.o: ${BUILD_DIR}/config.h
|
||||
pathphys.o: ${BUILD_DIR}/config.h
|
||||
rename.o: ${BUILD_DIR}/config.h
|
||||
setlinebuf.o: ${BUILD_DIR}/config.h
|
||||
shmbchare.o: ${BUILD_DIR}/config.h
|
||||
shquote.o: ${BUILD_DIR}/config.h
|
||||
shtty.o: ${BUILD_DIR}/config.h
|
||||
snprintf.o: ${BUILD_DIR}/config.h
|
||||
@@ -513,7 +515,7 @@ wcswidth.o: ${BASHINCDIR}/stdc.h
|
||||
|
||||
mbschr.o: ${topdir}/bashansi.h
|
||||
mbschr.o: ${BASHINCDIR}/ansi_stdlib.h
|
||||
mbschr.o: ${BASHINCDIR}/shmbutil.h
|
||||
mbschr.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/shmbchar.h
|
||||
|
||||
zgetline.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
|
||||
zgetline.o: ${BASHINCDIR}/stdc.h
|
||||
@@ -532,7 +534,7 @@ casemod.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
|
||||
casemod.o: ${BASHINCDIR}/stdc.h
|
||||
casemod.o: ${topdir}/xmalloc.h
|
||||
casemod.o: ${topdir}/bashtypes.h
|
||||
casemod.o: ${BASHINCDIR}/shmbutil.h
|
||||
casemod.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/shmbchar.h
|
||||
casemod.o: ${topdir}/bashintl.h ${LIBINTL_H} ${BASHINCDIR}/gettext.h
|
||||
|
||||
dprintf.o: ${BASHINCDIR}/stdc.h
|
||||
@@ -548,3 +550,5 @@ fnxform.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
|
||||
fnxform.o: ${BASHINCDIR}/stdc.h
|
||||
fnxform.o: ${topdir}/bashtypes.h
|
||||
fnxform.o: ${topdir}/bashintl.h ${LIBINTL_H} ${BASHINCDIR}/gettext.h
|
||||
|
||||
shmbchar.o: ${BASHINCDIR}/shmbchar.h
|
||||
|
||||
+13
-4
@@ -92,7 +92,7 @@ CSOURCES = clktck.c clock.c getcwd.c getenv.c oslib.c setlinebuf.c \
|
||||
mktime.c strftime.c mbschr.c zcatfd.c zmapfd.c winsize.c eaccess.c \
|
||||
wcsdup.c fpurge.c zgetline.c mbscmp.c uconvert.c ufuncs.c \
|
||||
casemod.c dprintf.c input_avail.c mbscasecmp.c fnxform.c \
|
||||
strchrnul.c unicode.c
|
||||
strchrnul.c unicode.c wcswidth.c shmbchar.c
|
||||
|
||||
# The header files for this library.
|
||||
HSOURCES =
|
||||
@@ -106,7 +106,7 @@ OBJECTS = clktck.o clock.o getenv.o oslib.o setlinebuf.o strnlen.o \
|
||||
strtrans.o snprintf.o mailstat.o fmtulong.o \
|
||||
fmtullong.o fmtumax.o zcatfd.o zmapfd.o winsize.o wcsdup.o \
|
||||
fpurge.o zgetline.o mbscmp.o uconvert.o ufuncs.o casemod.o \
|
||||
input_avail.o mbscasecmp.o fnxform.o unicode.o ${LIBOBJS}
|
||||
input_avail.o mbscasecmp.o fnxform.o unicode.o shmbchar.o ${LIBOBJS}
|
||||
|
||||
SUPPORT = Makefile
|
||||
|
||||
@@ -169,6 +169,7 @@ pathcanon.o: pathcanon.c
|
||||
pathphys.o: pathphys.c
|
||||
rename.o: rename.c
|
||||
setlinebuf.o: setlinebuf.c
|
||||
shmbchar.o: shmbchar.c
|
||||
shquote.o: shquote.c
|
||||
shtty.o: shtty.c
|
||||
snprintf.o: snprintf.c
|
||||
@@ -196,6 +197,7 @@ uconvert.o: uconvert.c
|
||||
ufuncs.o: ufuncs.c
|
||||
vprint.o: vprint.c
|
||||
wcsdup.o: wcsdup.c
|
||||
wcswidth.o: wcswidth.c
|
||||
mbschr.o: mbschr.c
|
||||
zcatfd.o: zcatfd.c
|
||||
zmapfd.o: zmapfd.c
|
||||
@@ -239,6 +241,7 @@ pathcanon.o: ${BUILD_DIR}/config.h
|
||||
pathphys.o: ${BUILD_DIR}/config.h
|
||||
rename.o: ${BUILD_DIR}/config.h
|
||||
setlinebuf.o: ${BUILD_DIR}/config.h
|
||||
shmbchare.o: ${BUILD_DIR}/config.h
|
||||
shquote.o: ${BUILD_DIR}/config.h
|
||||
shtty.o: ${BUILD_DIR}/config.h
|
||||
snprintf.o: ${BUILD_DIR}/config.h
|
||||
@@ -266,6 +269,7 @@ uconvert.o: ${BUILD_DIR}/config.h
|
||||
ufuncs.o: ${BUILD_DIR}/config.h
|
||||
vprint.o: ${BUILD_DIR}/config.h
|
||||
wcsdup.o: ${BUILD_DIR}/config.h
|
||||
wcswidth.o: ${BUILD_DIR}/config.h
|
||||
mbschr.o: ${BUILD_DIR}/config.h
|
||||
zcatfd.o: ${BUILD_DIR}/config.h
|
||||
zgetline.o: ${BUILD_DIR}/config.h
|
||||
@@ -506,9 +510,12 @@ wcsdup.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
|
||||
wcsdup.o: ${BASHINCDIR}/stdc.h
|
||||
wcsdup.o: ${topdir}/xmalloc.h
|
||||
|
||||
wcswidth.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
|
||||
wcswidth.o: ${BASHINCDIR}/stdc.h
|
||||
|
||||
mbschr.o: ${topdir}/bashansi.h
|
||||
mbschr.o: ${BASHINCDIR}/ansi_stdlib.h
|
||||
mbschr.o: ${BASHINCDIR}/shmbutil.h
|
||||
mbschr.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/shmchar.h
|
||||
|
||||
zgetline.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
|
||||
zgetline.o: ${BASHINCDIR}/stdc.h
|
||||
@@ -527,7 +534,7 @@ casemod.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
|
||||
casemod.o: ${BASHINCDIR}/stdc.h
|
||||
casemod.o: ${topdir}/xmalloc.h
|
||||
casemod.o: ${topdir}/bashtypes.h
|
||||
casemod.o: ${BASHINCDIR}/shmbutil.h
|
||||
casemod.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/shmchar.h
|
||||
casemod.o: ${topdir}/bashintl.h ${LIBINTL_H} ${BASHINCDIR}/gettext.h
|
||||
|
||||
dprintf.o: ${BASHINCDIR}/stdc.h
|
||||
@@ -543,3 +550,5 @@ fnxform.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
|
||||
fnxform.o: ${BASHINCDIR}/stdc.h
|
||||
fnxform.o: ${topdir}/bashtypes.h
|
||||
fnxform.o: ${topdir}/bashintl.h ${LIBINTL_H} ${BASHINCDIR}/gettext.h
|
||||
|
||||
shmbchar.o: ${BASHINCDIR}/shmbchar.h
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ curencoding ()
|
||||
mod = strchr (dot, '@');
|
||||
if (mod)
|
||||
*mod = '\0';
|
||||
return dot;
|
||||
return ++dot;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/* Copyright (C) 2001, 2006, 2009, 2010 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <shmbutil.h>
|
||||
#include <shmbchar.h>
|
||||
|
||||
#if IS_BASIC_ASCII
|
||||
|
||||
/* Bit table of characters in the ISO C "basic character set". */
|
||||
const unsigned int is_basic_table [UCHAR_MAX / 32 + 1] =
|
||||
{
|
||||
0x00001a00, /* '\t' '\v' '\f' */
|
||||
0xffffffef, /* ' '...'#' '%'...'?' */
|
||||
0xfffffffe, /* 'A'...'Z' '[' '\\' ']' '^' '_' */
|
||||
0x7ffffffe /* 'a'...'z' '{' '|' '}' '~' */
|
||||
/* The remaining bits are 0. */
|
||||
};
|
||||
|
||||
#endif /* IS_BASIC_ASCII */
|
||||
|
||||
size_t
|
||||
mbstrlen (s)
|
||||
const char *s;
|
||||
{
|
||||
size_t clen, nc;
|
||||
mbstate_t mbs = { 0 }, mbsbak = { 0 };
|
||||
int f;
|
||||
|
||||
nc = 0;
|
||||
while (*s && (clen = (f = is_basic (*s)) ? 1 : mbrlen(s, MB_CUR_MAX, &mbs)) != 0)
|
||||
{
|
||||
if (MB_INVALIDCH(clen))
|
||||
{
|
||||
clen = 1; /* assume single byte */
|
||||
mbs = mbsbak;
|
||||
}
|
||||
|
||||
if (f == 0)
|
||||
mbsbak = mbs;
|
||||
|
||||
s += clen;
|
||||
nc++;
|
||||
}
|
||||
return nc;
|
||||
}
|
||||
|
||||
/* Return pointer to first multibyte char in S, or NULL if none. */
|
||||
char *
|
||||
mbsmbchar (s)
|
||||
const char *s;
|
||||
{
|
||||
char *t;
|
||||
size_t clen;
|
||||
mbstate_t mbs = { 0 };
|
||||
|
||||
for (t = (char *)s; *t; t++)
|
||||
{
|
||||
if (is_basic (*t))
|
||||
continue;
|
||||
|
||||
clen = mbrlen (t, MB_CUR_MAX, &mbs);
|
||||
|
||||
if (clen == 0)
|
||||
return 0;
|
||||
if (MB_INVALIDCH(clen))
|
||||
continue;
|
||||
|
||||
if (clen > 1)
|
||||
return t;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
/* Copyright (C) 2001, 2006, 2009, 2010 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <shmbutil.h>
|
||||
#include <shmbchar.h>
|
||||
|
||||
#if IS_BASIC_ASCII
|
||||
|
||||
/* Bit table of characters in the ISO C "basic character set". */
|
||||
const unsigned int is_basic_table [UCHAR_MAX / 32 + 1] =
|
||||
{
|
||||
0x00001a00, /* '\t' '\v' '\f' */
|
||||
0xffffffef, /* ' '...'#' '%'...'?' */
|
||||
0xfffffffe, /* 'A'...'Z' '[' '\\' ']' '^' '_' */
|
||||
0x7ffffffe /* 'a'...'z' '{' '|' '}' '~' */
|
||||
/* The remaining bits are 0. */
|
||||
};
|
||||
|
||||
#endif /* IS_BASIC_ASCII */
|
||||
|
||||
size_t
|
||||
mbstrlen (s)
|
||||
const char *s;
|
||||
{
|
||||
size_t clen, nc;
|
||||
mbstate_t mbs = { 0 }, mbsbak = { 0 };
|
||||
|
||||
nc = 0;
|
||||
while (*s && (clen = is_basic (*s) ? 1 : mbrlen(s, MB_CUR_MAX, &mbs)) != 0)
|
||||
{
|
||||
if (MB_INVALIDCH(clen))
|
||||
{
|
||||
clen = 1; /* assume single byte */
|
||||
mbs = mbsbak;
|
||||
}
|
||||
|
||||
if (is_basic (*s) == 0)
|
||||
mbsbak = mbs;
|
||||
|
||||
s += clen;
|
||||
nc++;
|
||||
}
|
||||
return nc;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,91 @@
|
||||
/* Copyright (C) 2001, 2006, 2009, 2010 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <shmbutil.h>
|
||||
#include <shmbchar.h>
|
||||
|
||||
#if IS_BASIC_ASCII
|
||||
|
||||
/* Bit table of characters in the ISO C "basic character set". */
|
||||
const unsigned int is_basic_table [UCHAR_MAX / 32 + 1] =
|
||||
{
|
||||
0x00001a00, /* '\t' '\v' '\f' */
|
||||
0xffffffef, /* ' '...'#' '%'...'?' */
|
||||
0xfffffffe, /* 'A'...'Z' '[' '\\' ']' '^' '_' */
|
||||
0x7ffffffe /* 'a'...'z' '{' '|' '}' '~' */
|
||||
/* The remaining bits are 0. */
|
||||
};
|
||||
|
||||
#endif /* IS_BASIC_ASCII */
|
||||
|
||||
size_t
|
||||
mbstrlen (s)
|
||||
const char *s;
|
||||
{
|
||||
size_t clen, nc;
|
||||
mbstate_t mbs = { 0 }, mbsbak = { 0 };
|
||||
|
||||
nc = 0;
|
||||
while (*s && (clen = is_basic (*s) ? 1 : mbrlen(s, MB_CUR_MAX, &mbs)) != 0)
|
||||
{
|
||||
if (MB_INVALIDCH(clen))
|
||||
{
|
||||
clen = 1; /* assume single byte */
|
||||
mbs = mbsbak;
|
||||
}
|
||||
|
||||
if (is_basic (*s) == 0)
|
||||
mbsbak = mbs;
|
||||
|
||||
s += clen;
|
||||
nc++;
|
||||
}
|
||||
return nc;
|
||||
}
|
||||
|
||||
/* Return pointer to first multibyte char in S, or NULL if none. */
|
||||
char *
|
||||
mbsmbchar (s)
|
||||
const char *s;
|
||||
{
|
||||
char *t;
|
||||
size_t clen;
|
||||
mbstate_t mbs = { 0 };
|
||||
|
||||
for (t = (char *)s; *t; t++)
|
||||
{
|
||||
if (is_basic (*t))
|
||||
continue;
|
||||
|
||||
clen = mbrlen (t, MB_CUR_MAX, &mbs);
|
||||
|
||||
if (clen == 0)
|
||||
return 0;
|
||||
if (MB_INVALIDCH(clen))
|
||||
continue;
|
||||
|
||||
if (clen > 1)
|
||||
return t;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
+8
-3
@@ -64,14 +64,19 @@ static iconv_t localconv;
|
||||
static char *
|
||||
stub_charset ()
|
||||
{
|
||||
char *locale, *s;
|
||||
char *locale, *s, *t;
|
||||
|
||||
locale = get_locale_var ("LC_CTYPE");
|
||||
if (locale == 0)
|
||||
if (locale == 0 || *locale == 0)
|
||||
return "ASCII";
|
||||
s = strrchr (locale, '.');
|
||||
if (s)
|
||||
return ++s;
|
||||
{
|
||||
t = strchr (s, '@');
|
||||
if (t)
|
||||
*t = 0;
|
||||
return ++s;
|
||||
}
|
||||
else if (STREQ (locale, "UTF-8"))
|
||||
return "UTF-8";
|
||||
else
|
||||
|
||||
+33
-3
@@ -1,6 +1,6 @@
|
||||
/* unicode.c - functions to convert unicode characters */
|
||||
|
||||
/* Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -56,7 +56,33 @@ extern char *get_locale_var __P((char *));
|
||||
|
||||
static int u32init = 0;
|
||||
static int utf8locale = 0;
|
||||
#if defined (HAVE_ICONV)
|
||||
static iconv_t localconv;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_LOCALE_CHARSET
|
||||
static char *
|
||||
stub_charset ()
|
||||
{
|
||||
char *locale, *s;
|
||||
|
||||
locale = get_locale_var ("LC_CTYPE");
|
||||
if (locale == 0 || *locale == 0)
|
||||
return "ASCII";
|
||||
s = strrchr (locale, '.');
|
||||
if (s)
|
||||
{
|
||||
t = strchr (s, '@');
|
||||
if (t)
|
||||
*t = 0;
|
||||
return ++s;
|
||||
}
|
||||
else if (STREQ (locale, "UTF-8"))
|
||||
return "UTF-8";
|
||||
else
|
||||
return "ASCII";
|
||||
}
|
||||
#endif
|
||||
|
||||
/* u32toascii ? */
|
||||
int
|
||||
@@ -127,7 +153,7 @@ u32cconv (c, s)
|
||||
const char *charset;
|
||||
char obuf[25], *optr;
|
||||
size_t obytesleft;
|
||||
char *iptr;
|
||||
const char *iptr;
|
||||
size_t sn;
|
||||
#endif
|
||||
|
||||
@@ -154,7 +180,11 @@ u32cconv (c, s)
|
||||
/* this is mostly from coreutils-8.5/lib/unicodeio.c */
|
||||
if (u32init == 0)
|
||||
{
|
||||
# if HAVE_LOCALE_CHARSET
|
||||
charset = locale_charset (); /* XXX - fix later */
|
||||
# else
|
||||
charset = stub_charset ();
|
||||
# endif
|
||||
if (STREQ (charset, "UTF-8"))
|
||||
utf8locale = 1;
|
||||
else
|
||||
@@ -187,7 +217,7 @@ u32cconv (c, s)
|
||||
|
||||
iconv (localconv, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (iconv (localconv, &iptr, &sn, &optr, &obytesleft) == (size_t)-1)
|
||||
if (iconv (localconv, (ICONV_CONST char **)&iptr, &sn, &optr, &obytesleft) == (size_t)-1)
|
||||
return n; /* You get utf-8 if iconv fails */
|
||||
|
||||
*optr = '\0';
|
||||
|
||||
@@ -297,7 +297,7 @@ get_locale_var (var)
|
||||
locale = lc_all;
|
||||
|
||||
if (locale == 0 || *locale == 0)
|
||||
locale = get_string_value (var);
|
||||
locale = get_string_value (var); /* XXX - mem leak? */
|
||||
if (locale == 0 || *locale == 0)
|
||||
locale = lang;
|
||||
if (locale == 0 || *locale == 0)
|
||||
|
||||
@@ -5255,7 +5255,7 @@ decode_prompt_string (string)
|
||||
{
|
||||
t = strrchr (t_string, '/');
|
||||
if (t)
|
||||
memmove (t_string, t + 1, strlen (t) - 1);
|
||||
memmove (t_string, t + 1, strlen (t)); /* strlen(t) to copy NULL */
|
||||
}
|
||||
}
|
||||
#undef ROOT_PATH
|
||||
|
||||
@@ -3434,7 +3434,7 @@ parse_comsub (qc, open, close, lenp, flags)
|
||||
while (count)
|
||||
{
|
||||
comsub_readchar:
|
||||
ch = shell_getc (qc != '\'' && (tflags & LEX_PASSNEXT) == 0);
|
||||
ch = shell_getc (qc != '\'' && (tflags & (LEX_INCOMMENT|LEX_PASSNEXT)) == 0);
|
||||
|
||||
if (ch == EOF)
|
||||
{
|
||||
@@ -5255,7 +5255,7 @@ decode_prompt_string (string)
|
||||
{
|
||||
t = strrchr (t_string, '/');
|
||||
if (t)
|
||||
memmove (t_string, t + 1, strlen (t) - 1);
|
||||
memmove (t_string, t + 1, strlen (t)); /* tlen to copy NULL */
|
||||
}
|
||||
}
|
||||
#undef ROOT_PATH
|
||||
|
||||
@@ -63,7 +63,7 @@ extern int parse_and_execute_level, shell_initialized;
|
||||
extern int history_lines_this_session;
|
||||
#endif
|
||||
|
||||
extern void intialize_siglist ();
|
||||
extern void initialize_siglist ();
|
||||
|
||||
/* Non-zero after SIGINT. */
|
||||
volatile int interrupt_state = 0;
|
||||
|
||||
@@ -2297,11 +2297,7 @@ string_list_dollar_at (list, quoted)
|
||||
|
||||
/* XXX -- why call quote_list if ifs == 0? we can get away without doing
|
||||
it now that quote_escapes quotes spaces */
|
||||
#if 0
|
||||
tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0))
|
||||
#else
|
||||
tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
|
||||
#endif
|
||||
? quote_list (list)
|
||||
: list_quote_escapes (list);
|
||||
|
||||
@@ -2856,8 +2852,9 @@ do_assignment (string)
|
||||
}
|
||||
|
||||
int
|
||||
do_word_assignment (word)
|
||||
do_word_assignment (word, flags)
|
||||
WORD_DESC *word;
|
||||
int flags;
|
||||
{
|
||||
return do_assignment_internal (word, 1);
|
||||
}
|
||||
@@ -4154,7 +4151,13 @@ match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
|
||||
wchar_t wc, *wp, *nwpat, *wp1;
|
||||
size_t len;
|
||||
int mlen;
|
||||
int n, n1;
|
||||
int n, n1, n2, simple;
|
||||
|
||||
simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'[');
|
||||
#if defined (EXTENDED_GLOB)
|
||||
if (extended_glob)
|
||||
simple |= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/
|
||||
#endif
|
||||
|
||||
/* If the pattern doesn't match anywhere in the string, go ahead and
|
||||
short-circuit right away. A minor optimization, saves a bunch of
|
||||
@@ -4184,13 +4187,19 @@ match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
|
||||
return (0);
|
||||
|
||||
mlen = wmatchlen (wpat, wstrlen);
|
||||
|
||||
/* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */
|
||||
switch (mtype)
|
||||
{
|
||||
case MATCH_ANY:
|
||||
for (n = 0; n <= wstrlen; n++)
|
||||
{
|
||||
if (match_pattern_wchar (wpat, wstring + n))
|
||||
#if 1
|
||||
n2 = simple ? (*wpat == wstring[n]) : match_pattern_wchar (wpat, wstring + n);
|
||||
#else
|
||||
n2 = match_pattern_wchar (wpat, wstring + n);
|
||||
#endif
|
||||
if (n2)
|
||||
{
|
||||
#if 0
|
||||
for (n1 = wstrlen; n1 >= n; n1--)
|
||||
@@ -4288,6 +4297,7 @@ match_pattern (string, pat, mtype, sp, ep)
|
||||
size_t n;
|
||||
wchar_t *wstring, *wpat;
|
||||
char **indices;
|
||||
size_t slen, plen, mslen, mplen;
|
||||
#endif
|
||||
|
||||
if (string == 0 || *string == 0 || pat == 0 || *pat == 0)
|
||||
@@ -4296,6 +4306,17 @@ match_pattern (string, pat, mtype, sp, ep)
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1)
|
||||
{
|
||||
#if 0
|
||||
slen = STRLEN (string);
|
||||
mslen = MBSLEN (string);
|
||||
plen = STRLEN (pat);
|
||||
mplen = MBSLEN (pat);
|
||||
if (slen == mslen && plen == mplen)
|
||||
#else
|
||||
if (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0)
|
||||
#endif
|
||||
return (match_upattern (string, pat, mtype, sp, ep));
|
||||
|
||||
n = xdupmbstowcs (&wpat, NULL, pat);
|
||||
if (n == (size_t)-1)
|
||||
return (match_upattern (string, pat, mtype, sp, ep));
|
||||
@@ -5855,34 +5876,6 @@ valid_length_expression (name)
|
||||
legal_identifier (name + 1)); /* ${#PS1} */
|
||||
}
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
size_t
|
||||
mbstrlen (s)
|
||||
const char *s;
|
||||
{
|
||||
size_t clen, nc;
|
||||
mbstate_t mbs, mbsbak;
|
||||
|
||||
nc = 0;
|
||||
memset (&mbs, 0, sizeof (mbs));
|
||||
mbsbak = mbs;
|
||||
while ((clen = mbrlen(s, MB_CUR_MAX, &mbs)) != 0)
|
||||
{
|
||||
if (MB_INVALIDCH(clen))
|
||||
{
|
||||
clen = 1; /* assume single byte */
|
||||
mbs = mbsbak;
|
||||
}
|
||||
|
||||
s += clen;
|
||||
nc++;
|
||||
mbsbak = mbs;
|
||||
}
|
||||
return nc;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Handle the parameter brace expansion that requires us to return the
|
||||
length of a parameter. */
|
||||
static intmax_t
|
||||
@@ -5965,7 +5958,7 @@ parameter_brace_expand_length (name)
|
||||
if (list)
|
||||
dispose_words (list);
|
||||
|
||||
number = MB_STRLEN (t);
|
||||
number = t ? MB_STRLEN (t) : 0;
|
||||
FREE (t);
|
||||
}
|
||||
}
|
||||
@@ -7536,11 +7529,14 @@ param_expand (string, sindex, quoted, expanded_something,
|
||||
is unset, the parameters are separated by ' '; if $IFS is
|
||||
null, the parameters are concatenated. */
|
||||
temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list) : string_list (list);
|
||||
temp1 = quote_string (temp);
|
||||
if (*temp == 0)
|
||||
tflag |= W_HASQUOTEDNULL;
|
||||
free (temp);
|
||||
temp = temp1;
|
||||
if (temp)
|
||||
{
|
||||
temp1 = quote_string (temp);
|
||||
if (*temp == 0)
|
||||
tflag |= W_HASQUOTEDNULL;
|
||||
free (temp);
|
||||
temp = temp1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -8314,7 +8310,7 @@ add_twochars:
|
||||
if (list->next)
|
||||
{
|
||||
#if 0
|
||||
if (quoted_dollar_at && word->flags & W_NOSPLIT2)
|
||||
if (quoted_dollar_at && (word->flags & W_NOSPLIT2))
|
||||
temp = string_list_internal (quote_list (list), " ");
|
||||
else
|
||||
#endif
|
||||
@@ -8352,12 +8348,10 @@ add_twochars:
|
||||
else
|
||||
temp = (char *)NULL;
|
||||
|
||||
#if 0
|
||||
/* We do not want to add quoted nulls to strings that are only
|
||||
partially quoted; we can throw them away. */
|
||||
if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
|
||||
if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
add_quoted_string:
|
||||
|
||||
@@ -9194,7 +9188,7 @@ shell_expand_word_list (tlist, eflags)
|
||||
if (tlist->word->flags & W_ASSIGNASSOC)
|
||||
make_internal_declare (tlist->word->word, "-A");
|
||||
|
||||
t = do_word_assignment (tlist->word);
|
||||
t = do_word_assignment (tlist->word, 0);
|
||||
if (t == 0)
|
||||
{
|
||||
last_command_exit_value = EXECUTION_FAILURE;
|
||||
@@ -9294,7 +9288,7 @@ expand_word_list_internal (list, eflags)
|
||||
for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
|
||||
{
|
||||
this_command_name = (char *)NULL; /* no arithmetic errors */
|
||||
tint = do_word_assignment (temp_list->word);
|
||||
tint = do_word_assignment (temp_list->word, 0);
|
||||
/* Variable assignment errors in non-interactive shells
|
||||
running in Posix.2 mode cause the shell to exit. */
|
||||
if (tint == 0)
|
||||
@@ -9343,7 +9337,7 @@ expand_word_list_internal (list, eflags)
|
||||
if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
|
||||
{
|
||||
sh_wassign_func_t *assign_func;
|
||||
int is_special_builtin;
|
||||
int is_special_builtin, is_builtin_or_func;
|
||||
|
||||
/* If the remainder of the words expand to nothing, Posix.2 requires
|
||||
that the variable and environment assignments affect the shell's
|
||||
@@ -9351,15 +9345,16 @@ expand_word_list_internal (list, eflags)
|
||||
assign_func = new_list ? assign_in_env : do_word_assignment;
|
||||
tempenv_assign_error = 0;
|
||||
|
||||
is_builtin_or_func = (new_list && new_list->word && (find_shell_builtin (new_list->word->word) || find_function (new_list->word->word)));
|
||||
/* Posix says that special builtins exit if a variable assignment error
|
||||
occurs in an assignment preceding it. */
|
||||
is_special_builtin = (posixly_correct && new_list && find_special_builtin (new_list->word->word));
|
||||
is_special_builtin = (posixly_correct && new_list && new_list->word && find_special_builtin (new_list->word->word));
|
||||
|
||||
for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
|
||||
{
|
||||
this_command_name = (char *)NULL;
|
||||
assigning_in_environment = (assign_func == assign_in_env);
|
||||
tint = (*assign_func) (temp_list->word);
|
||||
tint = (*assign_func) (temp_list->word, is_builtin_or_func);
|
||||
assigning_in_environment = 0;
|
||||
/* Variable assignment errors in non-interactive shells running
|
||||
in Posix.2 mode cause the shell to exit. */
|
||||
|
||||
+9392
File diff suppressed because it is too large
Load Diff
@@ -52,6 +52,7 @@
|
||||
#include "mailcheck.h"
|
||||
|
||||
#include "shmbutil.h"
|
||||
#include "typemax.h"
|
||||
|
||||
#include "builtins/getopt.h"
|
||||
#include "builtins/common.h"
|
||||
@@ -2296,11 +2297,7 @@ string_list_dollar_at (list, quoted)
|
||||
|
||||
/* XXX -- why call quote_list if ifs == 0? we can get away without doing
|
||||
it now that quote_escapes quotes spaces */
|
||||
#if 0
|
||||
tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0))
|
||||
#else
|
||||
tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
|
||||
#endif
|
||||
? quote_list (list)
|
||||
: list_quote_escapes (list);
|
||||
|
||||
@@ -2855,8 +2852,9 @@ do_assignment (string)
|
||||
}
|
||||
|
||||
int
|
||||
do_word_assignment (word)
|
||||
do_word_assignment (word, flags)
|
||||
WORD_DESC *word;
|
||||
int flags;
|
||||
{
|
||||
return do_assignment_internal (word, 1);
|
||||
}
|
||||
@@ -4003,6 +4001,7 @@ match_upattern (string, pat, mtype, sp, ep)
|
||||
int c, len, mlen;
|
||||
register char *p, *p1, *npat;
|
||||
char *end;
|
||||
int n1;
|
||||
|
||||
/* If the pattern doesn't match anywhere in the string, go ahead and
|
||||
short-circuit right away. A minor optimization, saves a bunch of
|
||||
@@ -4049,8 +4048,15 @@ match_upattern (string, pat, mtype, sp, ep)
|
||||
for (p1 = end; p1 >= p; p1--)
|
||||
#else
|
||||
p1 = (mlen == -1) ? end : p + mlen;
|
||||
/* extra -1 to handle case of p1 == end */
|
||||
if (p1 - p + mlen - 1 > len)
|
||||
/* p1 - p = length of portion of string to be considered
|
||||
p = current position in string
|
||||
mlen = number of characters consumed by match (-1 for entire string)
|
||||
end = end of string
|
||||
we want to break immediately if the potential match len
|
||||
is greater than the number of characters remaining in the
|
||||
string
|
||||
*/
|
||||
if (p1 > end)
|
||||
break;
|
||||
for ( ; p1 >= p; p1--)
|
||||
#endif
|
||||
@@ -4145,7 +4151,13 @@ match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
|
||||
wchar_t wc, *wp, *nwpat, *wp1;
|
||||
size_t len;
|
||||
int mlen;
|
||||
int n, n1;
|
||||
int n, n1, n2, simple;
|
||||
|
||||
simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'[');
|
||||
#if defined (EXTENDED_GLOB)
|
||||
if (extended_glob)
|
||||
simple |= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/
|
||||
#endif
|
||||
|
||||
/* If the pattern doesn't match anywhere in the string, go ahead and
|
||||
short-circuit right away. A minor optimization, saves a bunch of
|
||||
@@ -4175,13 +4187,19 @@ match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
|
||||
return (0);
|
||||
|
||||
mlen = wmatchlen (wpat, wstrlen);
|
||||
|
||||
/* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */
|
||||
switch (mtype)
|
||||
{
|
||||
case MATCH_ANY:
|
||||
for (n = 0; n <= wstrlen; n++)
|
||||
{
|
||||
if (match_pattern_wchar (wpat, wstring + n))
|
||||
#if 1
|
||||
n2 = simple ? (*wpat == wstring[n]) : match_pattern_wchar (wpat, wstring + n);
|
||||
#else
|
||||
n2 = match_pattern_wchar (wpat, wstring + n);
|
||||
#endif
|
||||
if (n2)
|
||||
{
|
||||
#if 0
|
||||
for (n1 = wstrlen; n1 >= n; n1--)
|
||||
@@ -4279,6 +4297,7 @@ match_pattern (string, pat, mtype, sp, ep)
|
||||
size_t n;
|
||||
wchar_t *wstring, *wpat;
|
||||
char **indices;
|
||||
size_t slen, plen, mslen, mplen;
|
||||
#endif
|
||||
|
||||
if (string == 0 || *string == 0 || pat == 0 || *pat == 0)
|
||||
@@ -4287,6 +4306,13 @@ match_pattern (string, pat, mtype, sp, ep)
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1)
|
||||
{
|
||||
slen = STRLEN (string);
|
||||
mslen = MBSLEN (string);
|
||||
plen = STRLEN (pat);
|
||||
mplen = MBSLEN (pat);
|
||||
if (slen == mslen && plen == mplen)
|
||||
return (match_upattern (string, pat, mtype, sp, ep));
|
||||
|
||||
n = xdupmbstowcs (&wpat, NULL, pat);
|
||||
if (n == (size_t)-1)
|
||||
return (match_upattern (string, pat, mtype, sp, ep));
|
||||
@@ -5846,34 +5872,6 @@ valid_length_expression (name)
|
||||
legal_identifier (name + 1)); /* ${#PS1} */
|
||||
}
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
size_t
|
||||
mbstrlen (s)
|
||||
const char *s;
|
||||
{
|
||||
size_t clen, nc;
|
||||
mbstate_t mbs, mbsbak;
|
||||
|
||||
nc = 0;
|
||||
memset (&mbs, 0, sizeof (mbs));
|
||||
mbsbak = mbs;
|
||||
while ((clen = mbrlen(s, MB_CUR_MAX, &mbs)) != 0)
|
||||
{
|
||||
if (MB_INVALIDCH(clen))
|
||||
{
|
||||
clen = 1; /* assume single byte */
|
||||
mbs = mbsbak;
|
||||
}
|
||||
|
||||
s += clen;
|
||||
nc++;
|
||||
mbsbak = mbs;
|
||||
}
|
||||
return nc;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Handle the parameter brace expansion that requires us to return the
|
||||
length of a parameter. */
|
||||
static intmax_t
|
||||
@@ -5907,7 +5905,7 @@ parameter_brace_expand_length (name)
|
||||
break;
|
||||
case '!':
|
||||
if (last_asynchronous_pid == NO_PID)
|
||||
t = (char *)NULL;
|
||||
t = (char *)NULL; /* XXX - error if set -u set? */
|
||||
else
|
||||
t = itos (last_asynchronous_pid);
|
||||
break;
|
||||
@@ -5956,7 +5954,7 @@ parameter_brace_expand_length (name)
|
||||
if (list)
|
||||
dispose_words (list);
|
||||
|
||||
number = MB_STRLEN (t);
|
||||
number = t ? MB_STRLEN (t) : 0;
|
||||
FREE (t);
|
||||
}
|
||||
}
|
||||
@@ -7527,11 +7525,14 @@ param_expand (string, sindex, quoted, expanded_something,
|
||||
is unset, the parameters are separated by ' '; if $IFS is
|
||||
null, the parameters are concatenated. */
|
||||
temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list) : string_list (list);
|
||||
temp1 = quote_string (temp);
|
||||
if (*temp == 0)
|
||||
tflag |= W_HASQUOTEDNULL;
|
||||
free (temp);
|
||||
temp = temp1;
|
||||
if (temp)
|
||||
{
|
||||
temp1 = quote_string (temp);
|
||||
if (*temp == 0)
|
||||
tflag |= W_HASQUOTEDNULL;
|
||||
free (temp);
|
||||
temp = temp1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -8305,7 +8306,7 @@ add_twochars:
|
||||
if (list->next)
|
||||
{
|
||||
#if 0
|
||||
if (quoted_dollar_at && word->flags & W_NOSPLIT2)
|
||||
if (quoted_dollar_at && (word->flags & W_NOSPLIT2))
|
||||
temp = string_list_internal (quote_list (list), " ");
|
||||
else
|
||||
#endif
|
||||
@@ -8343,12 +8344,10 @@ add_twochars:
|
||||
else
|
||||
temp = (char *)NULL;
|
||||
|
||||
#if 0
|
||||
/* We do not want to add quoted nulls to strings that are only
|
||||
partially quoted; we can throw them away. */
|
||||
if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
|
||||
if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
add_quoted_string:
|
||||
|
||||
@@ -9185,7 +9184,7 @@ shell_expand_word_list (tlist, eflags)
|
||||
if (tlist->word->flags & W_ASSIGNASSOC)
|
||||
make_internal_declare (tlist->word->word, "-A");
|
||||
|
||||
t = do_word_assignment (tlist->word);
|
||||
t = do_word_assignment (tlist->word, 0);
|
||||
if (t == 0)
|
||||
{
|
||||
last_command_exit_value = EXECUTION_FAILURE;
|
||||
@@ -9285,7 +9284,7 @@ expand_word_list_internal (list, eflags)
|
||||
for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
|
||||
{
|
||||
this_command_name = (char *)NULL; /* no arithmetic errors */
|
||||
tint = do_word_assignment (temp_list->word);
|
||||
tint = do_word_assignment (temp_list->word, 0);
|
||||
/* Variable assignment errors in non-interactive shells
|
||||
running in Posix.2 mode cause the shell to exit. */
|
||||
if (tint == 0)
|
||||
@@ -9334,7 +9333,7 @@ expand_word_list_internal (list, eflags)
|
||||
if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
|
||||
{
|
||||
sh_wassign_func_t *assign_func;
|
||||
int is_special_builtin;
|
||||
int is_special_builtin, is_builtin_or_func;
|
||||
|
||||
/* If the remainder of the words expand to nothing, Posix.2 requires
|
||||
that the variable and environment assignments affect the shell's
|
||||
@@ -9342,15 +9341,16 @@ expand_word_list_internal (list, eflags)
|
||||
assign_func = new_list ? assign_in_env : do_word_assignment;
|
||||
tempenv_assign_error = 0;
|
||||
|
||||
is_builtin_or_func = (new_list && new_list->word && (find_shell_builtin (new_list->word->word) || find_function (new_list->word->word)));
|
||||
/* Posix says that special builtins exit if a variable assignment error
|
||||
occurs in an assignment preceding it. */
|
||||
is_special_builtin = (posixly_correct && new_list && find_special_builtin (new_list->word->word));
|
||||
is_special_builtin = (posixly_correct && new_list && new_list->word && find_special_builtin (new_list->word->word));
|
||||
|
||||
for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
|
||||
{
|
||||
this_command_name = (char *)NULL;
|
||||
assigning_in_environment = (assign_func == assign_in_env);
|
||||
tint = (*assign_func) (temp_list->word);
|
||||
tint = (*assign_func) (temp_list->word, is_builtin_or_func);
|
||||
assigning_in_environment = 0;
|
||||
/* Variable assignment errors in non-interactive shells running
|
||||
in Posix.2 mode cause the shell to exit. */
|
||||
|
||||
@@ -124,7 +124,7 @@ extern char *strip_trailing_ifs_whitespace __P((char *, char *, int));
|
||||
splitting on the result of expansion. */
|
||||
extern int do_assignment __P((char *));
|
||||
extern int do_assignment_no_expand __P((char *));
|
||||
extern int do_word_assignment __P((WORD_DESC *));
|
||||
extern int do_word_assignment __P((WORD_DESC *, int));
|
||||
|
||||
/* Append SOURCE to TARGET at INDEX. SIZE is the current amount
|
||||
of space allocated to TARGET. SOURCE can be NULL, in which
|
||||
@@ -260,6 +260,7 @@ extern void unlink_fifo __P((int));
|
||||
|
||||
extern char *copy_fifo_list __P((int *));
|
||||
extern void unlink_new_fifos __P((char *, int));
|
||||
extern void close_new_fifos __P((char *, int));
|
||||
|
||||
extern WORD_LIST *list_string_with_quotes __P((char *));
|
||||
|
||||
|
||||
@@ -260,6 +260,7 @@ extern void unlink_fifo __P((int));
|
||||
|
||||
extern char *copy_fifo_list __P((int *));
|
||||
extern void unlink_new_fifos __P((char *, int));
|
||||
extern void close_new_fifos __P((char *, int));
|
||||
|
||||
extern WORD_LIST *list_string_with_quotes __P((char *));
|
||||
|
||||
@@ -277,6 +278,7 @@ extern char *cond_expand_word __P((WORD_DESC *, int));
|
||||
#define SD_INVERT 0x02 /* look for chars NOT in passed set */
|
||||
#define SD_NOQUOTEDELIM 0x04 /* don't let single or double quotes act as delimiters */
|
||||
#define SD_NOSKIPCMD 0x08 /* don't skip over $(, <(, or >( command/process substitution */
|
||||
#define SD_EXTGLOB 0x10 /* skip over extended globbing patterns if appropriate */
|
||||
|
||||
extern int skip_to_delim __P((char *, int, char *, int));
|
||||
|
||||
|
||||
+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
|
||||
|
||||
|
||||
@@ -166,3 +166,7 @@ graph
|
||||
yes
|
||||
a
|
||||
a
|
||||
val
|
||||
val
|
||||
val
|
||||
no arg passed
|
||||
|
||||
@@ -384,3 +384,5 @@ ${THIS_SH} ./exp1.sub
|
||||
${THIS_SH} ./exp2.sub
|
||||
|
||||
${THIS_SH} ./exp3.sub
|
||||
|
||||
${THIS_SH} ./exp4.sub
|
||||
|
||||
@@ -0,0 +1,386 @@
|
||||
#
|
||||
# A suite of tests for bash word expansions
|
||||
#
|
||||
# This tests parameter and variable expansion, with an empahsis on
|
||||
# proper quoting behavior.
|
||||
#
|
||||
# Chet Ramey
|
||||
|
||||
#
|
||||
# If you comment out the body of this function, you can do a diff against
|
||||
# `expansion-tests.right' to see if the shell is behaving correctly
|
||||
#
|
||||
expect()
|
||||
{
|
||||
echo expect "$@"
|
||||
}
|
||||
|
||||
# Test the substitution quoting characters (CTLESC and CTLNUL) in different
|
||||
# combinations
|
||||
|
||||
expect "<^A>"
|
||||
recho `echo ''`
|
||||
expect "<^A>"
|
||||
recho `echo ""`
|
||||
expect "<^B>"
|
||||
recho `echo ''`
|
||||
expect "<^B>"
|
||||
recho `echo ""`
|
||||
expect "<^A>"
|
||||
recho `echo `
|
||||
expect "<^B>"
|
||||
recho `echo `
|
||||
|
||||
# Test null strings without variable expansion
|
||||
expect "<abcdefgh>"
|
||||
recho abcd""efgh
|
||||
expect "<abcdefgh>"
|
||||
recho abcd''efgh
|
||||
expect "<abcdefgh>"
|
||||
recho ""abcdefgh
|
||||
expect "<abcdefgh>"
|
||||
recho ''abcdefgh
|
||||
expect "<abcd>"
|
||||
recho abcd""
|
||||
expect "<abcd>"
|
||||
recho abcd''
|
||||
|
||||
# Test the quirky behavior of $@ in ""
|
||||
expect nothing
|
||||
recho "$@"
|
||||
expect "< >"
|
||||
recho " $@"
|
||||
expect "<-->"
|
||||
recho "-${@}-"
|
||||
|
||||
# Test null strings with variable expansion that fails
|
||||
expect '<>'
|
||||
recho $xxx""
|
||||
expect '<>'
|
||||
recho ""$xxx
|
||||
expect '<>'
|
||||
recho $xxx''
|
||||
expect '<>'
|
||||
recho ''$xxx
|
||||
expect '<>'
|
||||
recho $xxx""$yyy
|
||||
expect '<>'
|
||||
recho $xxx''$yyy
|
||||
|
||||
# Test null strings with variable expansion that succeeds
|
||||
xxx=abc
|
||||
yyy=def
|
||||
|
||||
expect '<abc>'
|
||||
recho $xxx""
|
||||
expect '<abc>'
|
||||
recho ""$xxx
|
||||
expect '<abc>'
|
||||
recho $xxx''
|
||||
expect '<abc>'
|
||||
recho ''$xxx
|
||||
expect '<abcdef>'
|
||||
recho $xxx""$yyy
|
||||
expect '<abcdef>'
|
||||
recho $xxx''$yyy
|
||||
|
||||
unset xxx yyy
|
||||
|
||||
# Test the unquoted special quoting characters
|
||||
expect "<^A>"
|
||||
recho
|
||||
expect "<^B>"
|
||||
recho
|
||||
expect "<^A>"
|
||||
recho ""
|
||||
expect "<^B>"
|
||||
recho ""
|
||||
expect "<^A>"
|
||||
recho ''
|
||||
expect "<^B>"
|
||||
recho ''
|
||||
|
||||
# Test expansion of a variable that is unset
|
||||
expect nothing
|
||||
recho $xxx
|
||||
expect '<>'
|
||||
recho "$xxx"
|
||||
|
||||
expect nothing
|
||||
recho "$xxx${@}"
|
||||
|
||||
# Test empty string expansion
|
||||
expect '<>'
|
||||
recho ""
|
||||
expect '<>'
|
||||
recho ''
|
||||
|
||||
# Test command substitution with (disabled) history substitution
|
||||
expect '<Hello World!>'
|
||||
# set +H
|
||||
recho "`echo \"Hello world!\"`"
|
||||
|
||||
# Test some shell special characters
|
||||
expect '<`>'
|
||||
recho "\`"
|
||||
expect '<">'
|
||||
recho "\""
|
||||
expect '<\^A>'
|
||||
recho "\"
|
||||
|
||||
expect '<\$>'
|
||||
recho "\\$"
|
||||
|
||||
expect '<\\>'
|
||||
recho "\\\\"
|
||||
|
||||
# This should give argv[1] = a argv[2] = b
|
||||
expect '<a> <b>'
|
||||
FOO=`echo 'a b' | tr ' ' '\012'`
|
||||
recho $FOO
|
||||
|
||||
# This should give argv[1] = ^A argv[2] = ^B
|
||||
expect '<^A> <^B>'
|
||||
FOO=`echo ' ' | tr ' ' '\012'`
|
||||
recho $FOO
|
||||
|
||||
# Test quoted and unquoted globbing characters
|
||||
expect '<**>'
|
||||
recho "*"*
|
||||
|
||||
expect '<\.\./*/>'
|
||||
recho "\.\./*/"
|
||||
|
||||
# Test patterns that come up when the shell quotes funny character
|
||||
# combinations
|
||||
expect '<^A^B^A^B>'
|
||||
recho ''
|
||||
expect '<^A^A>'
|
||||
recho ''
|
||||
expect '<^A^B>'
|
||||
recho ''
|
||||
expect '<^A^A^B>'
|
||||
recho ''
|
||||
|
||||
# More tests of "$@"
|
||||
set abc def ghi jkl
|
||||
expect '< abc> <def> <ghi> <jkl >'
|
||||
recho " $@ "
|
||||
expect '< abc> <def> <ghi> <jkl >'
|
||||
recho "${1+ $@ }"
|
||||
|
||||
set abc def ghi jkl
|
||||
expect '<--abc> <def> <ghi> <jkl-->'
|
||||
recho "--$@--"
|
||||
|
||||
set "a b" cd ef gh
|
||||
expect '<a b> <cd> <ef> <gh>'
|
||||
recho ${1+"$@"}
|
||||
expect '<a b> <cd> <ef> <gh>'
|
||||
recho ${foo:-"$@"}
|
||||
expect '<a b> <cd> <ef> <gh>'
|
||||
recho "${@}"
|
||||
|
||||
expect '< >'
|
||||
recho " "
|
||||
expect '< - >'
|
||||
recho " - "
|
||||
|
||||
# Test combinations of different types of quoting in a fully-quoted string
|
||||
# (so the WHOLLY_QUOTED tests fail and it doesn't get set)
|
||||
expect '</^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/>'
|
||||
recho "/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*"'$'"/\1/"
|
||||
|
||||
# Test the various Posix parameter expansions
|
||||
|
||||
expect '<foo bar>'
|
||||
recho "${x:-$(echo "foo bar")}"
|
||||
expect '<foo> <bar>'
|
||||
recho ${x:-$(echo "foo bar")}
|
||||
|
||||
unset X
|
||||
expect '<abc>'
|
||||
recho ${X:=abc}
|
||||
expect '<abc>'
|
||||
recho $X
|
||||
|
||||
set a b c
|
||||
expect '<posix>'
|
||||
recho ${3:+posix}
|
||||
|
||||
POSIX=/usr/posix
|
||||
expect '<10>'
|
||||
recho ${#POSIX}
|
||||
|
||||
# remove shortest trailing match
|
||||
x=file.c
|
||||
expect '<file.o>'
|
||||
recho ${x%.c}.o
|
||||
|
||||
# remove longest trailing match
|
||||
x=posix/src/std
|
||||
expect '<posix>'
|
||||
recho ${x%%/*}
|
||||
|
||||
# remove shortest leading pattern
|
||||
x=$HOME/src/cmd
|
||||
expect '</src/cmd>'
|
||||
recho ${x#$HOME}
|
||||
|
||||
# remove longest leading pattern
|
||||
x=/one/two/three
|
||||
expect '<three>'
|
||||
recho ${x##*/}
|
||||
|
||||
# pattern removal of patterns that don't match
|
||||
z=abcdef
|
||||
|
||||
expect '<abcdef>'
|
||||
recho ${z#xyz}
|
||||
expect '<abcdef>'
|
||||
recho ${z##xyz}
|
||||
|
||||
expect '<abcdef>'
|
||||
recho ${z%xyz}
|
||||
expect '<abcdef>'
|
||||
recho ${z%%xyz}
|
||||
|
||||
# Command substitution and the quirky differences between `` and $()
|
||||
|
||||
expect '<\$x>'
|
||||
recho '\$x'
|
||||
|
||||
expect '<$x>'
|
||||
recho `echo '\$x'`
|
||||
|
||||
expect '<\$x>'
|
||||
recho $(echo '\$x')
|
||||
|
||||
# The difference between $* "$*" and "$@"
|
||||
|
||||
set "abc" "def ghi" "jkl"
|
||||
|
||||
expect '<abc> <def> <ghi> <jkl>'
|
||||
recho $*
|
||||
|
||||
expect '<abc def ghi jkl>'
|
||||
recho "$*"
|
||||
|
||||
OIFS="$IFS"
|
||||
IFS=":$IFS"
|
||||
|
||||
# The special behavior of "$*", using the first character of $IFS as separator
|
||||
expect '<abc:def ghi:jkl>'
|
||||
recho "$*"
|
||||
|
||||
IFS="$OIFS"
|
||||
|
||||
expect '<abc> <def ghi> <jkl>'
|
||||
recho "$@"
|
||||
|
||||
expect '<xxabc> <def ghi> <jklyy>'
|
||||
recho "xx$@yy"
|
||||
|
||||
expect '<abc> <def ghi> <jklabc> <def ghi> <jkl>'
|
||||
recho "$@$@"
|
||||
|
||||
foo=abc
|
||||
bar=def
|
||||
|
||||
expect '<abcdef>'
|
||||
recho "$foo""$bar"
|
||||
|
||||
unset foo
|
||||
set $foo bar '' xyz "$foo" abc
|
||||
|
||||
expect '<bar> <> <xyz> <> <abc>'
|
||||
recho "$@"
|
||||
|
||||
# More tests of quoting and deferred evaluation
|
||||
|
||||
foo=10 x=foo
|
||||
y='$'$x
|
||||
expect '<$foo>'
|
||||
recho $y
|
||||
eval y='$'$x
|
||||
expect '<10>'
|
||||
recho $y
|
||||
|
||||
# case statements
|
||||
|
||||
NL='
|
||||
'
|
||||
x='ab
|
||||
cd'
|
||||
|
||||
expect '<newline expected>'
|
||||
case "$x" in
|
||||
*$NL*) recho "newline expected" ;;
|
||||
esac
|
||||
|
||||
expect '<got it>'
|
||||
case \? in
|
||||
*"?"*) recho "got it" ;;
|
||||
esac
|
||||
|
||||
expect '<got it>'
|
||||
case \? in
|
||||
*\?*) recho "got it" ;;
|
||||
esac
|
||||
|
||||
set one two three four five
|
||||
expect '<one> <three> <five>'
|
||||
recho $1 $3 ${5} $8 ${9}
|
||||
|
||||
# length tests on positional parameters and some special parameters
|
||||
|
||||
expect '<5> <5>'
|
||||
recho $# ${#}
|
||||
expect '<3>'
|
||||
recho ${#1}
|
||||
expect '<1>'
|
||||
recho ${##}
|
||||
expect '<1>'
|
||||
recho ${#?}
|
||||
expect '<5>'
|
||||
recho ${#@}
|
||||
expect '<5>'
|
||||
recho ${#*}
|
||||
expect '<5>'
|
||||
recho "${#@}"
|
||||
expect '<5>'
|
||||
recho "${#*}"
|
||||
|
||||
expect '<42>'
|
||||
recho $((28 + 14))
|
||||
expect '<26>'
|
||||
recho $[ 13 * 2 ]
|
||||
|
||||
expect '<\>'
|
||||
recho `echo \\\\`
|
||||
|
||||
expect '<~>'
|
||||
recho '~'
|
||||
|
||||
expect nothing
|
||||
recho $!
|
||||
expect nothing
|
||||
recho ${!}
|
||||
|
||||
# test word splitting of assignment statements not preceding a command
|
||||
a="a b c d e"
|
||||
declare b=$a
|
||||
expect '<a> <b> <c> <d> <e>'
|
||||
recho $b
|
||||
|
||||
a="a?b?c"
|
||||
|
||||
echo ${a//\\?/ }
|
||||
|
||||
echo ${a//\?/ }
|
||||
|
||||
${THIS_SH} ./exp1.sub
|
||||
|
||||
${THIS_SH} ./exp2.sub
|
||||
|
||||
${THIS_SH} ./exp3.sub
|
||||
@@ -0,0 +1,10 @@
|
||||
f=" val" e=
|
||||
echo "$e"$f
|
||||
echo $e$f
|
||||
echo "$e""$f"
|
||||
|
||||
if [[ "$1"x == x ]] ; then
|
||||
echo "no arg passed"
|
||||
exit 1
|
||||
fi
|
||||
echo "$1"x | cat -v
|
||||
@@ -11,3 +11,9 @@ aéb
|
||||
-абвгдежзиклмноп - 16
|
||||
-абвгдежзиклмноп- 15
|
||||
-абвгд- 5
|
||||
1,0000
|
||||
1.0000
|
||||
1.0000
|
||||
1.0000
|
||||
1.0000
|
||||
1,0000
|
||||
|
||||
@@ -39,3 +39,6 @@ printf '%s' "$*" | od -b
|
||||
|
||||
# display differences make this problematic
|
||||
${THIS_SH} ./intl1.sub
|
||||
|
||||
# this tests both international handling in printf and temporary environments
|
||||
${THIS_SH} ./intl2.sub
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
export LC_ALL=en_US.UTF-8
|
||||
|
||||
a=$'\303\251'
|
||||
|
||||
echo "$a"
|
||||
|
||||
echo ${#a}
|
||||
|
||||
b=$'A\303\251B'
|
||||
|
||||
echo "$b"
|
||||
|
||||
echo ${b: -1}
|
||||
|
||||
c=AeB
|
||||
|
||||
echo ${c: -1}
|
||||
|
||||
unset a
|
||||
a=$(printf '%b' 'A\303\251B')
|
||||
IFS=$(printf '%b' '\303\251')
|
||||
|
||||
case "$a" in
|
||||
"A${IFS}B") echo ok 1 ;;
|
||||
*) echo bad 1 ;;
|
||||
esac
|
||||
|
||||
set $a
|
||||
|
||||
case $1 in
|
||||
A) echo ok 2 ;;
|
||||
*) echo bad 2 ;;
|
||||
esac
|
||||
|
||||
set a b
|
||||
|
||||
printf '%s\n' "$*"
|
||||
printf '%s' "$*" | od -b
|
||||
|
||||
# display differences make this problematic
|
||||
${THIS_SH} ./intl1.sub
|
||||
@@ -0,0 +1,11 @@
|
||||
unset LC_ALL LC_NUMERIC
|
||||
export LANG=de_DE.UTF-8
|
||||
printf '%.4f\n' 1
|
||||
|
||||
LANG=C printf '%.4f\n' 1
|
||||
LANG=C /usr/bin/printf '%.4f\n' 1
|
||||
|
||||
env LANG=C printf '%.4f\n' 1
|
||||
(LANG=C; printf '%.4f\n' 1)
|
||||
|
||||
printf '%.4f\n' 1
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "unwind_prot.h"
|
||||
#include "quit.h"
|
||||
#include "sig.h"
|
||||
#include "error.h" /* for internal_warning */
|
||||
|
||||
/* Structure describing a saved variable and the value to restore it to. */
|
||||
typedef struct {
|
||||
|
||||
+38
-9
@@ -1235,10 +1235,6 @@ static int seeded_subshell = 0;
|
||||
static int
|
||||
brand ()
|
||||
{
|
||||
#if 0
|
||||
rseed = rseed * 1103515245 + 12345;
|
||||
return ((unsigned int)((rseed >> 16) & 32767)); /* was % 32768 */
|
||||
#else
|
||||
/* From "Random number generators: good ones are hard to find",
|
||||
Park and Miller, Communications of the ACM, vol. 31, no. 10,
|
||||
October 1988, p. 1195. filtered through FreeBSD */
|
||||
@@ -1254,7 +1250,6 @@ brand ()
|
||||
rseed += 0x7fffffff;
|
||||
#endif
|
||||
return ((unsigned int)(rseed & 32767)); /* was % 32768 */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Set the random number generator seed to SEED. */
|
||||
@@ -2491,8 +2486,9 @@ bind_function_def (name, value)
|
||||
responsible for moving the main temporary env to one of the other
|
||||
temporary environments. The expansion code in subst.c calls this. */
|
||||
int
|
||||
assign_in_env (word)
|
||||
assign_in_env (word, flags)
|
||||
WORD_DESC *word;
|
||||
int flags;
|
||||
{
|
||||
int offset;
|
||||
char *name, *temp, *value;
|
||||
@@ -2550,8 +2546,13 @@ assign_in_env (word)
|
||||
|
||||
array_needs_making = 1;
|
||||
|
||||
#if 0
|
||||
if (ifsname (name))
|
||||
setifs (var);
|
||||
else
|
||||
#endif
|
||||
if (flags)
|
||||
stupidly_hack_special_variables (name);
|
||||
|
||||
if (echo_command_at_execute)
|
||||
/* The Korn shell prints the `+ ' in front of assignment statements,
|
||||
@@ -3271,6 +3272,9 @@ find_tempenv_variable (name)
|
||||
return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL);
|
||||
}
|
||||
|
||||
char **tempvar_list;
|
||||
int tvlist_ind;
|
||||
|
||||
/* Push the variable described by (SHELL_VAR *)DATA down to the next
|
||||
variable context from the temporary environment. */
|
||||
static void
|
||||
@@ -3306,6 +3310,9 @@ push_temp_var (data)
|
||||
}
|
||||
v->attributes |= var->attributes;
|
||||
|
||||
if (find_special_var (var->name) >= 0)
|
||||
tempvar_list[tvlist_ind++] = savestring (var->name);
|
||||
|
||||
dispose_variable (var);
|
||||
}
|
||||
|
||||
@@ -3319,24 +3326,46 @@ propagate_temp_var (data)
|
||||
if (tempvar_p (var) && (var->attributes & att_propagate))
|
||||
push_temp_var (data);
|
||||
else
|
||||
dispose_variable (var);
|
||||
{
|
||||
if (find_special_var (var->name) >= 0)
|
||||
tempvar_list[tvlist_ind++] = savestring (var->name);
|
||||
dispose_variable (var);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free the storage used in the hash table for temporary
|
||||
environment variables. PUSHF is a function to be called
|
||||
to free each hash table entry. It takes care of pushing variables
|
||||
to previous scopes if appropriate. */
|
||||
to previous scopes if appropriate. PUSHF stores names of variables
|
||||
that require special handling (e.g., IFS) on tempvar_list, so this
|
||||
function can call stupidly_hack_special_variables on all the
|
||||
variables in the list when the temporary hash table is destroyed. */
|
||||
static void
|
||||
dispose_temporary_env (pushf)
|
||||
sh_free_func_t *pushf;
|
||||
{
|
||||
int i;
|
||||
|
||||
tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1);
|
||||
tempvar_list[tvlist_ind = 0] = 0;
|
||||
|
||||
hash_flush (temporary_env, pushf);
|
||||
hash_dispose (temporary_env);
|
||||
temporary_env = (HASH_TABLE *)NULL;
|
||||
|
||||
tempvar_list[tvlist_ind] = 0;
|
||||
|
||||
array_needs_making = 1;
|
||||
|
||||
sv_ifs ("IFS"); /* XXX here for now */
|
||||
#if 0
|
||||
sv_ifs ("IFS"); /* XXX here for now -- check setifs in assign_in_env */
|
||||
#endif
|
||||
for (i = 0; i < tvlist_ind; i++)
|
||||
stupidly_hack_special_variables (tempvar_list[i]);
|
||||
|
||||
strvec_dispose (tempvar_list);
|
||||
tempvar_list = 0;
|
||||
tvlist_ind = 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+40
-11
@@ -83,7 +83,7 @@ extern char **environ;
|
||||
|
||||
/* Variables used here and defined in other files. */
|
||||
extern int posixly_correct;
|
||||
extern int line_number;
|
||||
extern int line_number, line_number_base;
|
||||
extern int subshell_environment, indirection_level, subshell_level;
|
||||
extern int build_version, patch_level;
|
||||
extern int expanding_redir;
|
||||
@@ -1235,10 +1235,6 @@ static int seeded_subshell = 0;
|
||||
static int
|
||||
brand ()
|
||||
{
|
||||
#if 0
|
||||
rseed = rseed * 1103515245 + 12345;
|
||||
return ((unsigned int)((rseed >> 16) & 32767)); /* was % 32768 */
|
||||
#else
|
||||
/* From "Random number generators: good ones are hard to find",
|
||||
Park and Miller, Communications of the ACM, vol. 31, no. 10,
|
||||
October 1988, p. 1195. filtered through FreeBSD */
|
||||
@@ -1254,7 +1250,6 @@ brand ()
|
||||
rseed += 0x7fffffff;
|
||||
#endif
|
||||
return ((unsigned int)(rseed & 32767)); /* was % 32768 */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Set the random number generator seed to SEED. */
|
||||
@@ -1336,7 +1331,7 @@ assign_lineno (var, value, unused, key)
|
||||
|
||||
if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
|
||||
new_value = 0;
|
||||
line_number = new_value;
|
||||
line_number = line_number_base = new_value;
|
||||
return var;
|
||||
}
|
||||
|
||||
@@ -2491,8 +2486,9 @@ bind_function_def (name, value)
|
||||
responsible for moving the main temporary env to one of the other
|
||||
temporary environments. The expansion code in subst.c calls this. */
|
||||
int
|
||||
assign_in_env (word)
|
||||
assign_in_env (word, flags)
|
||||
WORD_DESC *word;
|
||||
int flags;
|
||||
{
|
||||
int offset;
|
||||
char *name, *temp, *value;
|
||||
@@ -2550,8 +2546,13 @@ assign_in_env (word)
|
||||
|
||||
array_needs_making = 1;
|
||||
|
||||
#if 0
|
||||
if (ifsname (name))
|
||||
setifs (var);
|
||||
else
|
||||
#endif
|
||||
if (flags)
|
||||
stupidly_hack_special_variables (name);
|
||||
|
||||
if (echo_command_at_execute)
|
||||
/* The Korn shell prints the `+ ' in front of assignment statements,
|
||||
@@ -3271,6 +3272,9 @@ find_tempenv_variable (name)
|
||||
return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL);
|
||||
}
|
||||
|
||||
char **tempvar_list;
|
||||
int tvlist_ind;
|
||||
|
||||
/* Push the variable described by (SHELL_VAR *)DATA down to the next
|
||||
variable context from the temporary environment. */
|
||||
static void
|
||||
@@ -3306,6 +3310,9 @@ push_temp_var (data)
|
||||
}
|
||||
v->attributes |= var->attributes;
|
||||
|
||||
if (find_special_var (var->name))
|
||||
tempvar_list[tvlist_ind++] = savestring (var->name);
|
||||
|
||||
dispose_variable (var);
|
||||
}
|
||||
|
||||
@@ -3319,24 +3326,46 @@ propagate_temp_var (data)
|
||||
if (tempvar_p (var) && (var->attributes & att_propagate))
|
||||
push_temp_var (data);
|
||||
else
|
||||
dispose_variable (var);
|
||||
{
|
||||
if (find_special_var (var->name))
|
||||
tempvar_list[tvlist_ind++] = savestring (var->name);
|
||||
dispose_variable (var);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free the storage used in the hash table for temporary
|
||||
environment variables. PUSHF is a function to be called
|
||||
to free each hash table entry. It takes care of pushing variables
|
||||
to previous scopes if appropriate. */
|
||||
to previous scopes if appropriate. PUSHF stores names of variables
|
||||
that require special handling (e.g., IFS) on tempvar_list, so this
|
||||
function can call stupidly_hack_special_variables on all the
|
||||
variables in the list when the temporary hash table is destroyed. */
|
||||
static void
|
||||
dispose_temporary_env (pushf)
|
||||
sh_free_func_t *pushf;
|
||||
{
|
||||
int i;
|
||||
|
||||
tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1);
|
||||
tempvar_list[tvlist_ind = 0] = 0;
|
||||
|
||||
hash_flush (temporary_env, pushf);
|
||||
hash_dispose (temporary_env);
|
||||
temporary_env = (HASH_TABLE *)NULL;
|
||||
|
||||
tempvar_list[tvlist_ind] = 0;
|
||||
|
||||
array_needs_making = 1;
|
||||
|
||||
sv_ifs ("IFS"); /* XXX here for now */
|
||||
#if 0
|
||||
sv_ifs ("IFS"); /* XXX here for now -- check setifs in assign_in_env */
|
||||
#endif
|
||||
for (i = 0; i < tvlist_ind; i++)
|
||||
stupidly_hack_special_variables (tempvar_list[i]);
|
||||
|
||||
strvec_dispose (tempvar_list);
|
||||
tempvar_list = 0;
|
||||
tvlist_ind = 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+1
-1
@@ -270,7 +270,7 @@ extern SHELL_VAR *bind_variable_value __P((SHELL_VAR *, char *, int));
|
||||
extern SHELL_VAR *bind_int_variable __P((char *, char *));
|
||||
extern SHELL_VAR *bind_var_to_int __P((char *, intmax_t));
|
||||
|
||||
extern int assign_in_env __P((WORD_DESC *));
|
||||
extern int assign_in_env __P((WORD_DESC *, int));
|
||||
|
||||
extern int unbind_variable __P((const char *));
|
||||
extern int unbind_func __P((const char *));
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* variables.h -- data structures for shell variables. */
|
||||
|
||||
/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1987-2010 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/* A Bison parser, made by GNU Bison 2.0. */
|
||||
/* A Bison parser, made by GNU Bison 2.3. */
|
||||
|
||||
/* Skeleton parser for Yacc-like parsing with Bison,
|
||||
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
|
||||
/* Skeleton interface for Bison's Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -15,13 +17,21 @@
|
||||
|
||||
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-1307, USA. */
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* As a special exception, when this file is copied by Bison into a
|
||||
Bison output file, you may use that output file without restriction.
|
||||
This special exception was added by the Free Software Foundation
|
||||
in version 1.24 of Bison. */
|
||||
/* As a special exception, you may create a larger work that contains
|
||||
part or all of the Bison parser skeleton and distribute that work
|
||||
under terms of your choice, so long as that work isn't itself a
|
||||
parser generator using the skeleton or a modified version thereof
|
||||
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||
the parser skeleton itself, you may (at your option) remove this
|
||||
special exception, which will cause the skeleton and the resulting
|
||||
Bison output files to be licensed under the GNU General Public
|
||||
License without this special exception.
|
||||
|
||||
This special exception was added by the Free Software Foundation in
|
||||
version 2.2 of Bison. */
|
||||
|
||||
/* Tokens. */
|
||||
#ifndef YYTOKENTYPE
|
||||
@@ -78,6 +88,7 @@
|
||||
yacc_EOF = 304
|
||||
};
|
||||
#endif
|
||||
/* Tokens. */
|
||||
#define IF 258
|
||||
#define THEN 259
|
||||
#define ELSE 260
|
||||
@@ -129,9 +140,10 @@
|
||||
|
||||
|
||||
|
||||
#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
typedef union YYSTYPE
|
||||
#line 323 "parse.y"
|
||||
typedef union YYSTYPE {
|
||||
{
|
||||
WORD_DESC *word; /* the word that we read. */
|
||||
int number; /* the number that we read. */
|
||||
WORD_LIST *word_list;
|
||||
@@ -139,9 +151,10 @@ typedef union YYSTYPE {
|
||||
REDIRECT *redirect;
|
||||
ELEMENT element;
|
||||
PATTERN_LIST *pattern;
|
||||
} YYSTYPE;
|
||||
/* Line 1274 of yacc.c. */
|
||||
#line 145 "y.tab.h"
|
||||
}
|
||||
/* Line 1489 of yacc.c. */
|
||||
#line 157 "y.tab.h"
|
||||
YYSTYPE;
|
||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
@@ -149,5 +162,3 @@ typedef union YYSTYPE {
|
||||
|
||||
extern YYSTYPE yylval;
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user