From 850fb2e7f94b4e0e9fbf3538ad9e3c44c9fed74b Mon Sep 17 00:00:00 2001 From: Tanaka Akira Date: Thu, 15 Apr 1999 18:14:01 +0000 Subject: zsh-3.1.5-pws-7 --- Src/Zle/comp.h | 10 ++ Src/Zle/comp1.c | 79 +----------- Src/Zle/comp1.export | 2 +- Src/Zle/compctl.c | 52 ++++++-- Src/Zle/zle_hist.c | 9 ++ Src/Zle/zle_main.c | 60 ++++++--- Src/Zle/zle_misc.c | 47 +++++++ Src/Zle/zle_thingy.c | 4 +- Src/Zle/zle_tricky.c | 347 ++++++++++++++++++++++++++++++++++++++------------- Src/Zle/zle_vi.c | 4 + Src/builtin.c | 85 +++++++++++-- Src/compat.c | 27 +++- Src/exec.c | 2 + Src/glob.c | 5 +- Src/init.c | 28 ++--- Src/makepro.awk | 7 ++ Src/options.c | 1 + Src/params.c | 2 +- Src/subst.c | 37 +++++- Src/utils.c | 108 ++++++++++++++-- Src/zsh.export | 4 + Src/zsh.h | 2 + 22 files changed, 683 insertions(+), 239 deletions(-) (limited to 'Src') diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h index 20e3d2cce..5f263557a 100644 --- a/Src/Zle/comp.h +++ b/Src/Zle/comp.h @@ -210,6 +210,7 @@ struct cmatch { int flags; /* see CMF_* below */ int brpl; /* the place where to put the brace prefix */ int brsl; /* ...and the suffix */ + char *rems; /* when to remove the suffix */ }; #define CMF_FILE 1 /* this is a file */ @@ -272,3 +273,12 @@ struct cline { #define CFN_FIRST 1 #define CFN_DEFAULT 2 + +/* Flags for compadd and addmatches(). */ + +#define CAF_QUOTE 1 +#define CAF_MENU 2 +#define CAF_NOSORT 4 +#define CAF_ALT 8 +#define CAF_FIGNORE 16 +#define CAF_MATCH 32 diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c index 36588a385..a5e35bc3c 100644 --- a/Src/Zle/comp1.c +++ b/Src/Zle/comp1.c @@ -49,7 +49,7 @@ void (*makecompparamsptr) _((void)); /* pointers to functions required by compctl and defined by zle */ /**/ -void (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, int, int, int, int, int, char **)); +void (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char **)); /**/ char *(*comp_strptr) _((int*,int*)); @@ -95,7 +95,8 @@ int incompfunc; /**/ long compcurrent, - compnmatches; + compnmatches, + compmatcher; /**/ char *compcontext, @@ -104,14 +105,8 @@ char *compcontext, *compsuffix, *compiprefix; -/* This variable and the functions rembslash() and quotename() came from * - * zle_tricky.c, but are now used in compctl.c, too. */ - -/* 1 if we are completing in a string */ - -/**/ -int instring; - +/* The function rembslash() came from zle_tricky.c, but is now used * + * in compctl.c, too. */ /**/ static void @@ -395,70 +390,6 @@ rembslash(char *s) return t; } -/* 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. Like * - * e, te may point to a position in the string and pl is used to return * - * the position of the character pointed to by te in the quoted string. * - * The string is metafied and may contain tokens. */ - -/**/ -char * -quotename(const char *s, char **e, char *te, int *pl) -{ - const char *u, *tt; - char *v, buf[PATH_MAX * 2]; - int sf = 0; - - tt = v = buf; - u = s; - for (; *u; u++) { - if (e && *e == u) - *e = v, sf |= 1; - if (te == u) - *pl = v - tt, sf |= 2; - if (ispecial(*u) && - (!instring || (isset(BANGHIST) && - *u == (char)bangchar) || - (instring == 2 && - (*u == '$' || *u == '`' || *u == '\"')) || - (instring == 1 && *u == '\''))) { - if (*u == '\n' || (instring == 1 && *u == '\'')) { - if (unset(RCQUOTES)) { - *v++ = '\''; - if (*u == '\'') - *v++ = '\\'; - *v++ = *u; - *v++ = '\''; - } else if (*u == '\n') - *v++ = '"', *v++ = '\n', *v++ = '"'; - else - *v++ = '\'', *v++ = '\''; - continue; - } else - *v++ = '\\'; - } - if(*u == Meta) - *v++ = *u++; - *v++ = *u; - } - *v = '\0'; - if (strcmp(buf, s)) - tt = dupstring(buf); - else - tt = s; - v += tt - buf; - if (e && (sf & 1)) - *e += tt - buf; - - if (e && *e == u) - *e = v; - if (te == u) - *pl = v - tt; - - return (char *) tt; -} - /**/ int setup_comp1(Module m) diff --git a/Src/Zle/comp1.export b/Src/Zle/comp1.export index 72581173b..278006b6a 100644 --- a/Src/Zle/comp1.export +++ b/Src/Zle/comp1.export @@ -14,6 +14,7 @@ compcontext compctltab compcurrent compiprefix +compmatcher compnmatches compprefix comp_strptr @@ -30,5 +31,4 @@ makecomplistcallptr makecomplistctlptr makecompparamsptr patcomps -quotename rembslash diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 879042cf3..dcc206c96 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -1385,7 +1385,7 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat) untokenize(p); quotedzputs(p, stdout); } else - quotedzputs(quotename(s, NULL, NULL, NULL), stdout); + quotedzputs(bslashquote(s, NULL, NULL, NULL, 0), stdout); } /* loop through flags w/o args that are set, printing them if so */ @@ -1515,7 +1515,7 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat) char *p = dupstring(s); untokenize(p); - quotedzputs(quotename(p, NULL, NULL, NULL), stdout); + quotedzputs(bslashquote(p, NULL, NULL, NULL, 0), stdout); } } putchar('\n'); @@ -1547,8 +1547,6 @@ bin_compctl(char *name, char **argv, char *ops, int func) cclist = 0; showmask = 0; - instring = 0; - /* Parse all the arguments */ if (*argv) { /* Let's see if this is a global matcher definition. */ @@ -1671,8 +1669,9 @@ bin_compadd(char *name, char **argv, char *ops, int func) { char *p, **sp, *e; char *ipre = NULL, *ppre = NULL, *psuf = NULL, *prpre = NULL; - char *pre = NULL, *suf = NULL, *group = NULL; - int f = 0, q = 0, m = 0, ns = 0, a = 0; + char *pre = NULL, *suf = NULL, *group = NULL, *m = NULL, *rs = NULL; + int f = 0, a = 0, dm; + Cmatcher match = NULL; if (incompfunc != 1) { zerrnam(name, "can only be called from completion function", NULL, 0); @@ -1681,21 +1680,25 @@ bin_compadd(char *name, char **argv, char *ops, int func) for (; *argv && **argv == '-'; argv++) { for (p = *argv + 1; *p; p++) { sp = NULL; + dm = 0; switch (*p) { case 'q': f |= CMF_REMOVE; break; case 'Q': - q = 1; + a |= CAF_QUOTE; break; case 'f': f |= CMF_FILE; break; + case 'F': + a |= CAF_FIGNORE; + break; case 'n': f |= CMF_NOLIST; break; case 'U': - m = 1; + a |= CAF_MENU; break; case 'P': sp = ⪯ @@ -1711,7 +1714,7 @@ bin_compadd(char *name, char **argv, char *ops, int func) break; case 'V': if (!group) - ns = 1; + a |= CAF_NOSORT; sp = &group; e = "group name expected after -%c"; break; @@ -1732,7 +1735,19 @@ bin_compadd(char *name, char **argv, char *ops, int func) e = "string expected after -%c"; break; case 'a': - a = 1; + a |= CAF_ALT; + break; + case 'm': + a |= CAF_MATCH; + break; + case 'M': + sp = &m; + e = "matching specification expected after -%c"; + dm = 1; + break; + case 'r': + sp = &rs; + e = "string expected after -%c"; break; case '-': argv++; @@ -1756,6 +1771,10 @@ bin_compadd(char *name, char **argv, char *ops, int func) zerrnam(name, e, NULL, *p); return 1; } + if (dm && (match = parse_cmatcher(name, m)) == pcm_err) { + match = NULL; + return 1; + } } } } @@ -1764,7 +1783,7 @@ bin_compadd(char *name, char **argv, char *ops, int func) return 1; addmatchesptr(ipre, ppre, psuf, prpre, pre, suf, group, - f, q, m, ns, a, argv); + rs, f, a, match, argv); return 0; } @@ -1794,6 +1813,7 @@ static struct compparam { { "SUFFIX", PM_SCALAR, VAR(compsuffix) }, { "IPREFIX", PM_SCALAR, VAR(compiprefix) }, { "NMATCHES", PM_INTEGER, VAR(compnmatches) }, + { "MATCHER", PM_INTEGER, VAR(compmatcher) }, { NULL, 0, NULL } }; @@ -2096,6 +2116,15 @@ cond_nmatches(char **a, int id) return 0; } +/**/ +static int +cond_matcher(char **a, int id) +{ + if (comp_check()) + return compmatcher == cond_val(a, 0); + return 0; +} + static struct builtin bintab[] = { BUILTIN("compctl", 0, bin_compctl, 0, -1, 0, NULL, NULL), BUILTIN("complist", 0, bin_complist, 1, -1, 0, NULL, NULL), @@ -2119,6 +2148,7 @@ static struct conddef cotab[] = { CONDDEF("after", 0, cond_range, 1, 1, 0), CONDDEF("mafter", 0, cond_range, 1, 1, 1), CONDDEF("nmatches", 0, cond_nmatches, 1, 1, 0), + CONDDEF("matcher", 0, cond_matcher, 1, 1, 0), }; static struct funcwrap wrapper[] = { diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c index fda204222..e6b385652 100644 --- a/Src/Zle/zle_hist.c +++ b/Src/Zle/zle_hist.c @@ -663,6 +663,11 @@ doisearch(int dir) static char *previous_search = NULL; static int previous_search_len = 0; + invalidatelist(); + moveto(0, 0); + clearflag = 0; + resetneeded = 1; + strcpy(ibuf, ISEARCH_PROMPT); memcpy(ibuf + NORM_PROMPT_POS, (dir == 1) ? "fwd" : "bck", 3); remember_edits(); @@ -943,6 +948,10 @@ getvisrchstr(void) zsfree(visrchstr); visrchstr = NULL; } + invalidatelist(); + moveto(0, 0); + clearflag = 0; + resetneeded = 1; statusline = sbuf; sbuf[0] = (visrchsense == -1) ? '?' : '/'; selectkeymap("main", 1); diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 03549b5d0..ca7a7fe19 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -661,10 +661,17 @@ bin_vared(char *name, char **args, char *ops, int func) { char *s; char *t; - Param pm; + Value v; + Param pm = 0; int create = 0; + int type = PM_SCALAR; char *p1 = NULL, *p2 = NULL; + if (zleactive) { + zwarnnam(name, "ZLE cannot be used recursively (yet)", NULL, 0); + return 1; + } + /* all options are handled as arguments */ while (*args && **args == '-') { while (*++(*args)) @@ -674,6 +681,12 @@ bin_vared(char *name, char **args, char *ops, int func) yet exist */ create = 1; break; + case 'a': + type = PM_ARRAY; + break; + case 'A': + type = PM_HASHED; + break; case 'p': /* -p option -- set main prompt string */ if ((*args)[1]) @@ -709,6 +722,9 @@ bin_vared(char *name, char **args, char *ops, int func) } args++; } + if (type && !create) { + zwarnnam(name, "-%s ignored", type == PM_ARRAY ? "a" : "A", 0); + } /* check we have a parameter name */ if (!*args) { @@ -716,17 +732,17 @@ bin_vared(char *name, char **args, char *ops, int func) return 1; } /* handle non-existent parameter */ - if (!(s = getsparam(args[0]))) { - if (create) - createparam(args[0], PM_SCALAR); - else { - zwarnnam(name, "no such variable: %s", args[0], 0); - return 1; - } - } - - if(zleactive) { - zwarnnam(name, "ZLE cannot be used recursively (yet)", NULL, 0); + s = args[0]; + v = fetchvalue(&s, (!create || type == PM_SCALAR), + SCANPM_WANTKEYS|SCANPM_WANTVALS|SCANPM_MATCHMANY); + if (!v && !create) { + zwarnnam(name, "no such variable: %s", args[0], 0); + return 1; + } else if (v) { + s = getstrvalue(v); + pm = v->pm; + } else if (*s) { + zwarnnam(name, "invalid parameter name: %s", args[0], 0); return 1; } @@ -744,14 +760,24 @@ bin_vared(char *name, char **args, char *ops, int func) if (t[strlen(t) - 1] == '\n') t[strlen(t) - 1] = '\0'; /* final assignment of parameter value */ - pm = (Param) paramtab->getnode(paramtab, args[0]); - if (pm && PM_TYPE(pm->flags) == PM_ARRAY) { + if (create && (!pm || (type && PM_TYPE(pm->flags) != type))) { + if (pm) + unsetparam(args[0]); + createparam(args[0], type); + pm = 0; + } + if (!pm) + pm = (Param) paramtab->getnode(paramtab, args[0]); + if (pm && (PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED))) { char **a; PERMALLOC { a = spacesplit(t, 1); } LASTALLOC; - setaparam(args[0], a); + if (PM_TYPE(pm->flags) == PM_ARRAY) + setaparam(args[0], a); + else + sethparam(args[0], a); } else setsparam(args[0], t); return 0; @@ -766,6 +792,10 @@ describekeybriefly(void) if (statusline) return; + invalidatelist(); + moveto(0, 0); + clearflag = 0; + resetneeded = 1; statusline = "Describe key briefly: _"; statusll = strlen(statusline); zrefresh(); diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index 836ff09ae..4b5df9cde 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -612,6 +612,10 @@ executenamedcommand(char *prmt) char *ptr; char *okeymap = curkeymapname; + invalidatelist(); + moveto(0, 0); + clearflag = 0; + resetneeded = 1; cmdbuf = halloc(l + NAMLEN + 2); strcpy(cmdbuf, prmt); statusline = cmdbuf; @@ -792,6 +796,49 @@ makeparamsuffix(int br, int n) } } +/* Set up suffix given a string containing the characters on which to * + * remove the suffix. */ + +/**/ +void +makesuffixstr(char *s, int n) +{ + if (s) { + int inv, i, v, z = 0; + + if (*s == '^' || *s == '!') { + inv = 1; + s++; + } else + inv = 0; + s = getkeystring(s, &i, 5, &z); + s = metafy(s, i, META_USEHEAP); + + if (inv) { + v = 0; + for (i = 0; i < 257; i++) + suffixlen[i] = n; + } else + v = n; + + if (z) + suffixlen[256] = v; + + while (*s) { + if (s[1] == '-' && s[2]) { + int b = (int) *s, e = (int) s[2]; + + while (b <= e) + suffixlen[b++] = v; + s += 2; + } else + suffixlen[STOUC(*s)] = v; + s++; + } + } else + makesuffix(n); +} + /* Remove suffix, if there is one, when inserting character c. */ /**/ diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c index 629d5a84e..d055c45c1 100644 --- a/Src/Zle/zle_thingy.c +++ b/Src/Zle/zle_thingy.c @@ -390,7 +390,7 @@ scanlistwidgets(HashNode hn, int list) if(w->flags & WIDGET_INT) return; if(list) { - fputs("zle -N ", stdout); + printf("zle -%c ", (w->flags & WIDGET_NCOMP) ? 'C' : 'N'); if(t->nam[0] == '-') fputs("-- ", stdout); quotedzputs(t->nam, stdout); @@ -406,7 +406,7 @@ scanlistwidgets(HashNode hn, int list) } else { nicezputs(t->nam, stdout); if (w->flags & WIDGET_NCOMP) { - fputs(" -c ", stdout); + fputs(" -C ", stdout); nicezputs(w->u.comp.wid, stdout); fputc(' ', stdout); nicezputs(w->u.comp.func, stdout); diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index df3e11f46..f1285da8c 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -223,7 +223,7 @@ typedef struct aminfo *Aminfo; struct aminfo { int cpl, csl, icpl, icsl; /* common prefix/suffix lengths */ - int prerest; /* minimum prefix rest */ + int minlen; /* minimum match length */ int suflen; /* minimum suffix length */ Cmatch firstm; /* the first match */ char *pprefix; /* common part of the -P prefixes */ @@ -270,6 +270,19 @@ enum { COMP_COMPLETE, COMP_LIST_EXPAND }; #define COMP_ISEXPAND(X) ((X) >= COMP_EXPAND) +/* Non-zero if the last completion done was ambiguous (used to find * + * out if AUTOMENU should start). More precisely, it's nonzero after * + * successfully doing any completion, unless the completion was * + * unambiguous and did not cause the display of a completion list. * + * From the other point of view, it's nonzero iff AUTOMENU (if set) * + * should kick in on another completion. * + * * + * If both AUTOMENU and BASHAUTOLIST are set, then we get a listing * + * on the second tab, a` la bash, and then automenu kicks in when * + * lastambig == 2. */ + +static int lastambig; + /**/ void completecall(void) @@ -287,8 +300,13 @@ completeword(void) useglob = isset(GLOBCOMPLETE); if (c == '\t' && usetab()) selfinsert(); - else - docomplete(COMP_COMPLETE); + else { + if (lastambig == 1 && isset(BASHAUTOLIST) && !usemenu && !menucmp) { + docomplete(COMP_LIST_COMPLETE); + lastambig = 2; + } else + docomplete(COMP_COMPLETE); + } } /**/ @@ -358,8 +376,13 @@ expandorcomplete(void) useglob = isset(GLOBCOMPLETE); if (c == '\t' && usetab()) selfinsert(); - else - docomplete(COMP_EXPAND_COMPLETE); + else { + if (lastambig == 1 && isset(BASHAUTOLIST) && !usemenu && !menucmp) { + docomplete(COMP_LIST_COMPLETE); + lastambig = 2; + } else + docomplete(COMP_EXPAND_COMPLETE); + } } /**/ @@ -451,15 +474,6 @@ static int lincmd, linredir; static char *rdstr; -/* Non-zero if the last completion done was ambiguous (used to find * - * out if AUTOMENU should start). More precisely, it's nonzero after * - * successfully doing any completion, unless the completion was * - * unambiguous and did not cause the display of a completion list. * - * From the other point of view, it's nonzero iff AUTOMENU (if set) * - * should kick in on another completion. */ - -static int lastambig; - /* This holds the name of the current command (used to find the right * * compctl). */ @@ -473,6 +487,16 @@ static char *varname; static int insubscr; +/* 1 if we are completing in a string */ + +/**/ +int instring; + +/* Convenience macro for calling bslashquote() (formerly quotename()). * + * This uses the instring variable above. */ + +#define quotename(s, e, te, pl) bslashquote(s, e, te, pl, instring) + /* Check if the given string is the name of a parameter and if this * * parameter is one worth expanding. */ @@ -569,7 +593,8 @@ docomplete(int lst) /* Check if we have to start a menu-completion (via automenu). */ - if ((amenu = (isset(AUTOMENU) && lastambig))) + if ((amenu = (isset(AUTOMENU) && lastambig && + (!isset(BASHAUTOLIST) || lastambig == 2)))) usemenu = 1; /* Expand history references before starting completion. If anything * @@ -919,7 +944,7 @@ unmetafy_line(void) static char * get_comp_string(void) { - int t0, tt0, i, j, k, cp, rd, sl, ocs, ins, oins; + int t0, tt0, i, j, k, cp, rd, sl, ocs, ins, oins, inarr, ia, parct; char *s = NULL, *linptr, *tmp, *p, *tt = NULL; zsfree(brbeg); @@ -982,7 +1007,7 @@ get_comp_string(void) inpush(dupstrspace((char *) linptr), 0, NULL); strinbeg(); stophist = 2; - i = tt0 = cp = rd = ins = oins = 0; + i = tt0 = cp = rd = ins = oins = inarr = parct = ia = 0; /* This loop is possibly the wrong way to do this. It goes through * * the previously massaged command line using the lexer. It stores * @@ -1001,7 +1026,21 @@ get_comp_string(void) linredir = (inredir && !ins); oins = ins; /* Get the next token. */ + if (inarr) + incmdpos = 0; ctxtlex(); + if (tok == ENVARRAY) { + inarr = 1; + zsfree(varname); + varname = ztrdup(tokstr); + } else if (tok == INPAR) + parct++; + else if (tok == OUTPAR) { + if (parct) + parct--; + else + inarr = 0; + } if (inredir) rdstr = tokstrings[tok]; if (tok == DINPAR) @@ -1043,6 +1082,7 @@ get_comp_string(void) clwpos = i; cp = lincmd; rd = linredir; + ia = inarr; if (inwhat == IN_NOTHING && incond) inwhat = IN_COND; } else if (linredir) @@ -1084,8 +1124,13 @@ get_comp_string(void) zsfree(clwords[clwnum]); clwords[clwnum] = NULL; t0 = tt0; - lincmd = cp; - linredir = rd; + if (ia) { + lincmd = linredir = 0; + inwhat = IN_ENV; + } else { + lincmd = cp; + linredir = rd; + } strinend(); inpop(); errflag = zleparse = 0; @@ -1789,9 +1834,17 @@ inst_cline(Cline l, int pl, int sl) pl += brpl; i = cs - wb; + if (pl >= 0 && i >= pl && brbeg && *brbeg) { + inststrlen(brbeg, 1, -1); + pl = -1; + hb = 1; + } + if (sl >= 0 && i >= sl && brend && *brend) { + inststrlen(brend, 1, -1); + sl = -1; + hb = 1; + } while (l) { - if (d < 0 && (l->flags & CLF_DIFF)) - d = cs; if (m < 0 && (l->flags & (CLF_MISS | CLF_SUF)) == (CLF_MISS | CLF_SUF)) m = cs; if (l->flags & CLF_MID) { @@ -1805,6 +1858,8 @@ inst_cline(Cline l, int pl, int sl) } else { inststrlen(l->line, 1, l->llen); } + if (d < 0 && (l->flags & CLF_DIFF)) + d = cs; if (m < 0 && (l->flags & CLF_MISS)) m = cs; i += l->llen; @@ -1893,8 +1948,10 @@ match_pfx(char *l, char *w, Cline *nlp, int *lp, Cline *rlp, int *bplp, while (ll && lw) { for (ms = mstack; ms; ms = ms->next) { for (mp = ms->matcher; mp; mp = mp->next) { - if (nm == mp || lm == mp) + if (nm == mp || lm == mp) { + nm = NULL; continue; + } t = 1; /* Try to match the prefix, if any. */ if (mp->flags & CMF_LEFT) { @@ -1930,7 +1987,7 @@ match_pfx(char *l, char *w, Cline *nlp, int *lp, Cline *rlp, int *bplp, NULL, NULL, mp)) break; } - if (k) { + if (k && i) { if (nlp) { nw = addtoword(&rw, &rwlen, nw, mp, l, w, i, 0); @@ -2106,8 +2163,10 @@ match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp, Cmatcher nm) while (ll && lw) { for (ms = mstack; ms; ms = ms->next) { for (mp = ms->matcher; mp; mp = mp->next) { - if (nm == mp || lm == mp) + if (nm == mp || lm == mp) { + nm = NULL; continue; + } t = 1; if (mp->flags & CMF_RIGHT) { if (il < mp->ralen || iw < mp->ralen) @@ -2135,13 +2194,13 @@ match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp, Cmatcher nm) if (t) { int i = 0, j = iw, k = lw; int jj = il + mp->llen, kk = ll - mp->llen; - char *p = l - mp->llen, *q = w; + char *p = l - mp->llen - 1, *q = w - 1; for (; k; i++, j++, k--, q--) - if (match_sfx(p, q, NULL, NULL, - NULL, mp)) + if (match_pfx(p, q, NULL, NULL, + NULL, NULL, mp)) break; - if (k) { + if (k && i) { if (nlp) { nw = addtoword(&rw, &rwlen, nw, mp, l - mp->llen, w - i, @@ -2151,10 +2210,10 @@ match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp, Cmatcher nm) ((mp->flags & CMF_LEFT) ? CLF_SUF : 0)); } - w = q; + w = q + 1; iw = j; lw = k; - l = p; + l = p + 1; il = jj; ll = kk; bc -= i; @@ -2395,20 +2454,45 @@ instmatch(Cmatch m) /**/ void addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, - char *suf, char *group, - int flags, int quote, int menu, int nosort, int alt, char **argv) + char *suf, char *group, char *rems, + int flags, int aflags, Cmatcher match, char **argv) { - char *s, *t; - int lpl, lsl, i; - Aminfo ai = (alt ? fainfo : ainfo); + char *s, *t, *e, *te, *ms, *lipre = NULL, *lpre, *lsuf; + int lpl, lsl, i, pl, sl, test, bpl, bsl, lsm, llpl; + Aminfo ai; + Cline lc = NULL; + LinkList l; Cmatch cm; + struct cmlist mst; + Cmlist oms = mstack; - if (menu && isset(AUTOMENU)) + if (aflags & CAF_ALT) { + l = fmatches; + ai = fainfo; + } else { + l = matches; + ai = ainfo; + } + if (match) { + mst.next = mstack; + mst.matcher = match; + mstack = &mst; + } + if ((aflags & CAF_MENU) && isset(AUTOMENU)) usemenu = 1; SWITCHHEAPS(compheap) { HEAPALLOC { + if (aflags & CAF_MATCH) { + ctokenize(lipre = dupstring(compiprefix)); + remnulargs(lipre); + ctokenize(lpre = dupstring(compprefix)); + remnulargs(lpre); + llpl = strlen(lpre); + ctokenize(lsuf = dupstring(compsuffix)); + remnulargs(lsuf); + } if (ipre) - ipre = dupstring(ipre); + ipre = (lipre ? dyncat(lipre, ipre) : dupstring(ipre)); if (ppre) { ppre = dupstring(ppre); lpl = strlen(ppre); @@ -2419,6 +2503,8 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, lsl = strlen(psuf); } else lsl = 0; + if (aflags & CAF_MATCH) + lsm = (psuf ? !strcmp(psuf, lsuf) : (!lsuf || !*lsuf)); if (pre) pre = dupstring(pre); if (suf) @@ -2430,10 +2516,12 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, prpre = dupstring(prpre); if (group) { endcmgroup(NULL); - begcmgroup(group, nosort); - if (nosort) + begcmgroup(group, (aflags & CAF_NOSORT)); + if (aflags & CAF_NOSORT) mgroup->flags |= CGF_NOSORT; } + if (rems) + rems = dupstring(rems); if (ai->pprefix) { if (pre) ai->pprefix[pfxlen(ai->pprefix, pre)] = '\0'; @@ -2442,10 +2530,54 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, } else ai->pprefix = dupstring(pre ? pre : ""); - for (; (s = *argv); argv++) { - if (ai->firstm) { - if ((i = pfxlen(ai->firstm->str, s)) < ai->prerest) - ai->prerest = i; + for (; (s = dupstring(*argv)); argv++) { + sl = strlen(s); + ms = NULL; + bpl = brpl; + bsl = brsl; + if ((!psuf || !*psuf) && (aflags & CAF_FIGNORE)) { + char **pt = fignore; + int filell; + + for (test = 1; test && *pt; pt++) + if ((filell = strlen(*pt)) < sl + && !strcmp(*pt, s + sl - filell)) + test = 0; + + if (!test) { + l = fmatches; + ai = fainfo; + } else { + l = matches; + ai = ainfo; + } + } + if (aflags & CAF_MATCH) { + t = (ppre ? dyncat(ppre, s) : s); + pl = sl + lpl; + if ((test = (llpl <= pl && !strncmp(t, lpre, pl)))) + test = lsm; + if (!test && mstack && + (ms = comp_match(lpre, lsuf, + (psuf ? dyncat(t, psuf) : t), + &lc, (aflags & CAF_QUOTE), + &bpl, &bsl))) + test = 1; + if (!test) + continue; + e = s + sl; + } else { + e = s; + pl = lpl; + } + if (!(aflags & CAF_QUOTE)) { + te = s + pl; + s = quotename(s, &e, te, &pl); + sl = strlen(s); + } + if (!ms && ai->firstm) { + if (sl < ai->minlen) + ai->minlen = sl; if ((i = sfxlen(ai->firstm->str, s)) < ai->suflen) ai->suflen = i; } @@ -2453,15 +2585,20 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, if (ppre) t = dyncat(ppre, t); if (ipre && *ipre) { + Cline tlc = prepend_cline(ipre, lc); + ai->noipre = 0; - if (ai->icpl > lpl) - ai->icpl = lpl; - if (ai->icsl > lsl) - ai->icsl = lsl; - if (ai->iaprefix) - ai->iaprefix[pfxlen(ai->iaprefix, t)] = '\0'; - else - ai->iaprefix = dupstring(t); + if (!ms) { + if ((aflags & CAF_MATCH) || ai->icpl > pl) + ai->icpl = pl; + if ((aflags & CAF_MATCH) || ai->icsl > lsl) + ai->icsl = lsl; + if (ai->iaprefix) + ai->iaprefix[pfxlen(ai->iaprefix, t)] = '\0'; + else + ai->iaprefix = dupstring(t); + } else + ai->ilinecl = join_clines(ai->ilinecl, lc); if (ai->iprefix) { if (strcmp(ipre, ai->iprefix)) ai->iprefix = ""; @@ -2469,16 +2606,21 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, ai->iprefix = dupstring(ipre); t = dyncat(ipre, t); + lc = tlc; } else ai->iprefix = ""; - if (ai->cpl > lpl) - ai->cpl = lpl; - if (ai->csl > lsl) - ai->csl = lsl; - if (ai->aprefix) - ai->aprefix[pfxlen(ai->aprefix, t)] = '\0'; - else - ai->aprefix = dupstring(t); + if (!ms) { + if ((aflags & CAF_MATCH) || ai->cpl > pl) + ai->cpl = pl; + if ((aflags & CAF_MATCH) || ai->csl > lsl) + ai->csl = lsl; + if (ai->aprefix) + ai->aprefix[pfxlen(ai->aprefix, t)] = '\0'; + else + ai->aprefix = dupstring(t); + } else + ai->linecl = join_clines(ai->linecl, lc); + mnum++; ai->count++; @@ -2486,25 +2628,41 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, cm->ppre = ppre; cm->psuf = psuf; cm->prpre = prpre; - if (!quote) - s = quotename(s, NULL, NULL, NULL); - cm->str = dupstring(s); + cm->str = (ms ? ms : dupstring(s)); cm->ipre = cm->ripre = ipre; cm->pre = pre; cm->suf = suf; cm->flags = flags; - cm->brpl = brpl; - cm->brsl = brsl; - addlinknode((alt ? fmatches : matches), cm); - - if (expl) - expl->fcount++; - if (!ai->firstm) - ai->firstm = cm; + cm->brpl = bpl; + cm->brsl = bsl; + cm->rems = rems; + addlinknode(l, cm); + + if (expl) { + if (l == matches) + expl->count++; + else + expl->fcount++; + } + if (!ms) { + if (!ai->firstm) + ai->firstm = cm; + if ((aflags & CAF_MATCH) && !(e - (s + pl))) { + if (!ai->exact) + ai->exact = 1; + else { + ai->exact = 2; + cm = NULL; + } + ai->exactm = cm; + } + } } compnmatches = mnum; } LASTALLOC; } SWITCHBACKHEAPS; + + mstack = oms; } /* This adds a match to the list of matches. The string to add is given * @@ -2685,8 +2843,8 @@ addmatch(char *s, char *t) if (!test) return; if (!ms && !ispattern && ai->firstm) { - if ((test = sl - pfxlen(ai->firstm->str, s)) < ai->prerest) - ai->prerest = test; + if (sl < ai->minlen) + ai->minlen = sl; if ((test = sfxlen(ai->firstm->str, s)) < ai->suflen) ai->suflen = test; } @@ -2716,8 +2874,7 @@ addmatch(char *s, char *t) ai->iaprefix[pfxlen(ai->iaprefix, t)] = '\0'; else ai->iaprefix = dupstring(t); - } - else + } else ai->ilinecl = join_clines(ai->ilinecl, lc); if (ai->iprefix) { if (strcmp(ipre, ai->iprefix)) @@ -2737,8 +2894,7 @@ addmatch(char *s, char *t) ai->aprefix[pfxlen(ai->aprefix, t)] = '\0'; else ai->aprefix = dupstring(t); - } - else + } else ai->linecl = join_clines(ai->linecl, lc); mnum++; @@ -2780,6 +2936,7 @@ addmatch(char *s, char *t) cm->flags = mflags | isf; cm->brpl = bpl; cm->brsl = bsl; + cm->rems = NULL; addlinknode(l, cm); /* One more match for this explanation. */ @@ -3211,7 +3368,12 @@ callcompfunc(char *s, char *fn) case IN_ENV: compcontext = "value"; compcommand = varname; - usea = 0; + if (!clwpos) { + clwpos = 1; + zsfree(clwords[1]); + clwords[1] = ztrdup(s); + } + aadd = 1; break; case IN_COND: compcontext = "condition"; @@ -3305,17 +3467,19 @@ makecomplist(char *s, int incmd, int lst) if (validlist) return !nmatches; + compmatcher = 1; for (;;) { if (m) { ms.next = NULL; ms.matcher = m->matcher; mstack = &ms; - } + } else + mstack = NULL; ainfo = (Aminfo) hcalloc(sizeof(struct aminfo)); fainfo = (Aminfo) hcalloc(sizeof(struct aminfo)); - ainfo->prerest = ainfo->suflen = - fainfo->prerest = fainfo->suflen = 10000; + ainfo->minlen = ainfo->suflen = + fainfo->minlen = fainfo->suflen = 10000; ainfo->noipre = fainfo->noipre= 1; freecl = NULL; @@ -3358,12 +3522,14 @@ makecomplist(char *s, int incmd, int lst) break; errflag = 0; + compmatcher++; } return 1; } /* This should probably be moved into tokenize(). */ +/**/ static char * ctokenize(char *p) { @@ -3564,10 +3730,11 @@ makecomplistcmd(char *os, int incmd, int flags) } /* Then search the pattern compctls, with the command name and the * * full pathname of the command. */ - makecomplistpc(os, incmd); - if (!(ccont & CC_CCCONT)) - return; - + if (cmdstr) { + makecomplistpc(os, incmd); + if (!(ccont & CC_CCCONT)) + return; + } /* If the command string starts with `=', try the path name of the * * command. */ if (cmdstr && cmdstr[0] == Equals) { @@ -5057,6 +5224,7 @@ dupmatch(Cmatch m) r->flags = m->flags; r->brpl = m->brpl; r->brsl = m->brsl; + r->rems = ztrdup(m->rems); return r; } @@ -5168,6 +5336,7 @@ freematch(Cmatch m) zsfree(m->ppre); zsfree(m->psuf); zsfree(m->prpre); + zsfree(m->rems); zfree(m, sizeof(m)); } @@ -5325,10 +5494,11 @@ do_ambiguous(void) * on the next call to completion the inserted string would be * * taken as a match and no menu completion would be started. */ - if (isset(RECEXACT) && !lc && !ainfo->prerest) + if (isset(RECEXACT) && !lc && ps && ainfo->minlen == strlen(ps)) am = 1; - /* If the LIST_AMBIGUOUS option (meaning roughly `show a list only * + /* + * If the LIST_AMBIGUOUS option (meaning roughly `show a list only * * if the completion is completely ambiguous') is set, and some * * prefix was inserted, return now, bypassing the list-displaying * * code. On the way, invalidate the list and note that we don't * @@ -5344,7 +5514,8 @@ do_ambiguous(void) * if it is needed. */ if (isset(LISTBEEP)) feep(); - if (isset(AUTOLIST) && !amenu && !showinglist && smatches >= 2) + if (isset(AUTOLIST) && !isset(BASHAUTOLIST) && !amenu && !showinglist && + smatches >= 2) showinglist = -2; if (am) lastambig = 1; @@ -5420,7 +5591,7 @@ do_single(Cmatch m) if (menuwe) { menuend += menuinsc; if (m->flags & CMF_REMOVE) { - makesuffix(menuinsc); + makesuffixstr(m->rems, menuinsc); if (menuinsc == 1) suffixlen[STOUC(m->suf[0])] = 1; } diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c index e699e438c..a116921b4 100644 --- a/Src/Zle/zle_vi.c +++ b/Src/Zle/zle_vi.c @@ -816,6 +816,10 @@ viswapcase(void) void vicapslockpanic(void) { + invalidatelist(); + moveto(0, 0); + clearflag = 0; + resetneeded = 1; zbeep(); statusline = "press a lowercase key to continue"; statusll = strlen(statusline); diff --git a/Src/builtin.c b/Src/builtin.c index ea1ac8ab9..2b77c57bc 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1036,6 +1036,9 @@ fixdir(char *src) { char *dest = src; char *d0 = dest; +#ifdef __CYGWIN__ + char *s0 = src; +#endif /*** if have RFS superroot directory ***/ #ifdef HAVE_SUPERROOT @@ -1052,6 +1055,11 @@ fixdir(char *src) for (;;) { /* compress multiple /es into single */ if (*src == '/') { +#ifdef __CYGWIN__ + /* allow leading // under cygwin */ + if (src == s0 && src[1] == '/') + *dest++ = *src++; +#endif *dest++ = *src++; while (*src == '/') src++; @@ -1657,7 +1665,8 @@ bin_typeset(char *name, char **argv, char *ops, int func) if (on & PM_TIED) { Param apm; - char *name1; + struct asgment asg0; + char *oldval = NULL; if (ops['m']) { zwarnnam(name, "incompatible options for -T", NULL, 0); @@ -1669,36 +1678,61 @@ bin_typeset(char *name, char **argv, char *ops, int func) return 1; } + if (!(asg = getasg(argv[0]))) + return 1; + asg0 = *asg; + if (!(asg = getasg(argv[1]))) + return 1; + if (!strcmp(asg0.name, asg->name)) { + zerrnam(name, "can't tie a variable to itself", NULL, 0); + return 1; + } + /* + * Keep the old value of the scalar. We need to do this + * here as if it is already tied to the same array it + * will be unset when we retie the array. This is all + * so that typeset -T is idempotent. + * + * We also need to remember here whether the damn thing is + * exported and pass that along. Isn't the world complicated? + */ + if ((pm = (Param) paramtab->getnode(paramtab, asg0.name)) + && !(pm->flags & PM_UNSET) + && (locallevel == pm->level || func == BIN_EXPORT)) { + if (!asg0.value && !(PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED))) + oldval = ztrdup(getsparam(asg0.name)); + on |= (pm->flags & PM_EXPORTED); + } /* * Create the tied array; this is normal except that * it has the PM_TIED flag set. Do it first because * we need the address. */ - if (!(asg = getasg(argv[1]))) - return 1; - name1 = ztrdup(asg->name); if (!(apm=typeset_single(name, asg->name, (Param)paramtab->getnode(paramtab, asg->name), - func, on | PM_ARRAY, off, roff, - asg->value, NULL))) + func, (on | PM_ARRAY) & ~PM_EXPORTED, + off, roff, asg->value, NULL))) return 1; /* * Create the tied colonarray. We make it as a normal scalar * and fix up the oddities later. */ - if (!(asg = getasg(argv[0])) || - !(pm=typeset_single(name, asg->name, + if (!(pm=typeset_single(name, asg0.name, (Param)paramtab->getnode(paramtab, - asg->name), - func, on, off, roff, asg->value, apm))) { + asg0.name), + func, on, off, roff, asg0.value, apm))) { + if (oldval) + zsfree(oldval); unsetparam_pm(apm, 1, 1); return 1; } - pm->ename = name1; - apm->ename = ztrdup(asg->name); + pm->ename = ztrdup(asg->name); + apm->ename = ztrdup(asg0.name); + if (oldval) + setsparam(asg0.name, oldval); return 0; } @@ -1928,14 +1962,39 @@ bin_unset(char *name, char **argv, char *ops, int func) /* do not glob -- unset the given parameter */ while ((s = *argv++)) { + char *ss = strchr(s, '['); + char *sse = ss; + if (ss) { + if (skipparens('[', ']', &sse) || *sse) { + zerrnam(name, "%s: invalid parameter name", s, 0); + returnval = 1; + continue; + } + *ss = 0; + } pm = (Param) paramtab->getnode(paramtab, s); if (!pm) returnval = 1; else if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) { zerrnam(name, "%s: restricted", pm->nam, 0); returnval = 1; + } else if (ss) { + if (PM_TYPE(pm->flags) == PM_HASHED) { + HashTable tht = paramtab; + if ((paramtab = pm->gets.hfn(pm))) { + *--sse = 0; + unsetparam(ss+1); + *sse = ']'; + } + paramtab = tht; + } else { + zerrnam(name, "%s: invalid element for unset", s, 0); + returnval = 1; + } } else - unsetparam(s); + unsetparam_pm(pm, 0, 1); + if (ss) + *ss = '['; } return returnval; } diff --git a/Src/compat.c b/Src/compat.c index ca9c57aac..b1bcbc21b 100644 --- a/Src/compat.c +++ b/Src/compat.c @@ -111,12 +111,17 @@ zgetdir(struct dirsav *d) { char nbuf[PATH_MAX+3]; char *buf; - int bufsiz, pos, len; + int bufsiz, pos; struct stat sbuf; + ino_t pino; + dev_t pdev; +#ifndef __CYGWIN__ struct dirent *de; DIR *dir; - ino_t ino, pino; - dev_t dev, pdev; + dev_t dev; + ino_t ino; + int len; +#endif buf = halloc(bufsiz = PATH_MAX); pos = bufsiz - 1; @@ -137,6 +142,7 @@ zgetdir(struct dirsav *d) #ifdef HAVE_FCHDIR else #endif +#ifndef __CYGWIN__ holdintr(); for (;;) { @@ -221,6 +227,21 @@ zgetdir(struct dirsav *d) if (*buf) zchdir(buf + pos + 1); noholdintr(); + +#else /* __CYGWIN__ case */ + + if (!getcwd(buf, bufsiz)) { + if (d) { + return NULL; + } + } else { + if (d) { + return d->dirname = ztrdup(buf); + } + return buf; + } +#endif + buf[0] = '.'; buf[1] = '\0'; return buf; diff --git a/Src/exec.c b/Src/exec.c index e563db6a4..bb331f426 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -148,6 +148,7 @@ parse_string(char *s) return l; } +/**/ #ifdef HAVE_GETRLIMIT /* the resource limits for the shell and its children */ @@ -184,6 +185,7 @@ setlimits(char *nam) return ret; } +/**/ #endif /* HAVE_GETRLIMIT */ /* fork and set limits */ diff --git a/Src/glob.c b/Src/glob.c index 7a3839576..5815f05a8 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -1432,7 +1432,7 @@ glob(LinkList list, LinkNode np) } } break; - case 'o': + case 'f': /* Match modes with chmod-spec. */ func = qualmodeflags; data = qgetmodespec(&s); @@ -1501,6 +1501,7 @@ glob(LinkList list, LinkNode np) data = qgetnum(&s); break; + case 'o': case 'O': { int t; @@ -1524,7 +1525,7 @@ glob(LinkList list, LinkNode np) } gf_sorts |= t; gf_sortlist[gf_nsorts++] = t | - ((sense & 1) ? GS_DESC : 0); + (((sense & 1) ^ (s[-1] == 'O')) ? GS_DESC : 0); s++; break; } diff --git a/Src/init.c b/Src/init.c index 5e0a550dd..10013c52b 100644 --- a/Src/init.c +++ b/Src/init.c @@ -28,11 +28,12 @@ */ #include "zsh.mdh" -#include "init.pro" #include "zshpaths.h" #include "zshxmods.h" +#include "init.pro" + /**/ int noexitct = 0; @@ -300,22 +301,19 @@ init_io(void) /* Make sure the tty is opened read/write. */ if (isatty(0)) { + zsfree(ttystrname); + if ((ttystrname = ztrdup(ttyname(0)))) { + SHTTY = movefd(open(ttystrname, O_RDWR | O_NOCTTY)); #ifdef TIOCNXCL - /* - * See if the terminal claims to be busy. If so, and fd 0 - * is a terminal, try and set non-exclusive use for that. - * This is something to do with Solaris over-cleverness. - */ - int tmpfd; - if ((tmpfd = open("/dev/tty", O_RDWR | O_NOCTTY)) < 0) { - if (errno == EBUSY) + /* + * See if the terminal claims to be busy. If so, and fd 0 + * is a terminal, try and set non-exclusive use for that. + * This is something to do with Solaris over-cleverness. + */ + if (SHTTY == -1 && errno == EBUSY) ioctl(0, TIOCNXCL, 0); - } else - close(tmpfd); #endif - zsfree(ttystrname); - if ((ttystrname = ztrdup(ttyname(0)))) - SHTTY = movefd(open(ttystrname, O_RDWR | O_NOCTTY)); + } /* * xterm, rxvt and probably all terminal emulators except * dtterm on Solaris 2.6 & 7 have a bug. Applications are @@ -936,6 +934,7 @@ noop_function_int(int nothing) /* do nothing */ } +/**/ # ifdef UNLINKED_XMOD_zle /**/ @@ -947,6 +946,7 @@ autoload_zleread(char *lp, char *rp, int ha) return zleread(lp, rp, ha); } +/**/ # endif /* UNLINKED_XMOD_zle */ /**/ diff --git a/Src/makepro.awk b/Src/makepro.awk index 86117fcc1..3306d41d4 100644 --- a/Src/makepro.awk +++ b/Src/makepro.awk @@ -40,6 +40,13 @@ BEGIN { aborting = 1 exit 1 } + if (line == "" && $0 ~ /^[ \t]*#/) { + # Directly after the /**/ was a preprocessor line. + # Spit it out and re-start the outer loop. + printf "%s\n", $0 + locals = locals $0 "\n" + next + } gsub(/\t/, " ") line = line " " $0 gsub(/\/\*([^*]|\*+[^*\/])*\*+\//, " ", line) diff --git a/Src/options.c b/Src/options.c index 745a6627c..693132494 100644 --- a/Src/options.c +++ b/Src/options.c @@ -90,6 +90,7 @@ static struct optname optns[] = { {NULL, "badpattern", OPT_EMULATE|OPT_NONBOURNE, BADPATTERN}, {NULL, "banghist", OPT_EMULATE|OPT_NONBOURNE, BANGHIST}, {NULL, "bareglobqual", OPT_EMULATE|OPT_ZSH, BAREGLOBQUAL}, +{NULL, "bashautolist", 0, BASHAUTOLIST}, {NULL, "beep", OPT_ALL, BEEP}, {NULL, "bgnice", OPT_EMULATE|OPT_NONBOURNE, BGNICE}, {NULL, "braceccl", 0, BRACECCL}, diff --git a/Src/params.c b/Src/params.c index f57413a2e..f91a448a1 100644 --- a/Src/params.c +++ b/Src/params.c @@ -1500,7 +1500,7 @@ setsparam(char *s, char *val) } else { if (!(v = getvalue(&s, 1))) createparam(t, PM_SCALAR); - else if (PM_TYPE(v->pm->flags) == PM_ARRAY && + else if ((PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) && !(v->pm->flags & (PM_SPECIAL|PM_TIED)) && unset(KSHARRAYS)) { unsetparam(t); createparam(t, PM_SCALAR); diff --git a/Src/subst.c b/Src/subst.c index b77dbd4a4..422c9c4e9 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -718,10 +718,12 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) int copied = 0; int arrasg = 0; int eval = 0; + int aspar = 0; int nojoin = 0; char inbrace = 0; /* != 0 means ${...}, otherwise $... */ char hkeys = 0; char hvals = 0; + int subexp; *s++ = '\0'; if (!ialnum(*s) && *s != '#' && *s != Pound && *s != '-' && @@ -813,6 +815,9 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) case 'e': eval = 1; break; + case 'P': + aspar = 1; + break; case 'c': whichlen = 1; @@ -949,7 +954,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) } else globsubst = 1; } else if (*s == '+') { - if (iident(s[1])) + if (iident(s[1]) || (aspar && isstring(s[1]) && + (s[2] == Inbrace || s[2] == Inpar))) chkset = 1, s++; else if (!inbrace) { *aptr = '$'; @@ -965,7 +971,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) globsubst = globsubst && !qt; idbeg = s; - if (s[-1] && isstring(*s) && (s[1] == Inbrace || s[1] == Inpar)) { + if ((subexp = (s[-1] && isstring(*s) && + (s[1] == Inbrace || s[1] == Inpar)))) { int sav; int quoted = *s == Qstring; @@ -973,17 +980,28 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) skipparens(*s, *s == Inpar ? Outpar : Outbrace, &s); sav = *s; *s = 0; - if (multsub(&val, &aval, &isarr, NULL) && quoted) { + if (multsub(&val, (aspar ? NULL : &aval), &isarr, NULL) && quoted) { isarr = -1; aval = alloc(sizeof(char *)); - } + aspar = 0; + } else if (aspar) + idbeg = val; if (isarr) isarr = -1; copied = 1; *s = sav; v = (Value) NULL; - } else { - if (!(v = fetchvalue(&s, (wantt ? -1 : + } else if (aspar) { + if ((v = getvalue(&s, 1))) { + val = idbeg = getstrvalue(v); + subexp = 1; + } else + vunset = 1; + } + if (!subexp || aspar) { + char *ov = val; + + if (!(v = fetchvalue((subexp ? &ov : &s), (wantt ? -1 : ((unset(KSHARRAYS) || inbrace) ? 1 : -1)), hkeys|hvals))) vunset = 1; @@ -1690,6 +1708,7 @@ modify(char **str, char **ptr) case 't': case 'l': case 'u': + case 'q': c = **ptr; break; @@ -1808,6 +1827,9 @@ modify(char **str, char **ptr) if (hsubl && hsubr) subst(©, hsubl, hsubr, gbal); break; + case 'q': + copy = bslashquote(copy, NULL, NULL, NULL, 0); + break; } tc = *tt; *tt = '\0'; @@ -1859,6 +1881,9 @@ modify(char **str, char **ptr) } } break; + case 'q': + *str = bslashquote(*str, NULL, NULL, NULL, 0); + break; } } if (rec < 0) { diff --git a/Src/utils.c b/Src/utils.c index 90da15368..18a797948 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -446,7 +446,8 @@ finddir_scan(HashNode hn, int flags) { Nameddir nd = (Nameddir) hn; - if(nd->diff > finddir_best && !dircmp(nd->dir, finddir_full)) { + if(nd->diff > finddir_best && !dircmp(nd->dir, finddir_full) + && !(nd->flags & ND_NOABBREV)) { finddir_last=nd; finddir_best=nd->diff; } @@ -514,9 +515,8 @@ adduserdir(char *s, char *t, int flags, int always) * with always==0. Unless the AUTO_NAME_DIRS option is set, we * * don't let such assignments actually create directory names. * * Instead, a reference to the parameter as a directory name can * - * cause the actual creation of the hash table entry. Never hash * - * PWD unless it was explicitly requested (or already hashed). */ - if (!always && (unset(AUTONAMEDIRS) || !strcmp(s, "PWD")) && + * cause the actual creation of the hash table entry. */ + if (!always && unset(AUTONAMEDIRS) && !nameddirtab->getnode2(nameddirtab, s)) return; @@ -534,6 +534,9 @@ adduserdir(char *s, char *t, int flags, int always) nd = (Nameddir) zcalloc(sizeof *nd); nd->flags = flags; nd->dir = ztrdup(t); + /* The variables PWD and OLDPWD are not to be displayed as ~PWD etc. */ + if (!strcmp(s, "PWD") || !strcmp(s, "OLDPWD")) + nd->flags |= ND_NOABBREV; nameddirtab->addnode(nameddirtab, ztrdup(s), nd); } @@ -1150,11 +1153,24 @@ checkrmall(char *s) return (getquery("ny", 1) == 'y'); } +/**/ +int +read1char(void) +{ + char c; + + while (read(SHTTY, &c, 1) != 1) { + if (errno != EINTR) + return -1; + } + return STOUC(c); +} + /**/ int getquery(char *valid_chars, int purge) { - char c, d; + int c, d; int isem = !strcmp(term, "emacs"); #ifdef FIONREAD @@ -1177,7 +1193,7 @@ getquery(char *valid_chars, int purge) return 'n'; } #endif - while (read(SHTTY, &c, 1) == 1) { + while ((c = read1char()) >= 0) { if (c == 'Y' || c == '\t') c = 'y'; else if (c == 'N') @@ -1199,13 +1215,13 @@ getquery(char *valid_chars, int purge) } if (isem) { if (c != '\n') - while (read(SHTTY, &d, 1) == 1 && d != '\n'); + while ((d = read1char()) >= 0 && d != '\n'); } else { settyinfo(&shttyinfo); if (c != '\n' && !valid_chars) write(SHTTY, "\n", 1); } - return (int)c; + return c; } static int d; @@ -3109,6 +3125,73 @@ 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. Like * + * e, te may point to a position in the string and pl is used to return * + * the position of the character pointed to by te in the quoted string. * + * 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, and * + * two if it is for the inside of double quoted string. * + * The string may be metafied and contain tokens. */ + +/**/ +char * +bslashquote(const char *s, char **e, char *te, int *pl, int instring) +{ + const char *u, *tt; + char *v, buf[PATH_MAX * 2]; + int sf = 0; + + tt = v = buf; + u = s; + for (; *u; u++) { + if (e && *e == u) + *e = v, sf |= 1; + if (te == u) + *pl = v - tt, sf |= 2; + if (ispecial(*u) && + (!instring || (isset(BANGHIST) && + *u == (char)bangchar) || + (instring == 2 && + (*u == '$' || *u == '`' || *u == '\"')) || + (instring == 1 && *u == '\''))) { + if (*u == '\n' || (instring == 1 && *u == '\'')) { + if (unset(RCQUOTES)) { + *v++ = '\''; + if (*u == '\'') + *v++ = '\\'; + *v++ = *u; + *v++ = '\''; + } else if (*u == '\n') + *v++ = '"', *v++ = '\n', *v++ = '"'; + else + *v++ = '\'', *v++ = '\''; + continue; + } else + *v++ = '\\'; + } + if(*u == Meta) + *v++ = *u++; + *v++ = *u; + } + *v = '\0'; + if (strcmp(buf, s)) + tt = dupstring(buf); + else + tt = s; + v += tt - buf; + if (e && (sf & 1)) + *e += tt - buf; + + if (e && *e == u) + *e = v; + if (te == u) + *pl = v - tt; + + return (char *) tt; +} + /* Unmetafy and output a string, quoted if it contains special characters. */ /**/ @@ -3349,12 +3432,19 @@ getkeystring(char *s, int *len, int fromwhere, int *misc) case Meta: *t++ = '\\', s--; break; + case '-': + if (fromwhere == 5) { + *misc = 1; + break; + } + goto def; case 'c': if (fromwhere < 2) { *misc = 1; break; } default: + def: if ((idigit(*s) && *s < '8') || *s == 'x') { if (!fromwhere) { if (*s == '0') @@ -3386,7 +3476,7 @@ getkeystring(char *s, int *len, int fromwhere, int *misc) } else if (fromwhere == 4 && *s == Snull) { for (u = t; (*u++ = *s++);); return t + 1; - } else if (*s == '^' && fromwhere == 2) { + } else if (*s == '^' && (fromwhere == 2 || fromwhere == 5)) { control = 1; continue; } else if (*s == Meta) diff --git a/Src/zsh.export b/Src/zsh.export index 32c0e7d3c..bfad7aea2 100644 --- a/Src/zsh.export +++ b/Src/zsh.export @@ -14,6 +14,7 @@ attachtty bangchar bin_notavail breaks +bslashquote bufstack builtintab chline @@ -55,6 +56,7 @@ exlast expanding fallback_compctlread fallback_zleread +fetchvalue fignore file_type filesub @@ -72,6 +74,7 @@ getkeystring getlinknode getshfunc getsparam +getstrvalue gettempname glob_pre glob_suf @@ -228,6 +231,7 @@ ugetnode uinsertlinknode unmeta unmetafy +unsetparam unsetparam_pm untokenize uremnode diff --git a/Src/zsh.h b/Src/zsh.h index e23f9c895..87ec3e0c0 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -963,6 +963,7 @@ struct nameddir { /* flags for named directories */ /* DISABLED is defined (1<<0) */ #define ND_USERNAME (1<<1) /* nam is actually a username */ +#define ND_NOABBREV (1<<2) /* never print as abbrev (PWD or OLDPWD) */ /* flags for controlling printing of hash table nodes */ @@ -1056,6 +1057,7 @@ enum { BADPATTERN, BANGHIST, BAREGLOBQUAL, + BASHAUTOLIST, BEEP, BGNICE, BRACECCL, -- cgit 1.4.1