From 147cedfb6fa2973f6ff6ce69d63d98096b4e2604 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 27 May 2010 18:57:34 +0000 Subject: 27965, 27966: Improve ${(q)...}: newline appears as $'\n;, --- ChangeLog | 7 ++++++- Src/builtin.c | 2 +- Src/subst.c | 6 +++--- Src/utils.c | 39 ++++++++++++++++++++++++++++++--------- Src/zsh.h | 6 +++++- 5 files changed, 45 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7fd3d0c1e..e2f427227 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2010-05-27 Peter Stephenson + * 27965 plus as per 27966: Src/builtin.c, Src/subst.c, + Src/utils.c, Src/zsh.h: Use $'\n' quoting instead of literal + newline for ${(q)...} to avoid lines getting split unexpectedly. + Quote empty strings as ''. + * 27976: Doc/Zsh/expn.yo: add yet more to the my-brain-hurts description of how parameter expansion is ordered. @@ -13164,5 +13169,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.4983 $ +* $Revision: 1.4984 $ ***************************************************** diff --git a/Src/builtin.c b/Src/builtin.c index 3f26f0304..e9e8e3bff 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -4233,7 +4233,7 @@ bin_print(char *name, char **args, Options ops, int func) break; case 'q': stringval = curarg ? - quotestring(curarg, NULL, QT_BACKSLASH) : &nullstr; + quotestring(curarg, NULL, QT_BACKSLASH_SHOWNULL) : &nullstr; *d = 's'; print_val(stringval); break; diff --git a/Src/subst.c b/Src/subst.c index 80a56410a..304add6f9 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -2896,7 +2896,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) } } else for (; *ap; ap++) - *ap = quotestring(*ap, NULL, QT_BACKSLASH); + *ap = quotestring(*ap, NULL, QT_BACKSLASH_SHOWNULL); } else { int one = noerrs, oef = errflag, haserr = 0; @@ -2933,7 +2933,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) if (quotetype == QT_DOLLARS) val[0] = '$'; } else - val = quotestring(val, NULL, QT_BACKSLASH); + val = quotestring(val, NULL, QT_BACKSLASH_SHOWNULL); } else { int one = noerrs, oef = errflag, haserr; @@ -3490,7 +3490,7 @@ modify(char **str, char **ptr) subst(©, hsubl, hsubr, gbal); break; case 'q': - copy = quotestring(copy, NULL, QT_BACKSLASH); + copy = quotestring(copy, NULL, QT_BACKSLASH_SHOWNULL); break; case 'Q': { diff --git a/Src/utils.c b/Src/utils.c index 1d7b3109a..184b2f354 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -4576,7 +4576,7 @@ quotestring(const char *s, char **e, int instring) char *v; int alloclen; char *buf; - int sf = 0; + int sf = 0, shownull; /* * quotesub is used with QT_SINGLE_OPTIONAL. * quotesub = 0: mechanism not active @@ -4585,11 +4585,18 @@ quotestring(const char *s, char **e, int instring) * quotesub = 2: mechanism active, added opening "'"; need * closing "'". */ - int quotesub = 0; + int quotesub = 0, slen; char *quotestart; convchar_t cc; const char *uend; + slen = strlen(s); + if (instring == QT_BACKSLASH_SHOWNULL) { + shownull = 1; + instring = QT_BACKSLASH; + } else { + shownull = 0; + } switch (instring) { case QT_BACKSLASH: @@ -4598,21 +4605,24 @@ quotestring(const char *s, char **e, int instring) * Keep memory usage within limits by allocating temporary * storage and using heap for correct size at end. */ - alloclen = strlen(s) * 7 + 1; + alloclen = slen * 7 + 1; + if (!*s && shownull) + alloclen += 2; /* for '' */ break; case QT_SINGLE_OPTIONAL: /* * Here, we may need to add single quotes. */ - alloclen = strlen(s) * 4 + 3; + alloclen = slen * 4 + 3; quotesub = 1; break; default: - alloclen = strlen(s) * 4 + 1; + alloclen = slen * 4 + 1; break; } + tt = quotestart = v = buf = zshcalloc(alloclen); DPUTS(instring < QT_BACKSLASH || instring == QT_BACKTICK || @@ -4659,6 +4669,13 @@ quotestring(const char *s, char **e, int instring) } else { + if (shownull) { + /* We can't show an empty string with just backslash quoting. */ + if (!*u) { + *v++ = '\''; + *v++ = '\''; + } + } /* * Here there are syntactic special characters, so * we start by going through bytewise. @@ -4771,15 +4788,19 @@ quotestring(const char *s, char **e, int instring) continue; } else if (*u == '\n' || (instring == QT_SINGLE && *u == '\'')) { - if (unset(RCQUOTES)) { + if (*u == '\n') { + *v++ = '$'; + *v++ = '\''; + *v++ = '\\'; + *v++ = 'n'; + *v++ = '\''; + } else if (unset(RCQUOTES)) { *v++ = '\''; if (*u == '\'') *v++ = '\\'; *v++ = *u; *v++ = '\''; - } else if (*u == '\n') - *v++ = '"', *v++ = '\n', *v++ = '"'; - else + } else *v++ = '\'', *v++ = '\''; u++; continue; diff --git a/Src/zsh.h b/Src/zsh.h index 1b1175cb2..77281aa75 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -218,7 +218,11 @@ enum { * Single quotes, but the default is not to quote unless necessary. * This is only useful as an argument to quotestring(). */ - QT_SINGLE_OPTIONAL + QT_SINGLE_OPTIONAL, + /* + * As QT_BACKSLASH, but a NULL string is shown as ''. + */ + QT_BACKSLASH_SHOWNULL }; #define QT_IS_SINGLE(x) ((x) == QT_SINGLE || (x) == QT_SINGLE_OPTIONAL) -- cgit 1.4.1