summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2006-10-05 21:53:26 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2006-10-05 21:53:26 +0000
commit289b14113b1675b7b8d844b1f41aff1e2f3a5146 (patch)
tree89020810aae313b94a061156efcc557d7251ba16 /Src
parent298a8b8130bd3f515c1aa9f8fcd901c878cbb668 (diff)
downloadzsh-289b14113b1675b7b8d844b1f41aff1e2f3a5146.tar.gz
zsh-289b14113b1675b7b8d844b1f41aff1e2f3a5146.zip
22819: improved internal use of string quotation,
plus completion bug fix with RCQUOTES
Diffstat (limited to 'Src')
-rw-r--r--Src/Zle/compcore.c163
-rw-r--r--Src/Zle/compctl.c95
-rw-r--r--Src/Zle/complete.c24
-rw-r--r--Src/Zle/computil.c7
-rw-r--r--Src/Zle/zle_tricky.c98
-rw-r--r--Src/builtin.c3
-rw-r--r--Src/subst.c36
-rw-r--r--Src/text.c2
-rw-r--r--Src/utils.c57
-rw-r--r--Src/zsh.h35
10 files changed, 377 insertions, 143 deletions
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index 8aa44d319..e397e776b 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -303,11 +303,13 @@ do_completion(UNUSED(Hookdef dummy), Compldat dat)
matchers = newlinklist();
zsfree(compqstack);
- compqstack = ztrdup("\\");
- if (instring == 2)
- compqstack[0] = '"';
- else if (instring)
- compqstack[0] = '\'';
+ compqstack = zalloc(2);
+ /*
+ * It looks like we may need to do stuff with backslashes even
+ * if instring is QT_NONE.
+ */
+ *compqstack = (instring == QT_NONE) ? QT_BACKSLASH : (char)instring;
+ compqstack[1] = '\0';
hasunqu = 0;
useline = (wouldinstab ? -1 : (lst != COMP_LIST_COMPLETE));
@@ -650,13 +652,22 @@ callcompfunc(char *s, char *fn)
compredirect = ztrdup(compredirect);
zsfree(compquote);
zsfree(compquoting);
- if (instring) {
- if (instring == 1) {
+ if (instring > QT_BACKSLASH) {
+ switch (instring) {
+ case QT_SINGLE:
compquote = ztrdup("\'");
compquoting = ztrdup("single");
- } else {
+ break;
+
+ case QT_DOUBLE:
compquote = ztrdup("\"");
compquoting = ztrdup("double");
+ break;
+
+ case QT_DOLLARS:
+ compquote = ztrdup("$'");
+ compquoting = ztrdup("dollars");
+ break;
}
kset |= CP_QUOTE | CP_QUOTING;
} else if (inbackt) {
@@ -1026,8 +1037,7 @@ multiquote(char *s, int ign)
p += ign;
while (*p) {
if (ign >= 0 || p[1])
- s = bslashquote(s, NULL,
- (*p == '\'' ? 1 : (*p == '"' ? 2 : 0)));
+ s = quotestring(s, NULL, *p);
p++;
}
}
@@ -1290,9 +1300,29 @@ comp_str(int *ipl, int *pl, int untok)
return str;
}
+/**/
+mod_export char *
+comp_quoting_string(int stype)
+{
+ switch (stype)
+ {
+ case QT_SINGLE:
+ return "'";
+ case QT_DOUBLE:
+ return "\"";
+ case QT_DOLLARS:
+ return "$'";
+ default: /* shuts up compiler */
+ return "\\";
+ }
+}
+
/*
* This is the code behind compset -q, which splits the
* the current word as if it were a command line.
+ *
+ * This is one of those completion functions that merits the
+ * coveted title "not just ordinarily horrific".
*/
/**/
@@ -1307,7 +1337,7 @@ set_comp_sep(void)
int tl, got = 0, i = 0, j, cur = -1, oll, sl, css = 0;
int remq = 0, dq = 0, odq, sq = 0, osq, issq = 0, sqq = 0, lsq = 0, qa = 0;
int ois = instring, oib = inbackt, noffs = lp, ona = noaliases;
- char *tmp, *p, *ns, *ol, sav, *qp, *qs, *ts, qc = '\0';
+ char *tmp, *p, *ns, *ol, sav, *qp, *qs, *ts;
METACHECK();
@@ -1334,21 +1364,27 @@ set_comp_sep(void)
strcpy(tmp + 2 + noffs, s + noffs);
switch (*compqstack) {
- case '\\':
+ case QT_NONE:
+#ifdef DEBUG
+ dputs("BUG: head of compstack is NULL");
+#endif
+ break;
+
+ case QT_BACKSLASH:
remq = 1;
tmp = rembslash(tmp);
break;
- case '\'':
+
+ case QT_SINGLE:
issq = 1;
if (isset(RCQUOTES))
qa = 1;
else
qa = 3;
-
sq = remsquote(tmp);
-
break;
- case '"':
+
+ case QT_DOUBLE:
for (j = 0, p = tmp; *p; p++, j++)
if (*p == '\\' && p[1] == '\\') {
dq++;
@@ -1360,6 +1396,11 @@ set_comp_sep(void)
if (!*p)
break;
}
+ break;
+
+ case QT_DOLLARS:
+ /* TODO */
+ break;
}
odq = dq;
osq = sq;
@@ -1450,19 +1491,36 @@ set_comp_sep(void)
untokenize(ts = dupstring(ns));
- if (*ns == Snull || *ns == Dnull) {
- instring = (*ns == Snull ? 1 : 2);
+ if (*ns == Snull || *ns == Dnull ||
+ ((*ns == String || *ns == Qstring) && ns[1] == Snull)) {
+ char *tsptr = ts, *nsptr = ns, sav;
+ switch (*ns) {
+ case Snull:
+ instring = QT_SINGLE;
+ break;
+
+ case Dnull:
+ instring = QT_DOUBLE;
+ break;
+
+ default:
+ instring = QT_DOLLARS;
+ nsptr++;
+ tsptr++;
+ break;
+ }
+
inbackt = 0;
swb++;
- if (ns[strlen(ns) - 1] == *ns && ns[1])
+ if (nsptr[strlen(nsptr) - 1] == *nsptr && nsptr[1])
swe--;
zsfree(autoq);
- autoq = ztrdup(compqstack[1] ? "" :
- multiquote(*ns == Snull ? "'" : "\"", 1));
- qc = (*ns == Snull ? '\'' : '"');
- ts++;
+ sav = *++tsptr;
+ *tsptr = '\0';
+ autoq = ztrdup(compqstack[1] ? "" : multiquote(ts, 1));
+ *(ts = tsptr) = sav;
} else {
- instring = 0;
+ instring = QT_NONE;
zsfree(autoq);
autoq = NULL;
}
@@ -1496,7 +1554,7 @@ set_comp_sep(void)
}
ns = ts;
- if (instring && strchr(compqstack, '\\')) {
+ if (instring && strchr(compqstack, QT_BACKSLASH)) {
int rl = strlen(ns), ql = strlen(multiquote(ns, !!compqstack[1]));
if (ql > rl)
@@ -1525,24 +1583,38 @@ set_comp_sep(void)
}
{
int set = CP_QUOTE | CP_QUOTING, unset = 0;
+ char compnewchars[2];
- p = tricat((instring ? (instring == 1 ? "'" : "\"") : "\\"),
- compqstack, "");
+ compnewchars[0] =
+ (char)(instring == QT_NONE ? QT_BACKSLASH : instring);
+ compnewchars[1] = '\0';
+ p = tricat(compnewchars, compqstack, "");
zsfree(compqstack);
compqstack = p;
zsfree(compquote);
zsfree(compquoting);
- if (instring == 2) {
+ switch (instring) {
+ case QT_DOUBLE:
compquote = "\"";
compquoting = "double";
- } else if (instring == 1) {
+ break;
+
+ case QT_SINGLE:
compquote = "'";
compquoting = "single";
- } else {
+ break;
+
+ case QT_DOLLARS:
+ compquote = "$'";
+ compquoting = "dollars";
+ break;
+
+ default:
compquote = compquoting = "";
unset = set;
set = 0;
+ break;
}
compquote = ztrdup(compquote);
compquoting = ztrdup(compquoting);
@@ -1804,20 +1876,33 @@ addmatches(Cadata dat, char **argv)
dat->flags |= parflags;
if (compquote && (qc = *compquote)) {
if (qc == '`') {
- instring = 0;
+ instring = QT_NONE;
+ /*
+ * Yes, inbackt has always been set to zero here. I'm
+ * sure there's a simple explanation.
+ */
inbackt = 0;
autoq = "";
} else {
- char buf[2];
+ switch (qc) {
+ case '\'':
+ instring = QT_SINGLE;
+ break;
- instring = (qc == '\'' ? 1 : 2);
+ case '"':
+ instring = QT_DOUBLE;
+ break;
+
+ case '$':
+ instring = QT_DOLLARS;
+ break;
+ }
inbackt = 0;
- buf[0] = qc;
- buf[1] = '\0';
- autoq = multiquote(buf, 1);
+ autoq = multiquote(compquote, 1);
}
} else {
- instring = inbackt = 0;
+ instring = QT_NONE;
+ inbackt = 0;
autoq = NULL;
}
qipre = ztrdup(compqiprefix ? compqiprefix : "");
@@ -2549,8 +2634,8 @@ add_match_data(int alt, char *str, char *orig, Cline line,
cm->modec = '\0';
}
}
- if ((*compqstack == '\\' && compqstack[1]) ||
- (autoq && *compqstack && compqstack[1] == '\\'))
+ if ((*compqstack == QT_BACKSLASH && compqstack[1]) ||
+ (autoq && *compqstack && compqstack[1] == QT_BACKSLASH))
cm->flags |= CMF_NOSPACE;
if (nbrbeg) {
int *p;
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index b8ed66260..4cd9d9c65 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -1401,7 +1401,7 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat)
untokenize(p);
quotedzputs(p, stdout);
} else
- quotedzputs(bslashquote(s, NULL, 0), stdout);
+ quotedzputs(quotestring(s, NULL, QT_BACKSLASH), stdout);
}
/* loop through flags w/o args that are set, printing them if so */
@@ -1537,7 +1537,7 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat)
char *p = dupstring(s);
untokenize(p);
- quotedzputs(bslashquote(p, NULL, 0), stdout);
+ quotedzputs(quotestring(p, NULL, QT_BACKSLASH), stdout);
}
}
putchar('\n');
@@ -1735,10 +1735,13 @@ static char ic;
static int addwhat;
-/* Convenience macro for calling bslashquote() (formerly quotename()). *
- * This uses the instring variable above. */
+/*
+ * Convenience macro for calling quotestring (formerly bslashquote()
+ * (formerly quotename())).
+ * This uses the instring variable exported from zle_tricky.c.
+ */
-#define quotename(s, e) bslashquote(s, e, instring)
+#define quotename(s, e) quotestring(s, e, instring)
/* Hook functions */
@@ -2279,22 +2282,38 @@ makecomplistctl(int flags)
char *os = cmdstr, **ow = clwords, **p, **q, qc;
int on = clwnum, op = clwpos, ois = instring, oib = inbackt;
char *oisuf = isuf, *oqp = qipre, *oqs = qisuf, *oaq = autoq;
- char buf[2];
+ char buf[3];
if (compquote && (qc = *compquote)) {
if (qc == '`') {
- instring = 0;
+ instring = QT_NONE;
+ /*
+ * Yes, inbackt has always been set to zero here. I'm
+ * sure there's a simple explanation.
+ */
inbackt = 0;
autoq = "";
} else {
- buf[0] = qc;
- buf[1] = '\0';
- instring = (qc == '\'' ? 1 : 2);
+ switch (qc) {
+ case '\'':
+ instring = QT_SINGLE;
+ break;
+
+ case '"':
+ instring = QT_DOUBLE;
+ break;
+
+ case '$':
+ instring = QT_DOLLARS;
+ break;
+ }
inbackt = 0;
+ strcpy(buf, compquote);
autoq = buf;
}
} else {
- instring = inbackt = 0;
+ instring = QT_NONE;
+ inbackt = 0;
autoq = "";
}
qipre = ztrdup(compqiprefix ? compqiprefix : "");
@@ -2589,7 +2608,7 @@ makecomplistext(Compctl occ, char *os, int incmd)
int compadd, m = 0, d = 0, t, tt, i, j, a, b, ins;
char *sc = NULL, *s, *ss;
- ins = (instring ? instring : (inbackt ? 3 : 0));
+ ins = (instring != QT_NONE ? instring : (inbackt ? QT_BACKTICK : 0));
/* This loops over the patterns separated by `-'s. */
for (compc = occ->ext; compc; compc = compc->next) {
@@ -2607,9 +2626,9 @@ makecomplistext(Compctl occ, char *os, int incmd)
erange = clwnum - 1;
switch (cc->type) {
case CCT_QUOTE:
- t = ((cc->u.s.s[i][0] == 's' && ins == 1) ||
- (cc->u.s.s[i][0] == 'd' && ins == 2) ||
- (cc->u.s.s[i][0] == 'b' && ins == 3));
+ t = ((cc->u.s.s[i][0] == 's' && ins == QT_SINGLE) ||
+ (cc->u.s.s[i][0] == 'd' && ins == QT_DOUBLE) ||
+ (cc->u.s.s[i][0] == 'b' && ins == QT_BACKTICK));
break;
case CCT_POS:
tt = clwpos;
@@ -2755,7 +2774,7 @@ sep_comp_string(char *ss, char *s, int noffs)
int sl = strlen(ss), tl, got = 0, i = 0, cur = -1, oll = zlemetall, remq;
int ois = instring, oib = inbackt, ona = noaliases;
char *tmp, *p, *ns, *ol = zlemetaline, sav, *oaq = autoq;
- char *qp, *qs, *ts, qc = '\0';
+ char *qp, *qs, *ts;
swb = swe = soffs = 0;
ns = NULL;
@@ -2774,7 +2793,7 @@ sep_comp_string(char *ss, char *s, int noffs)
memcpy(tmp + sl + 1, s, noffs);
tmp[(scs = zlemetacs = sl + 1 + noffs)] = 'x';
strcpy(tmp + sl + 2 + noffs, s + noffs);
- if ((remq = (*compqstack == '\\')))
+ if ((remq = (*compqstack == QT_BACKSLASH)))
tmp = rembslash(tmp);
inpush(dupstrspace(tmp), 0, NULL);
zlemetaline = tmp;
@@ -2841,17 +2860,35 @@ sep_comp_string(char *ss, char *s, int noffs)
untokenize(ts = dupstring(ns));
- if (*ns == Snull || *ns == Dnull) {
- instring = (*ns == Snull ? 1 : 2);
+ if (*ns == Snull || *ns == Dnull ||
+ ((*ns == String || *ns == Qstring) && ns[1] == Snull)) {
+ char *tsptr = ts, *nsptr = ns, sav;
+ switch (*ns) {
+ case Snull:
+ instring = QT_SINGLE;
+ break;
+
+ case Dnull:
+ instring = QT_DOUBLE;
+ break;
+
+ default:
+ instring = QT_DOLLARS;
+ nsptr++;
+ tsptr++;
+ break;
+ }
+
inbackt = 0;
swb++;
- if (ns[strlen(ns) - 1] == *ns && ns[1])
+ if (nsptr[strlen(nsptr) - 1] == *nsptr && nsptr[1])
swe--;
- autoq = compqstack[1] ? "" : multiquote(*ns == Snull ? "'" : "\"", 1);
- qc = (*ns == Snull ? '\'' : '"');
- ts++;
+ sav = *++tsptr;
+ *tsptr = '\0';
+ autoq = compqstack[1] ? "" : multiquote(ts, 1);
+ *(ts = tsptr) = sav;
} else {
- instring = 0;
+ instring = QT_NONE;
autoq = "";
}
for (p = ns, i = swb; *p; p++, i++) {
@@ -2878,7 +2915,7 @@ sep_comp_string(char *ss, char *s, int noffs)
}
ns = ts;
- if (instring && strchr(compqstack, '\\')) {
+ if (instring != QT_NONE && strchr(compqstack, QT_BACKSLASH)) {
int rl = strlen(ns), ql = strlen(multiquote(ns, !!compqstack[1]));
if (ql > rl)
@@ -2904,13 +2941,15 @@ sep_comp_string(char *ss, char *s, int noffs)
{
char **ow = clwords, *os = cmdstr, *oqp = qipre, *oqs = qisuf;
- char *oqst = compqstack;
+ char *oqst = compqstack, compnewchar[2];
int olws = clwsize, olwn = clwnum, olwp = clwpos;
int obr = brange, oer = erange, oof = offs;
unsigned long occ = ccont;
- compqstack = tricat((instring ? (instring == 1 ? "'" : "\"") : "\\"),
- compqstack, "");
+ compnewchar[0] = (char)(instring != QT_NONE ? (char)instring :
+ QT_BACKSLASH);
+ compnewchar[1] = '\0';
+ compqstack = tricat(compnewchar, compqstack, "");
clwsize = clwnum = countlinknodes(foo);
clwords = (char **) zalloc((clwnum + 1) * sizeof(char *));
diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c
index 46e9a06d8..a73d3cf14 100644
--- a/Src/Zle/complete.c
+++ b/Src/Zle/complete.c
@@ -992,6 +992,8 @@ static const struct gsu_scalar unambig_pos_gsu =
{ get_unambig_pos, nullstrsetfn, compunsetfn };
static const struct gsu_scalar insert_pos_gsu =
{ get_insert_pos, nullstrsetfn, compunsetfn };
+static const struct gsu_scalar compqstack_gsu =
+{ get_compqstack, nullstrsetfn, compunsetfn };
static const struct gsu_integer compvarinteger_gsu =
{ intvargetfn, intvarsetfn, compunsetfn };
@@ -1047,7 +1049,7 @@ static struct compparam compkparams[] = {
{ "old_insert", PM_SCALAR, VAL(compoldins), NULL },
{ "vared", PM_SCALAR, VAL(compvared), NULL },
{ "list_lines", PM_INTEGER | PM_READONLY, NULL, GSU(listlines_gsu) },
- { "all_quotes", PM_SCALAR | PM_READONLY, VAL(compqstack), NULL },
+ { "all_quotes", PM_SCALAR | PM_READONLY, NULL, GSU(compqstack_gsu) },
{ "ignored", PM_INTEGER | PM_READONLY, VAL(compignored), NULL },
{ NULL, 0, NULL, NULL }
};
@@ -1223,6 +1225,26 @@ get_insert_pos(UNUSED(Param pm))
}
/**/
+static char *
+get_compqstack(UNUSED(Param pm))
+{
+ char *p, *ptr, *cqp;
+
+ if (!compqstack) /* TODO: don't think this can happen... */
+ return "";
+
+ ptr = p = zhalloc(2*strlen(compqstack)+1);
+
+ for (cqp = compqstack; *cqp; cqp++) {
+ char *str = comp_quoting_string(*cqp);
+ *ptr++ = *str;
+ }
+ *ptr = '\0';
+
+ return p;
+}
+
+/**/
static void
compunsetfn(Param pm, int exp)
{
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index bde1f79af..f13397e5e 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -3441,8 +3441,7 @@ comp_quote(char *str, int prefix)
if ((x = (prefix && *str == '=')))
*str = 'x';
- ret = bslashquote(str, NULL, (*compqstack == '\'' ? 1 :
- (*compqstack == '"' ? 2 : 0)));
+ ret = quotestring(str, NULL, *compqstack);
if (x)
*str = *ret = '=';
@@ -4344,7 +4343,7 @@ cf_ignore(char **names, LinkList ign, char *style, char *path)
for (; (n = *names); names++) {
if (!ztat(n, &nst, 0) && S_ISDIR(nst.st_mode)) {
if (tpwd && nst.st_dev == est.st_dev && nst.st_ino == est.st_ino) {
- addlinknode(ign, bslashquote(n, NULL, 0));
+ addlinknode(ign, quotestring(n, NULL, QT_BACKSLASH));
continue;
}
if (tpar && !strncmp((c = dupstring(n)), path, pl)) {
@@ -4360,7 +4359,7 @@ cf_ignore(char **names, LinkList ign, char *style, char *path)
if (found || ((e = strrchr(c, '/')) && e > c + pl &&
!ztat(c, &st, 0) && st.st_dev == nst.st_dev &&
st.st_ino == nst.st_ino))
- addlinknode(ign, bslashquote(n, NULL, 0));
+ addlinknode(ign, quotestring(n, NULL, QT_BACKSLASH));
}
}
}
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 89277a9e1..09a0be5d8 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -402,15 +402,22 @@ mod_export int insubscr;
/**/
mod_export Param keypm;
-/* 1 if we are completing in a quoted string (or inside `...`) */
+/*
+ * instring takes one of the QT_* values defined in zsh.h.
+ * It's never QT_TICK, instead we use inbackt.
+ * TODO: can we combine the two?
+ */
/**/
mod_export int instring, inbackt;
-/* Convenience macro for calling bslashquote() (formerly quotename()). *
- * This uses the instring variable above. */
+/*
+ * Convenience macro for calling quotestring (formerly bslashquote() (formerly
+ * quotename())).
+ * This uses the instring variable above.
+ */
-#define quotename(s, e) bslashquote(s, e, instring)
+#define quotename(s, e) quotestring(s, e, instring)
/* Check if the given string is the name of a parameter and if this *
* parameter is one worth expanding. */
@@ -891,7 +898,7 @@ addx(char **ptmp)
zlemetaline[zlemetacs] == ';' || zlemetaline[zlemetacs] == '|' ||
zlemetaline[zlemetacs] == '&' ||
zlemetaline[zlemetacs] == '>' || zlemetaline[zlemetacs] == '<' ||
- (instring && (zlemetaline[zlemetacs] == '"' ||
+ (instring != QT_NONE && (zlemetaline[zlemetacs] == '"' ||
zlemetaline[zlemetacs] == '\'')) ||
(addspace = (comppref && !iblank(zlemetaline[zlemetacs])))) {
*ptmp = zlemetaline;
@@ -1032,7 +1039,18 @@ static char *
get_comp_string(void)
{
int t0, tt0, i, j, k, cp, rd, sl, ocs, ins, oins, ia, parct, varq = 0;
- int ona = noaliases, qsub;
+ int ona = noaliases;
+ /*
+ * qsub fixes up the offset into the current completion word
+ * for changes made by the lexer. That currently means the
+ * effect of RCQUOTES on embedded pairs of single quotes.
+ * zlemetacs_qsub takes account of the effect of this offset
+ * on the cursor position; it's only needed when using the
+ * word we got from the lexer, which we only do sometimes because
+ * otherwise it would be too easy. If looking at zlemetaline we
+ * still use zlemetacs.
+ */
+ int qsub, zlemetacs_qsub = 0;
char *s = NULL, *tmp, *p, *tt = NULL, rdop[20];
char *linptr, *u;
@@ -1070,7 +1088,7 @@ get_comp_string(void)
u++;
}
inbackt = (i & 1);
- instring = 0;
+ instring = QT_NONE;
addx(&tmp);
linptr = zlemetaline;
pushheap();
@@ -1235,9 +1253,11 @@ get_comp_string(void)
clwords[i][--sl] = '\0';
/* If this is the word the cursor is in and we added a `x', *
* remove it. */
- if (clwpos == i++ && addedx)
- chuck(&clwords[i - 1][((zlemetacs - wb - qsub) >= sl) ?
- (sl - 1) : (zlemetacs - wb - qsub)]);
+ if (clwpos == i++ && addedx) {
+ zlemetacs_qsub = zlemetacs - qsub;
+ chuck(&clwords[i - 1][((zlemetacs_qsub - wb) >= sl) ?
+ (sl - 1) : (zlemetacs_qsub - wb)]);
+ }
} while (tok != LEXERR && tok != ENDINPUT &&
(tok != SEPER || (zleparse && !tt0)));
/* Calculate the number of words stored in the clwords array. */
@@ -1299,7 +1319,8 @@ get_comp_string(void)
*s = sav;
if (*s == '+')
s++;
- if (skipparens(Inbrack, Outbrack, &s) > 0 || s > tt + zlemetacs - wb) {
+ if (skipparens(Inbrack, Outbrack, &s) > 0 || s > tt +
+ zlemetacs_qsub - wb) {
s = NULL;
inwhat = IN_MATH;
if ((keypm = (Param) paramtab->getnode(paramtab, varname)) &&
@@ -1308,7 +1329,7 @@ get_comp_string(void)
else
insubscr = 1;
} else if (*s == '=') {
- if (zlemetacs > wb + (s - tt)) {
+ if (zlemetacs_qsub > wb + (s - tt)) {
s++;
wb += s - tt;
s = ztrdup(s);
@@ -1365,7 +1386,7 @@ get_comp_string(void)
nnb = s + MB_METACHARLEN(s);
else
nnb = s;
- for (tt = s; tt < s + zlemetacs - wb;) {
+ for (tt = s; tt < s + zlemetacs_qsub - wb;) {
if (*tt == Inbrack) {
i++;
nb = nnb;
@@ -1504,21 +1525,46 @@ get_comp_string(void)
level--;
}
}
- if ((*s == Snull || *s == Dnull) && !has_real_token(s + 1)) {
- char *q = (*s == Snull ? "'" : "\""), *n = tricat(qipre, q, "");
+ if ((*s == Snull || *s == Dnull ||
+ ((*s == String || *s == Qstring) && s[1] == Snull))
+ && !has_real_token(s + 1)) {
int sl = strlen(s);
+ char *q, *qtptr = s, *n;
+
+ switch (*s) {
+ case Snull:
+ q = "'";
+ instring = QT_SINGLE;
+ break;
+
+ case Dnull:
+ q = "\"";
+ instring = QT_DOUBLE;
+ break;
+
+ default:
+ q = "$'";
+ instring = QT_DOLLARS;
+ qtptr++;
+ sl--;
+ break;
+ }
- instring = (*s == Snull ? 1 : 2);
+ n = tricat(qipre, q, "");
zsfree(qipre);
qipre = n;
- if (sl > 1 && s[sl - 1] == *s) {
+ if (sl > 1 && qtptr[sl - 1] == *qtptr) {
n = tricat(q, qisuf, "");
zsfree(qisuf);
qisuf = n;
}
autoq = ztrdup(q);
- if (instring == 2) {
+ /*
+ * \! in double quotes is extracted by the history code before normal
+ * parsing, so sanitize it here, too.
+ */
+ if (instring == QT_DOUBLE) {
for (q = s; *q; q++)
if (*q == '\\' && q[1] == '!')
*q = Bnull;
@@ -1651,11 +1697,11 @@ get_comp_string(void)
new->next = NULL;
new->str = dupstrpfx(bbeg, len);
- new->str = ztrdup(bslashquote(new->str, NULL, instring));
+ new->str = ztrdup(quotename(new->str, NULL));
untokenize(new->str);
new->pos = begi;
*dbeg = '\0';
- new->qpos = strlen(bslashquote(predup, NULL, instring));
+ new->qpos = strlen(quotename(predup, NULL));
*dbeg = '{';
i -= len;
boffs -= len;
@@ -1700,11 +1746,11 @@ get_comp_string(void)
lastbrbeg = new;
new->str = dupstrpfx(bbeg, len);
- new->str = ztrdup(bslashquote(new->str, NULL, instring));
+ new->str = ztrdup(quotename(new->str, NULL));
untokenize(new->str);
new->pos = begi;
*dbeg = '\0';
- new->qpos = strlen(bslashquote(predup, NULL, instring));
+ new->qpos = strlen(quotename(predup, NULL));
*dbeg = '{';
i -= len;
boffs -= len;
@@ -1737,7 +1783,7 @@ get_comp_string(void)
brend = new;
new->str = dupstrpfx(bbeg, len);
- new->str = ztrdup(bslashquote(new->str, NULL, instring));
+ new->str = ztrdup(quotename(new->str, NULL));
untokenize(new->str);
new->pos = dp - predup - len + 1;
new->qpos = len;
@@ -1766,11 +1812,11 @@ get_comp_string(void)
lastbrbeg = new;
new->str = dupstrpfx(bbeg, len);
- new->str = ztrdup(bslashquote(new->str, NULL, instring));
+ new->str = ztrdup(quotename(new->str, NULL));
untokenize(new->str);
new->pos = begi;
*dbeg = '\0';
- new->qpos = strlen(bslashquote(predup, NULL, instring));
+ new->qpos = strlen(quotename(predup, NULL));
*dbeg = '{';
boffs -= len;
strcpy(dbeg, dbeg + len);
@@ -1785,7 +1831,7 @@ get_comp_string(void)
p = bp->pos;
l = bp->qpos;
bp->pos = strlen(predup + p + l);
- bp->qpos = strlen(bslashquote(predup + p + l, NULL, instring));
+ bp->qpos = strlen(quotename(predup + p + l, NULL));
strcpy(predup + p, predup + p + l);
}
}
diff --git a/Src/builtin.c b/Src/builtin.c
index 713e41a98..185365644 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -3964,7 +3964,8 @@ bin_print(char *name, char **args, Options ops, int func)
count += fprintf(fout, "%*c", width, ' ');
break;
case 'q':
- stringval = curarg ? bslashquote(curarg, NULL, 0) : &nullstr;
+ stringval = curarg ?
+ quotestring(curarg, NULL, QT_BACKSLASH) : &nullstr;
*d = 's';
print_val(stringval);
break;
diff --git a/Src/subst.c b/Src/subst.c
index 0f351df4c..8ef8d446e 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -1394,7 +1394,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
* quoterr is simply (X) but gets passed around a lot because the
* combination (eX) needs it.
*/
- int quotemod = 0, quotetype = 0, quoteerr = 0;
+ int quotemod = 0, quotetype = QT_NONE, quoteerr = 0;
/*
* (V) flag: fairly straightforward, except that as with so
* many flags it's not easy to decide where to put it in the order.
@@ -2835,8 +2835,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
* the repetitions of the (q) flag.
*/
if (quotemod) {
- if (--quotetype > 3)
- quotetype = 3;
+ if (quotetype > QT_DOLLARS)
+ quotetype = QT_DOLLARS;
if (isarr) {
char **ap;
@@ -2845,24 +2845,25 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
ap = aval;
if (quotemod > 0) {
- if (quotetype) {
+ if (quotetype > QT_BACKSLASH) {
int sl;
char *tmp;
for (; *ap; ap++) {
- int pre = quotetype != 3 ? 1 : 2;
- tmp = bslashquote(*ap, NULL, quotetype);
+ int pre = quotetype != QT_DOLLARS ? 1 : 2;
+ tmp = quotestring(*ap, NULL, quotetype);
sl = strlen(tmp);
*ap = (char *) zhalloc(pre + sl + 2);
strcpy((*ap) + pre, tmp);
- ap[0][pre - 1] = ap[0][pre + sl] = (quotetype != 2 ? '\'' : '"');
+ ap[0][pre - 1] = ap[0][pre + sl] =
+ (quotetype != QT_DOUBLE ? '\'' : '"');
ap[0][pre + sl + 1] = '\0';
- if (quotetype == 3)
+ if (quotetype == QT_DOLLARS)
ap[0][0] = '$';
}
} else
for (; *ap; ap++)
- *ap = bslashquote(*ap, NULL, 0);
+ *ap = quotestring(*ap, NULL, QT_BACKSLASH);
} else {
int one = noerrs, oef = errflag, haserr = 0;
@@ -2885,20 +2886,21 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
if (!copied)
val = dupstring(val), copied = 1;
if (quotemod > 0) {
- if (quotetype) {
- int pre = quotetype != 3 ? 1 : 2;
+ if (quotetype > QT_BACKSLASH) {
+ int pre = quotetype != QT_DOLLARS ? 1 : 2;
int sl;
char *tmp;
- tmp = bslashquote(val, NULL, quotetype);
+ tmp = quotestring(val, NULL, quotetype);
sl = strlen(tmp);
val = (char *) zhalloc(pre + sl + 2);
strcpy(val + pre, tmp);
- val[pre - 1] = val[pre + sl] = (quotetype != 2 ? '\'' : '"');
+ val[pre - 1] = val[pre + sl] =
+ (quotetype != QT_DOUBLE ? '\'' : '"');
val[pre + sl + 1] = '\0';
- if (quotetype == 3)
+ if (quotetype == QT_DOLLARS)
val[0] = '$';
} else
- val = bslashquote(val, NULL, 0);
+ val = quotestring(val, NULL, QT_BACKSLASH);
} else {
int one = noerrs, oef = errflag, haserr;
@@ -3387,7 +3389,7 @@ modify(char **str, char **ptr)
subst(&copy, hsubl, hsubr, gbal);
break;
case 'q':
- copy = bslashquote(copy, NULL, 0);
+ copy = quotestring(copy, NULL, QT_BACKSLASH);
break;
case 'Q':
{
@@ -3453,7 +3455,7 @@ modify(char **str, char **ptr)
}
break;
case 'q':
- *str = bslashquote(*str, NULL, 0);
+ *str = quotestring(*str, NULL, QT_BACKSLASH);
break;
case 'Q':
{
diff --git a/Src/text.c b/Src/text.c
index db24d8c9e..0079e9fea 100644
--- a/Src/text.c
+++ b/Src/text.c
@@ -807,7 +807,7 @@ getredirs(LinkList redirs)
* quotes certainly isn't right in that case).
*/
taddchr('\'');
- taddstr(bslashquote(f->name, NULL, 1));
+ taddstr(quotestring(f->name, NULL, QT_SINGLE));
taddchr('\'');
} else
taddstr(f->name);
diff --git a/Src/utils.c b/Src/utils.c
index 99b0eb743..0aa0dfe2f 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -1357,7 +1357,7 @@ settyinfo(struct ttyinfo *ti)
}
/* the default tty state */
-
+
/**/
mod_export struct ttyinfo shttyinfo;
@@ -1576,13 +1576,13 @@ extern char *_mktemp(char *);
* NULL, the name is relative to $TMPPREFIX; If it is non-NULL, the
* unique suffix includes a prefixed '.' for improved readability. If
* "use_heap" is true, we allocate the returned name on the heap. */
-
+
/**/
mod_export char *
gettempname(const char *prefix, int use_heap)
{
char *ret, *suffix = prefix ? ".XXXXXX" : "XXXXXX";
-
+
queue_signals();
if (!prefix && !(prefix = getsparam("TMPPREFIX")))
prefix = DEFAULT_TMPPREFIX;
@@ -1642,7 +1642,7 @@ gettempfile(const char *prefix, int use_heap, char **tempname)
*tempname = fn;
return fd;
}
-
+
/* Check if a string contains a token */
/**/
@@ -1656,7 +1656,7 @@ has_token(const char *s)
}
/* Delete a character in a string */
-
+
/**/
mod_export void
chuck(char *str)
@@ -3082,7 +3082,7 @@ itype_end(const char *ptr, int itype, int once)
*/
switch (itype) {
case IWORD:
- if (!iswalnum(wc) &&
+ if (!iswalnum(wc) &&
!wmemchr(wordchars_wide.chars, wc,
wordchars_wide.len))
return (char *)ptr;
@@ -3820,7 +3820,7 @@ nicezputs(char const *s, FILE *stream)
if (itok(c)) {
if (c <= Comma)
c = ztokens[c - Pound];
- else
+ else
continue;
}
if (c == Meta)
@@ -3845,7 +3845,7 @@ niceztrlen(char const *s)
if (itok(c)) {
if (c <= Comma)
c = ztokens[c - Pound];
- else
+ else
continue;
}
if (c == Meta)
@@ -4134,27 +4134,32 @@ hasspecial(char const *s)
return 0;
}
-/* Quote the string s and return the result. If e is non-zero, the *
- * pointer it points to may point to a position in s and in e the position *
- * of the corresponding character in the quoted string is returned. *
- * The last argument should be zero if this is to be used outside a string, *
- * one if it is to be quoted for the inside of a single quoted string, *
- * two if it is for the inside of a double quoted string, and *
- * three if it is for the inside of a $'...' quoted string. *
- * The string may be metafied and contain tokens. */
+/*
+ * Quote the string s and return the result.
+ *
+ * If e is non-zero, the
+ * pointer it points to may point to a position in s and in e the position
+ * of the corresponding character in the quoted string is returned.
+ *
+ * The last argument is a QT_ value defined in zsh.h other than QT_NONE.
+ *
+ * The string may be metafied and contain tokens.
+ */
/**/
mod_export char *
-bslashquote(const char *s, char **e, int instring)
+quotestring(const char *s, char **e, int instring)
{
const char *u, *tt;
char *v;
char *buf = hcalloc(4 * strlen(s) + 1);
int sf = 0;
+ DPUTS(instring < QT_BACKSLASH || instring > QT_DOLLARS,
+ "BUG: bad quote type in quotestring");
tt = v = buf;
u = s;
- if (instring == 3) {
+ if (instring == QT_DOLLARS) {
/*
* As we test for printability here we need to be able
* to look for multibyte characters.
@@ -4170,7 +4175,7 @@ bslashquote(const char *s, char **e, int instring)
}
if (
#ifdef MULTIBYTE_SUPPORT
- cc != WEOF &&
+ cc != WEOF &&
#endif
WC_ISPRINT(cc)) {
switch (cc) {
@@ -4276,13 +4281,13 @@ bslashquote(const char *s, char **e, int instring)
(isset(MAGICEQUALSUBST) &&
(u[-1] == '=' || u[-1] == ':')) ||
(*u == '~' && isset(EXTENDEDGLOB))) &&
- (!instring ||
+ (instring == QT_BACKSLASH ||
(isset(BANGHIST) && *u == (char)bangchar &&
- instring != 1) ||
- (instring == 2 &&
+ instring != QT_SINGLE) ||
+ (instring == QT_DOUBLE &&
(*u == '$' || *u == '`' || *u == '\"' || *u == '\\')) ||
- (instring == 1 && *u == '\''))) {
- if (*u == '\n' || (instring == 1 && *u == '\'')) {
+ (instring == QT_SINGLE && *u == '\''))) {
+ if (*u == '\n' || (instring == QT_SINGLE && *u == '\'')) {
if (unset(RCQUOTES)) {
*v++ = '\'';
if (*u == '\'')
@@ -4306,7 +4311,7 @@ bslashquote(const char *s, char **e, int instring)
if (e && *e == u)
*e = v, sf = 1;
- DPUTS(e && !sf, "BUG: Wild pointer *e in bslashquote()");
+ DPUTS(e && !sf, "BUG: Wild pointer *e in quotestring()");
return buf;
}
@@ -4654,7 +4659,7 @@ getkeystring(char *s, int *len, int how, int *misc)
*len = t - buf;
return buf;
}
- t += count;
+ t += count;
continue;
# else
# if defined(HAVE_NL_LANGINFO) && defined(CODESET)
diff --git a/Src/zsh.h b/Src/zsh.h
index 9a76bf9a5..c73ae3b9a 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -178,6 +178,41 @@ struct mathfunc {
#define SPECCHARS "#$^*()=|{}[]`<>?~;&\n\t \\\'\""
+/*
+ * Types of quote. This is used in various places, so care needs
+ * to be taken when changing them. (Oooh, don't you look surprised.)
+ * - Passed to quotestring() to indicate style. This is the ultimate
+ * destiny of most of the other uses of members of the enum.
+ * - In paramsubst(), to count q's in parameter substitution.
+ * - In the completion code, where we maintain a stack of quotation types.
+ */
+enum {
+ /*
+ * No quote. Not a valid quote, but useful in the substitution
+ * and completion code to indicate we're not doing any quoting.
+ */
+ QT_NONE,
+ /* Backslash: \ */
+ QT_BACKSLASH,
+ /* Single quote: ' */
+ QT_SINGLE,
+ /* Double quote: " */
+ QT_DOUBLE,
+ /* Print-style quote: $' */
+ QT_DOLLARS,
+ /*
+ * Backtick: `
+ * Not understood by many parts of the code; here for a convenience
+ * in those cases where we need to represent a complete set.
+ */
+ QT_BACKTICK,
+};
+
+/*
+ * Lexical tokens: unlike the character tokens above, these never
+ * appear in strings and don't necessarily represent a single character.
+ */
+
enum {
NULLTOK, /* 0 */
SEPER,