summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Doc/Zsh/options.yo27
-rw-r--r--Src/options.c3
-rw-r--r--Src/utils.c15
-rw-r--r--Src/zsh.h1
-rw-r--r--Test/A03quoting.ztst22
5 files changed, 65 insertions, 3 deletions
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index d334f5829..467c92723 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -1891,6 +1891,33 @@ If multibyte character support is not compiled into the shell this option is
ignored; all octets with the top bit set may be used in identifiers.
This is non-standard but is the traditional zsh behaviour.
)
+pindex(POSIX_STRINGS)
+pindex(NO_POSIX_STRINGS)
+pindex(POSIXSTRINGS)
+pindex(NOPOSIXSTRINGS)
+cindex(discarding embedded nulls in $'...')
+cindex(embedded nulls, in $'...')
+cindex(nulls, embedded in $'...')
+item(tt(POSIX_STRINGS) <K> <S>)(
+This option affects processing of quoted strings. Currently it only
+affects the behaviour of null characters, i.e. character 0 in the
+portable character set corresponding to US ASCII.
+
+When this option is not set, null characters embedded within strings
+of the form tt($')var(...)tt(') are treated as ordinary characters. The
+entire string is maintained within the shell and output to files where
+necessary, although owing to restrictions of the library interface
+the string is truncated at the null character in file names, environment
+variables, or in arguments to external programs.
+
+When this option is set, the tt($')var(...)tt(') expression is truncated at
+the null character. Note that remaining parts of the same string
+beyond the termination of the quotes are not trunctated.
+
+For example, the command line argument tt(a$'b\0c'd) is treated with
+the option off as the characters tt(a), tt(b), null, tt(c), tt(d),
+and with the option on as the characters tt(a), tt(b), tt(d).
+)
pindex(POSIX_TRAPS)
pindex(NO_POSIX_TRAPS)
pindex(POSIXTRAPS)
diff --git a/Src/options.c b/Src/options.c
index a2d5e0855..00d552ad5 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -205,7 +205,8 @@ static struct optname optns[] = {
{{NULL, "posixcd", OPT_EMULATE|OPT_BOURNE}, POSIXCD},
{{NULL, "posixidentifiers", OPT_EMULATE|OPT_BOURNE}, POSIXIDENTIFIERS},
{{NULL, "posixjobs", OPT_EMULATE|OPT_BOURNE}, POSIXJOBS},
-{{NULL, "posixtraps", OPT_EMULATE|OPT_BOURNE}, POSIXTRAPS},
+{{NULL, "posixstrings", OPT_EMULATE|OPT_BOURNE}, POSIXSTRINGS},
+{{NULL, "posixtraps", OPT_EMULATE|OPT_BOURNE}, POSIXTRAPS},
{{NULL, "printeightbit", 0}, PRINTEIGHTBIT},
{{NULL, "printexitvalue", 0}, PRINTEXITVALUE},
{{NULL, "privileged", OPT_SPECIAL}, PRIVILEGED},
diff --git a/Src/utils.c b/Src/utils.c
index e788051cf..2e30c176a 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -5200,7 +5200,7 @@ getkeystring(char *s, int *len, int how, int *misc)
char *buf, tmp[1];
char *t, *tdest = NULL, *u = NULL, *sstart = s, *tbuf = NULL;
char svchar = '\0';
- int meta = 0, control = 0;
+ int meta = 0, control = 0, ignoring = 0;
int i;
#if defined(HAVE_WCHAR_H) && defined(HAVE_WCTOMB) && defined(__STDC_ISO_10646__)
wint_t wval;
@@ -5623,11 +5623,22 @@ getkeystring(char *s, int *len, int how, int *misc)
if (how & GETKEY_DOLLAR_QUOTE) {
char *t2;
for (t2 = tbuf; t2 < t; t2++) {
+ /*
+ * In POSIX mode, an embedded NULL is discarded and
+ * terminates processing. It just does, that's why.
+ */
+ if (isset(POSIXSTRINGS)) {
+ if (*t2 == '\0')
+ ignoring = 1;
+ if (ignoring)
+ break;
+ }
if (imeta(*t2)) {
*tdest++ = Meta;
*tdest++ = *t2 ^ 32;
- } else
+ } else {
*tdest++ = *t2;
+ }
}
/*
* Reset use of temporary buffer.
diff --git a/Src/zsh.h b/Src/zsh.h
index cc50826e5..1d793741a 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1992,6 +1992,7 @@ enum {
POSIXCD,
POSIXIDENTIFIERS,
POSIXJOBS,
+ POSIXSTRINGS,
POSIXTRAPS,
PRINTEIGHTBIT,
PRINTEXITVALUE,
diff --git a/Test/A03quoting.ztst b/Test/A03quoting.ztst
index f0f86e0b2..0cf0e8a02 100644
--- a/Test/A03quoting.ztst
+++ b/Test/A03quoting.ztst
@@ -42,6 +42,7 @@
unsetopt rcquotes
0:Yes RC_QUOTES with single quotes
>'
+# ' Deconfuse Emacs quoting rules
print '<\u0041>'
printf '%s\n' $'<\u0042>'
@@ -52,3 +53,24 @@
><B>
><C>
><D>
+
+ null1="$(print -r a$'b\0c'd)"
+ null2="$(setopt posixstrings; print -r a$'b\0c'd)"
+ for string in $null1 $null2; do
+ print ":"
+ for (( i = 1; i <= $#string; i++ )); do
+ char=$string[$i]
+ print $(( [#16] #char ))
+ done
+ done
+0:Embedded null characters in $'...' strings.
+>:
+>16#61
+>16#62
+>16#0
+>16#63
+>16#64
+>:
+>16#61
+>16#62
+>16#64