From d6d4a3abfc84f0940e663cd69537789a039a7056 Mon Sep 17 00:00:00 2001 From: Tanaka Akira Date: Mon, 19 Jul 1999 14:26:14 +0000 Subject: zsh-3.1.6-test-2 --- Src/Modules/zftp.c | 6 +- Src/Zle/comp.h | 26 ++++---- Src/Zle/comp1.c | 1 + Src/Zle/comp1.export | 1 + Src/Zle/compctl.c | 1 + Src/Zle/complist.c | 42 +++++++------ Src/Zle/zle.export | 1 + Src/Zle/zle_params.c | 25 +------- Src/Zle/zle_refresh.c | 8 ++- Src/Zle/zle_tricky.c | 162 ++++++++++++++++++++++++++++++++++++-------------- Src/builtin.c | 114 ++++++++++++++++++++++------------- Src/exec.c | 17 +++++- Src/glob.c | 10 +++- Src/lex.c | 1 + Src/options.c | 1 + Src/parse.c | 26 +++++--- Src/utils.c | 99 +++++++++++++++--------------- Src/zsh.h | 1 + 18 files changed, 342 insertions(+), 200 deletions(-) (limited to 'Src') diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c index 63bca854c..738d596fa 100644 --- a/Src/Modules/zftp.c +++ b/Src/Modules/zftp.c @@ -2261,7 +2261,7 @@ zftp_type(char *name, char **args, int flags) fflush(stdout); return 0; } else { - nt = toupper(*str); + nt = toupper(STOUC(*str)); /* * RFC959 specifies other types, but these are the only * ones we know what to do with. @@ -2294,7 +2294,7 @@ zftp_mode(char *name, char **args, int flags) fflush(stdout); return 0; } - nt = str[0] = toupper(*str); + nt = str[0] = toupper(STOUC(*str)); if (str[1] || (nt != 'S' && nt != 'B')) { zwarnnam(name, "transfer mode %s not recognised", str, 0); return 1; @@ -2651,7 +2651,7 @@ bin_zftp(char *name, char **args, char *ops, int func) if ((prefs = getsparam("ZFTP_PREFS"))) { zfprefs = 0; for (ptr = prefs; *ptr; ptr++) { - switch (toupper(*ptr)) { + switch (toupper(STOUC(*ptr))) { case 'S': /* sendport */ zfprefs |= ZFPF_SNDP; diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h index 8264890df..b0fbf3ac6 100644 --- a/Src/Zle/comp.h +++ b/Src/Zle/comp.h @@ -218,6 +218,8 @@ struct cmatch { int brsl; /* ...and the suffix */ char *rems; /* when to remove the suffix */ char *remf; /* shell function to call for suffix-removal */ + int qipl; /* length of quote-prefix */ + int qisl; /* length of quote-suffix */ int rnum; /* group relative number */ int gnum; /* global number */ }; @@ -349,25 +351,25 @@ struct chdata { #define CPN_NMATCHES 0 -#define CP_NMATCHES (1 << CPN_NMATCHES) +#define CP_NMATCHES (1 << CPN_NMATCHES) #define CPN_MATCHER 1 -#define CP_MATCHER (1 << CPN_MATCHER) +#define CP_MATCHER (1 << CPN_MATCHER) #define CPN_MATCHERSTR 2 -#define CP_MATCHERSTR (1 << CPN_MATCHERSTR) +#define CP_MATCHERSTR (1 << CPN_MATCHERSTR) #define CPN_MATCHERTOT 3 -#define CP_MATCHERTOT (1 << CPN_MATCHERTOT) +#define CP_MATCHERTOT (1 << CPN_MATCHERTOT) #define CPN_CONTEXT 4 -#define CP_CONTEXT (1 << CPN_CONTEXT) +#define CP_CONTEXT (1 << CPN_CONTEXT) #define CPN_PARAMETER 5 -#define CP_PARAMETER (1 << CPN_PARAMETER) +#define CP_PARAMETER (1 << CPN_PARAMETER) #define CPN_REDIRECT 6 -#define CP_REDIRECT (1 << CPN_REDIRECT) +#define CP_REDIRECT (1 << CPN_REDIRECT) #define CPN_QUOTE 7 -#define CP_QUOTE (1 << CPN_QUOTE) +#define CP_QUOTE (1 << CPN_QUOTE) #define CPN_QUOTING 8 -#define CP_QUOTING (1 << CPN_QUOTING) +#define CP_QUOTING (1 << CPN_QUOTING) #define CPN_RESTORE 9 -#define CP_RESTORE (1 << CPN_RESTORE) +#define CP_RESTORE (1 << CPN_RESTORE) #define CPN_LIST 10 #define CP_LIST (1 << CPN_LIST) #define CPN_FORCELIST 11 @@ -398,6 +400,8 @@ struct chdata { #define CP_OLDINS (1 << CPN_OLDINS) #define CPN_VARED 24 #define CP_VARED (1 << CPN_VARED) +#define CPN_NNMATCHES 25 +#define CP_NNMATCHES (1 << CPN_NNMATCHES) -#define CP_KEYPARAMS 25 +#define CP_KEYPARAMS 26 #define CP_ALLKEYS ((unsigned int) 0xffffff) diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c index ba8bcc868..c1e2bfb57 100644 --- a/Src/Zle/comp1.c +++ b/Src/Zle/comp1.c @@ -105,6 +105,7 @@ int incompfunc; /**/ zlong compcurrent, compnmatches, + compnnmatches, compmatcher, compmatchertot, complistmax; diff --git a/Src/Zle/comp1.export b/Src/Zle/comp1.export index 9b738cc78..4b6dd92fd 100644 --- a/Src/Zle/comp1.export +++ b/Src/Zle/comp1.export @@ -27,6 +27,7 @@ compmatcher compmatcherstr compmatchertot compnmatches +compnnmatches compoldlist compoldins compparameter diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 694af8429..e9ff83387 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -2210,6 +2210,7 @@ static struct compparam compkparams[] = { { "old_list", PM_SCALAR, VAL(compoldlist), NULL, NULL }, { "old_insert", PM_SCALAR, VAL(compoldins), NULL, NULL }, { "vared", PM_SCALAR, VAL(compvared), NULL, NULL }, + { "normal_nmatches", PM_INTEGER, VAL(compnnmatches), NULL, NULL }, { NULL, 0, NULL, NULL, NULL } }; diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c index 0e7152866..4bf3fec0e 100644 --- a/Src/Zle/complist.c +++ b/Src/Zle/complist.c @@ -308,8 +308,8 @@ complistmatches(Hookdef dummy, Chdata dat) Cmatch *p, m; Cexpl *e; int nlines = 0, ncols, nlist = 0, longest = 1, pnl = 0, opl = 0; - int of = isset(LISTTYPES); - int mc, ml = 0, cc, hasm = 0, cl; + int of = isset(LISTTYPES), cf; + int mc, ml = 0, cc, hasm = 0, cl = -1; struct listcols col; if (minfo.asked == 2) { @@ -318,15 +318,6 @@ complistmatches(Hookdef dummy, Chdata dat) } getcols(&col); - /* Set the cursor below the prompt. */ - if (inselect) - clearflag = 0; - trashzle(); - showinglist = listshown = 0; - - clearflag = (isset(USEZLE) && !termflags && - complastprompt && *complastprompt); - for (g = amatches; g; g = g->next) { char **pp = g->ylist; int nl = 0, l; @@ -403,6 +394,19 @@ complistmatches(Hookdef dummy, Chdata dat) nlines += 1 + ((1 + niceztrlen(m->str)) / columns); } } + cf = (isset(USEZLE) && !termflags && complastprompt && *complastprompt); + if (!nlines || (mselect >= 0 && (!cf || (nlines + nlnct - 1) >= lines))) { + showinglist = listshown = 0; + noselect = 1; + return 1; + } + /* Set the cursor below the prompt. */ + if (inselect) + clearflag = 0; + trashzle(); + showinglist = listshown = 0; + + clearflag = cf; /* Maybe we have to ask if the user wants to see the list. */ if ((!minfo.cur || !minfo.asked) && @@ -654,20 +658,20 @@ complistmatches(Hookdef dummy, Chdata dat) pnl = 1; g = g->next; } - if (clearflag) { /* Move the cursor up to the prompt, if always_last_prompt * * is set and all that... */ if ((nlines += nlnct - 1) < lines) { tcmultout(TCUP, TCMULTUP, nlines); showinglist = -1; - listshown = 1; } else clearflag = 0, putc('\n', shout); } else putc('\n', shout); + listshown = (clearflag ? 1 : -1); if (!hasm || nlines >= lines) noselect = 1; + return noselect; } @@ -676,7 +680,7 @@ typedef struct menustack *Menustack; struct menustack { Menustack prev; char *line; - int cs; + int cs, acc; struct menuinfo info; Cmgroup amatches, pmatches, lmatches; }; @@ -742,19 +746,19 @@ domenuselect(Hookdef dummy, Chdata dat) s->amatches = amatches; s->pmatches = pmatches; s->lmatches = lmatches; - menucmp = 0; + s->acc = menuacc; + menucmp = menuacc = 0; fixsuffix(); validlist = 0; pmatches = NULL; invalidatelist(); menucomplete(zlenoargs); if (dat->num < 2 || !minfo.cur || !*(minfo.cur)) { - noselect = 1; - clearlist = 1; + noselect = clearlist = listshown = 1; zrefresh(); break; } - clearlist = 1; + clearlist = listshown = 1; mselect = (*(minfo.cur))->gnum; continue; } else if (cmd == Th(z_acceptandhold) || @@ -767,6 +771,7 @@ domenuselect(Hookdef dummy, Chdata dat) s->cs = cs; memcpy(&(s->info), &minfo, sizeof(struct menuinfo)); s->amatches = s->pmatches = s->lmatches = NULL; + s->acc = menuacc; acceptlast(); do_menucmp(0); mselect = (*(minfo.cur))->gnum; @@ -782,6 +787,7 @@ domenuselect(Hookdef dummy, Chdata dat) spaceinline(l = strlen(u->line)); strncpy((char *) line, u->line, l); cs = u->cs; + menuacc = u->acc; memcpy(&minfo, &(u->info), sizeof(struct menuinfo)); p = &(minfo.cur); if (u->pmatches && pmatches != u->pmatches) { diff --git a/Src/Zle/zle.export b/Src/Zle/zle.export index 8bc049e16..f63f45eb8 100644 --- a/Src/Zle/zle.export +++ b/Src/Zle/zle.export @@ -24,6 +24,7 @@ lastambig linkkeymap listshown lmatches +menuacc menucmp menucomplete menucur diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c index dc4e27685..5ed846cd6 100644 --- a/Src/Zle/zle_params.c +++ b/Src/Zle/zle_params.c @@ -67,7 +67,7 @@ static struct zleparam { zleunsetfn, NULL }, { "LASTWIDGET", PM_SCALAR | PM_READONLY, NULL, FN(get_lwidget), zleunsetfn, NULL }, - { "keys", PM_ARRAY | PM_READONLY, NULL, FN(get_keys), + { "KEYS", PM_SCALAR | PM_READONLY, NULL, FN(get_keys), zleunsetfn, NULL }, { "NUMERIC", PM_INTEGER | PM_UNSET, FN(set_numeric), FN(get_numeric), unset_numeric, NULL }, @@ -247,29 +247,10 @@ get_lwidget(Param pm) } /**/ -static char ** +static char * get_keys(Param pm) { - char **r, **q, *p, *k, c; - - r = (char **) zhalloc((strlen(keybuf) + 1) * sizeof(char *)); - for (q = r, p = keybuf; (c = *p); q++, p++) { - k = *q = (char *) zhalloc(5); - if (c & 0x80) { - *k++ = 'M'; - *k++ = '-'; - c &= 0x7f; - } - if (c < 32 || c == 0x7f) { - *k++ = '^'; - c ^= 64; - } - *k++ = c; - *k = '\0'; - } - *q = NULL; - - return r; + return keybuf; } /**/ diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index 48e1071b8..1dbffc21c 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -53,7 +53,8 @@ int nlnct; /**/ int showinglist; -/* Non-zero if a completion list was displayed. */ +/* > 0 if a completion list is displayed below the prompt, + * < 0 if a list is displayed above the prompt. */ /**/ int listshown; @@ -265,7 +266,7 @@ zrefresh(void) if (inlist) return; - if (clearlist && listshown) { + if (clearlist && listshown > 0) { if (tccan(TCCLEAREOD)) { int ovln = vln, ovcs = vcs; char *nb = nbuf[vln]; @@ -331,7 +332,8 @@ zrefresh(void) tcout(TCCLEAREOD); else cleareol = 1; /* request: clear to end of line */ - listshown = 0; + if (listshown > 0) + listshown = 0; } if (t0 > -1) olnct = t0; diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index 5461079cb..b678a5cad 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -106,10 +106,11 @@ static int insmnum, insgnum, insgroup, insspace; static int movetoend; -/* != 0 if we are in the middle of a menu completion */ +/* != 0 if we are in the middle of a menu completion and number of matches +* accepted with accept-and-menu-complete */ /**/ -int menucmp; +int menucmp, menuacc; /* Information about menucompletion. */ @@ -192,6 +193,10 @@ static char *qipre, *qisuf, autoq; static int lpl, lsl, rpl, rsl, fpl, fsl, lppl, lpsl; static int noreal; +/* A parameter expansion prefix (like ${). */ + +static char *parpre; + /* This is either zero or equal to the special character the word we are * * trying to complete starts with (e.g. Tilde or Equals). */ @@ -209,9 +214,9 @@ static char *qword; static Cmgroup mgroup; -/* A match counter. */ +/* Match counters: all matches, normal matches (not alternate set). */ -static int mnum; +static int mnum, nmnum; /* The match counter when unambig_data() was called. */ @@ -540,6 +545,8 @@ reversemenucomplete(char **args) void acceptlast(void) { + menuacc++; + if (brbeg && *brbeg) { int l; @@ -553,10 +560,16 @@ acceptlast(void) brbeg[l] = ','; brbeg[l + 1] = '\0'; } else { + int l; + cs = minfo.pos + minfo.len + minfo.insc; iremovesuffix(' ', 1); - + l = cs; + cs = minfo.pos + minfo.len - (*(minfo.cur))->qisl; + foredel(l - cs); inststrlen(" ", 1, 1); + if (parpre) + inststr(parpre); minfo.insc = minfo.len = 0; minfo.pos = cs; minfo.we = 1; @@ -694,6 +707,9 @@ check_param(char *s, int set, int test) { char *p; + zsfree(parpre); + parpre = NULL; + if (!test) ispar = parq = eparq = 0; /* Try to find a `$'. */ @@ -755,6 +771,8 @@ check_param(char *s, int set, int test) /* Now make sure that the cursor is inside the name. */ if (offs <= e - s && offs >= b - s && n <= 0) { + char sav; + if (br) { p = e; while (*p == (test ? Dnull : '"')) @@ -782,6 +800,12 @@ check_param(char *s, int set, int test) else parq = eparq = 0; + /* Save the prefix. */ + sav = *b; + *b = '\0'; + untokenize(parpre = ztrdup(s)); + *b = sav; + /* And adjust wb, we, and offs again. */ offs -= b - s; wb = cs - offs; @@ -1017,7 +1041,7 @@ docomplete(int lst) int ocs = cs, ne = noerrs; noerrs = 1; - doexpansion(s, lst, olst, lincmd); + ret = doexpansion(s, lst, olst, lincmd); lastambig = 0; noerrs = ne; @@ -1043,8 +1067,8 @@ docomplete(int lst) } } ret = docompletion(s, lst, lincmd); - } else - ret = !strcmp(ol, (char *) line); + } else if (ret) + clearlist = 1; } else /* Just do completion. */ ret = docompletion(s, lst, lincmd); @@ -1064,7 +1088,7 @@ docomplete(int lst) dat.num = nmatches; dat.cur = NULL; if (runhookdef(MENUSTARTHOOK, (void *) &dat)) - menucmp = 0; + menucmp = menuacc = 0; } return ret; } @@ -1736,9 +1760,10 @@ get_comp_string(void) /* Expand the current word. */ /**/ -static void +static int doexpansion(char *s, int lst, int olst, int explincmd) { + int ret = 1; LinkList vl; char *ss; @@ -1775,7 +1800,7 @@ doexpansion(char *s, int lst, int olst, int explincmd) } if (lst == COMP_LIST_EXPAND) { /* Only the list of expansions was requested. */ - listlist(vl); + ret = listlist(vl); showinglist = 0; goto end; } @@ -1783,6 +1808,7 @@ doexpansion(char *s, int lst, int olst, int explincmd) cs = wb; foredel(we - wb); while ((ss = (char *)ugetnode(vl))) { + ret = 0; untokenize(ss); ss = quotename(ss, NULL); inststr(ss); @@ -1801,6 +1827,8 @@ doexpansion(char *s, int lst, int olst, int explincmd) end: popheap(); } LASTALLOC; + + return ret; } /* This is called from the lexer to give us word positions. */ @@ -3547,6 +3575,8 @@ add_match_data(int alt, char *str, Cline line, ai->line = join_clines(ai->line, line); mnum++; + if (!alt) + nmnum++; ai->count++; /* Allocate and fill the match structure. */ @@ -3569,6 +3599,8 @@ add_match_data(int alt, char *str, Cline line, cm->flags = flags; cm->brpl = bpl; cm->brsl = bsl; + cm->qipl = qipl; + cm->qisl = qisl; cm->autoq = (autoq ? autoq : (inbackt ? '`' : '\0')); cm->rems = cm->remf = NULL; addlinknode((alt ? fmatches : matches), cm); @@ -3896,6 +3928,7 @@ addmatches(Cadata dat, char **argv) } } compnmatches = mnum; + compnnmatches = nmnum; if (dat->exp) addexpl(); if (dat->apar) @@ -4380,10 +4413,14 @@ docompletion(char *s, int lst, int incmd) } if (comppatmatch && *comppatmatch && comppatmatch != opm) haspattern = 1; - if (!useline && uselist) + if (!useline && uselist) { /* All this and the guy only wants to see the list, sigh. */ + cs = 0; + foredel(ll); + inststr(origline); + cs = origcs; showinglist = -2; - else if (useline) { + } else if (useline) { /* We have matches. */ if (nmatches > 1) { /* There is more than one match. */ @@ -4399,9 +4436,13 @@ docompletion(char *s, int lst, int incmd) do_single(m->matches[0]); invalidatelist(); } - } else + } else { invalidatelist(); - + cs = 0; + foredel(ll); + inststr(origline); + cs = origcs; + } /* Print the explanation strings if needed. */ if (!showinglist && validlist && usemenu != 2 && nmatches != 1) { Cmgroup g = amatches; @@ -4582,22 +4623,22 @@ callcompfunc(char *s, char *fn) zsfree(compprefix); zsfree(compsuffix); if (unset(COMPLETEINWORD)) { - /* Maybe we'll have to do quoting here some time. */ - tmp = dupstring(s); + tmp = quotename(s, NULL); untokenize(tmp); compprefix = ztrdup(tmp); compsuffix = ztrdup(""); } else { char *ss, sav; - tmp = dupstring(s); - ss = tmp + offs; + ss = s + offs; sav = *ss; *ss = '\0'; + tmp = quotename(s, NULL); untokenize(tmp); compprefix = ztrdup(tmp); *ss = sav; + ss = quotename(ss, NULL); untokenize(ss); compsuffix = ztrdup(ss); } @@ -4611,6 +4652,7 @@ callcompfunc(char *s, char *fn) compqisuffix = ztrdup(qisuf ? qisuf : ""); compcurrent = (usea ? (clwpos + 1 - aadd) : 0); compnmatches = mnum; + compnnmatches = nmnum; zsfree(complist); switch (uselist) { @@ -4825,13 +4867,13 @@ makecomplist(char *s, int incmd, int lst) if (!validlist) lastambig = 0; amatches = NULL; - mnum = 0; + mnum = nmnum = 0; unambig_mnum = -1; isuf = NULL; insmnum = insgnum = 1; insgroup = oldlist = oldins = 0; begcmgroup("default", 0); - menucmp = 0; + menucmp = menuacc = 0; ccused = newlinklist(); ccstack = newlinklist(); @@ -4984,6 +5026,8 @@ sep_comp_string(char *ss, char *s, int noffs, int rec) memcpy(tmp + sl + 1, s, noffs); tmp[(scs = cs = sl + 1 + noffs)] = 'x'; strcpy(tmp + sl + 2 + noffs, s + noffs); + if (incompfunc) + tmp = rembslash(tmp); inpush(dupstrspace(tmp), 0, NULL); line = (unsigned char *) tmp; ll = tl - 1; @@ -5013,6 +5057,7 @@ sep_comp_string(char *ss, char *s, int noffs, int rec) p = NULL; if (!got && !zleparse) { DPUTS(!p, "no current word in substr"); + got = 1; cur = i; swb = wb - 1; swe = we - 1; @@ -5077,7 +5122,7 @@ sep_comp_string(char *ss, char *s, int noffs, int rec) } sav = s[(i = swb - sl - 1)]; s[i] = '\0'; - qp = tricat(qipre, s, ""); + qp = tricat(qipre, (incompfunc ? rembslash(s) : s), ""); s[i] = sav; if (swe < swb) swe = swb; @@ -5085,7 +5130,7 @@ sep_comp_string(char *ss, char *s, int noffs, int rec) sl = strlen(s); if (swe > sl) swe = sl, ns[swe - swb + 1] = '\0'; - qs = tricat(s + swe, qisuf, ""); + qs = tricat((incompfunc ? rembslash(s + swe) : s + swe), qisuf, ""); sl = strlen(ns); if (soffs > sl) soffs = sl; @@ -5172,7 +5217,7 @@ sep_comp_string(char *ss, char *s, int noffs, int rec) compisuffix = ztrdup(""); zsfree(compqiprefix); zsfree(compqisuffix); - if (instring) { + if (ois) { compqiprefix = qp; compqisuffix = qs; } else { @@ -5188,6 +5233,7 @@ sep_comp_string(char *ss, char *s, int noffs, int rec) p = compwords[i] = (char *) getdata(n); untokenize(p); } + compcurrent = cur + 1; compwords[i] = NULL; } autoq = oaq; @@ -5242,6 +5288,7 @@ makecomplistcall(Compctl cc) inbackt = oib; autoq = oaq; compnmatches = mnum; + compnnmatches = nmnum; } LASTALLOC; } SWITCHBACKHEAPS; @@ -5317,6 +5364,7 @@ makecomplistctl(int flags) autoq = oaq; offs = ooffs; compnmatches = mnum; + compnnmatches = nmnum; zsfree(cmdstr); freearray(clwords); cmdstr = os; @@ -5979,7 +6027,10 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) char save = line[cs]; line[cs] = 0; - lppre = dupstring((char *) (line + wb)); + lppre = dupstring((char *) line + wb + + (qipre && *qipre ? + (strlen(qipre) - + (*qipre == '\'' || *qipre == '\"')) : 0)); line[cs] = save; if (brbeg && *brbeg) strcpy(lppre + qbrpl, lppre + qbrpl + strlen(brbeg)); @@ -5998,11 +6049,17 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) lppl = 0; } if (cs != we) { - char save = line[we]; + int end = we; + char save = line[end]; + + if (qisuf && *qisuf) { + int ql = strlen(qisuf); - line[we] = 0; + end -= ql - (qisuf[ql-1] == '\'' || qisuf[ql-1] == '"'); + } + line[end] = 0; lpsuf = dupstring((char *) (line + cs)); - line[we] = save; + line[end] = save; if (brend && *brend) { char *p = lpsuf + qbrsl - (cs - wb); @@ -6640,7 +6697,8 @@ invalidatelist(void) listmatches(); if (validlist) freematches(); - lastambig = menucmp = validlist = showinglist = fromcomp = 0; + lastambig = menucmp = menuacc = validlist = showinglist = + fromcomp = listshown = 0; minfo.cur = NULL; minfo.asked = 0; compwidget = NULL; @@ -6917,6 +6975,8 @@ dupmatch(Cmatch m) r->rems = ztrdup(m->rems); r->remf = ztrdup(m->remf); r->autoq = m->autoq; + r->qipl = m->qipl; + r->qisl = m->qisl; return r; } @@ -7346,7 +7406,9 @@ instmatch(Cmatch m, int *scs) /* Ignored prefix. */ if (m->ipre) { - inststrlen(m->ipre, 1, (l = strlen(m->ipre))); + char *p = m->ipre + (menuacc ? m->qipl : 0); + + inststrlen(p, 1, (l = strlen(p))); r += l; } /* -P prefix. */ @@ -7413,7 +7475,8 @@ static int do_ambiguous(void) { int ret = 0; - menucmp = 0; + + menucmp = menuacc = 0; /* If we have to insert the first match, call do_single(). This is * * how REC_EXACT takes effect. We effectively turn the ambiguous * @@ -7501,11 +7564,13 @@ do_ambiguous(void) * if it is needed. */ if (isset(LISTBEEP)) ret = 1; - if (uselist && (usemenu != 2 || (!showinglist && !oldlist)) && + + if (uselist && (usemenu != 2 || (!listshown && !oldlist)) && ((!showinglist && (!listshown || !oldlist)) || (usemenu == 3 && !oldlist)) && (smatches >= 2 || (compforcelist && *compforcelist))) showinglist = -2; + return ret; } @@ -7649,7 +7714,7 @@ do_single(Cmatch m) } } if (!minfo.insc) - cs = minfo.pos + minfo.len; + cs = minfo.pos + minfo.len - m->qisl; } /* If completing in a brace expansion... */ if (brbeg) { @@ -7688,8 +7753,11 @@ do_single(Cmatch m) if (minfo.we && m->ripre && isset(AUTOPARAMKEYS)) makeparamsuffix(((m->flags & CMF_PARBR) ? 1 : 0), minfo.insc - parq); - if ((menucmp && !minfo.we) || !movetoend) + if ((menucmp && !minfo.we) || !movetoend) { cs = minfo.end; + if (cs + m->qisl == lastend) + cs += minfo.insc; + } { Cmatch *om = minfo.cur; struct chdata dat; @@ -7732,6 +7800,7 @@ do_ambig_menu(void) if (usemenu != 3) { menucmp = 1; + menuacc = 0; minfo.cur = NULL; } else { if (oldlist) { @@ -7931,13 +8000,6 @@ ilistmatches(Hookdef dummy, Chdata dat) int nlines = 0, ncols, nlist = 0, longest = 1, pnl = 0; int of = isset(LISTTYPES), opl = 0; - /* Set the cursor below the prompt. */ - trashzle(); - showinglist = listshown = 0; - - clearflag = (isset(USEZLE) && !termflags && - complastprompt && *complastprompt); - for (g = amatches; g; g = g->next) { char **pp = g->ylist; int nl = 0, l; @@ -8013,6 +8075,16 @@ ilistmatches(Hookdef dummy, Chdata dat) nlines += 1 + ((1 + niceztrlen(m->str)) / columns); } } + if (!nlines) { + showinglist = listshown = 0; + return 1; + } + /* Set the cursor below the prompt. */ + trashzle(); + showinglist = listshown = 0; + + clearflag = (isset(USEZLE) && !termflags && + complastprompt && *complastprompt); /* Maybe we have to ask if the user wants to see the list. */ if ((!minfo.cur || !minfo.asked) && @@ -8152,25 +8224,25 @@ ilistmatches(Hookdef dummy, Chdata dat) pnl = 1; g = g->next; } - if (clearflag) { /* Move the cursor up to the prompt, if always_last_prompt * * is set and all that... */ if ((nlines += nlnct - 1) < lines) { tcmultout(TCUP, TCMULTUP, nlines); showinglist = -1; - listshown = 1; } else clearflag = 0, putc('\n', shout); } else putc('\n', shout); + listshown = (clearflag ? 1 : -1); + return 0; } /* This is used to print expansions. */ /**/ -void +int listlist(LinkList l) { struct cmgroup dg; @@ -8193,6 +8265,8 @@ listlist(LinkList l) validlist = vl; smatches = sm; complastprompt = oclp; + + return !dg.lcount; } /* Expand the history references. */ diff --git a/Src/builtin.c b/Src/builtin.c index 0e9baf9be..5c6b24601 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -658,6 +658,9 @@ set_pwd_env(void) } } +/* set if we are resolving links to their true paths */ +static int chasinglinks; + /* The main pwd changing function. The real work is done by other * * functions. cd_get_dest() does the initial argument processing; * * cd_do_chdir() actually changes directory, if possible; cd_new_pwd() * @@ -670,7 +673,6 @@ bin_cd(char *nam, char **argv, char *ops, int func) { LinkNode dir; struct stat st1, st2; - int chaselinks; if (isset(RESTRICTED)) { zwarnnam(nam, "restricted", NULL, 0); @@ -694,7 +696,7 @@ bin_cd(char *nam, char **argv, char *ops, int func) for (s = *argv; *++s; ops[STOUC(*s)] = 1); } brk: - chaselinks = ops['P'] || (isset(CHASELINKS) && !ops['L']); + chasinglinks = ops['P'] || (isset(CHASELINKS) && !ops['L']); PERMALLOC { pushnode(dirstack, ztrdup(pwd)); if (!(dir = cd_get_dest(nam, argv, ops, func))) { @@ -702,7 +704,7 @@ bin_cd(char *nam, char **argv, char *ops, int func) LASTALLOC_RETURN 1; } } LASTALLOC; - cd_new_pwd(func, dir, chaselinks); + cd_new_pwd(func, dir); if (stat(unmeta(pwd), &st1) < 0) { zsfree(pwd); @@ -710,7 +712,7 @@ bin_cd(char *nam, char **argv, char *ops, int func) } else if (stat(".", &st2) < 0) chdir(unmeta(pwd)); else if (st1.st_ino != st2.st_ino || st1.st_dev != st2.st_dev) { - if (chaselinks) { + if (chasinglinks) { zsfree(pwd); pwd = metafy(zgetcwd(), -1, META_DUP); } else { @@ -915,40 +917,49 @@ static char * cd_try_chdir(char *pfix, char *dest, int hard) { char *buf; + int dlen, dochaselinks = 0; /* handle directory prefix */ if (pfix && *pfix) { if (*pfix == '/') buf = tricat(pfix, "/", dest); else { - int pwl = strlen(pwd); int pfl = strlen(pfix); + dlen = strlen(pwd); - buf = zalloc(pwl + pfl + strlen(dest) + 3); + buf = zalloc(dlen + pfl + strlen(dest) + 3); strcpy(buf, pwd); - buf[pwl] = '/'; - strcpy(buf + pwl + 1, pfix); - buf[pwl + 1 + pfl] = '/'; - strcpy(buf + pwl + pfl + 2, dest); + buf[dlen] = '/'; + strcpy(buf + dlen + 1, pfix); + buf[dlen + 1 + pfl] = '/'; + strcpy(buf + dlen + pfl + 2, dest); } } else if (*dest == '/') buf = ztrdup(dest); else { - int pwl = strlen(pwd); + dlen = strlen(pwd); - buf = zalloc(pwl + strlen(dest) + 2); + buf = zalloc(dlen + strlen(dest) + 2); strcpy(buf, pwd); - buf[pwl] = '/'; - strcpy(buf + pwl + 1, dest); + buf[dlen] = '/'; + strcpy(buf + dlen + 1, dest); } - /* Normalise path. See the definition of fixdir() for what this means. */ - fixdir(buf); + /* Normalise path. See the definition of fixdir() for what this means. + * We do not do this if we are chasing links. + */ + if (!chasinglinks) + dochaselinks = fixdir(buf); + else + unmetafy(buf, &dlen); if (lchdir(buf, NULL, hard)) { - zsfree(buf); + free(buf); return NULL; } + /* the chdir succeeded, so decide if we should force links to be chased */ + if (dochaselinks) + chasinglinks = 1; return metafy(buf, -1, META_NOALLOC); } @@ -956,7 +967,7 @@ cd_try_chdir(char *pfix, char *dest, int hard) /**/ static void -cd_new_pwd(int func, LinkNode dir, int chaselinks) +cd_new_pwd(int func, LinkNode dir) { List l; char *new_pwd, *s; @@ -972,7 +983,7 @@ cd_new_pwd(int func, LinkNode dir, int chaselinks) } else if (func == BIN_CD && unset(AUTOPUSHD)) zsfree(getlinknode(dirstack)); - if (chaselinks) { + if (chasinglinks) { s = new_pwd; new_pwd = findpwd(s); zsfree(s); @@ -1039,17 +1050,20 @@ printdirstack(void) } /* Normalise a path. Segments consisting of ., and foo/.. * - * combinations, are removed and the path is unmetafied. */ + * combinations, are removed and the path is unmetafied. + * Returns 1 if we found a ../ path which should force links to + * be chased, 0 otherwise. + */ /**/ -static void +int fixdir(char *src) { - char *dest = src; - char *d0 = dest; -#ifdef __CYGWIN__ + char *dest = src, *d0 = dest; +#ifdef __CYGWIN char *s0 = src; #endif + int ret = 0; /*** if have RFS superroot directory ***/ #ifdef HAVE_SUPERROOT @@ -1081,19 +1095,40 @@ fixdir(char *src) while (dest > d0 + 1 && dest[-1] == '/') dest--; *dest = '\0'; - return; + return ret; } if (src[0] == '.' && src[1] == '.' && - (src[2] == '\0' || src[2] == '/')) { - if (dest > d0 + 1) { - /* remove a foo/.. combination */ - for (dest--; dest > d0 + 1 && dest[-1] != '/'; dest--); - if (dest[-1] != '/') - dest--; - } - src++; - while (*++src == '/'); - } else if (src[0] == '.' && (src[1] == '/' || src[1] == '\0')) { + (src[2] == '\0' || src[2] == '/')) { + if (isset(CHASEDOTS)) { + ret = 1; + /* and treat as normal path segment */ + } else { + if (dest > d0 + 1) { + /* + * remove a foo/.. combination: + * first check foo exists, else return. + */ + struct stat st; + *dest = '\0'; + if (stat(d0, &st) < 0 || !S_ISDIR(st.st_mode)) { + char *ptrd, *ptrs; + if (dest == src) + *dest = '.'; + for (ptrs = src, ptrd = dest; *ptrs; ptrs++, ptrd++) + *ptrd = (*ptrs == Meta) ? (*++ptrs ^ 32) : *ptrs; + *ptrd = '\0'; + return 1; + } + for (dest--; dest > d0 + 1 && dest[-1] != '/'; dest--); + if (dest[-1] != '/') + dest--; + } + src++; + while (*++src == '/'); + continue; + } + } + if (src[0] == '.' && (src[1] == '/' || src[1] == '\0')) { /* skip a . section */ while (*++src == '/'); } else { @@ -3249,12 +3284,11 @@ bin_read(char *name, char **args, char *ops, int func) nchars = 1; args++; } - - firstarg = *args; - if (*args && **args == '?') - args++; - /* default result parameter */ + /* This `*args++ : *args' looks a bit weird, but it works around a bug + * in gcc-2.8.1 under DU 4.0. */ + firstarg = (*args && **args == '?' ? *args++ : *args); reply = *args ? *args++ : ops['A'] ? "reply" : "REPLY"; + if (ops['A'] && *args) { zwarnnam(name, "only one array argument allowed", NULL, 0); return 1; diff --git a/Src/exec.c b/Src/exec.c index 9c7a1ceb5..dc281675f 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -3144,9 +3144,24 @@ static int cancd2(char *s) { struct stat buf; - char *us = unmeta(s); + char *us, *us2 = NULL; + /* + * If CHASEDOTS and CHASELINKS are not set, we want to rationalize the + * path by removing foo/.. combinations in the logical rather than + * the physical path. If either is set, we test the physical path. + */ + if (!isset(CHASEDOTS) && !isset(CHASELINKS)) { + if (*s != '/') + us = tricat(pwd[1] ? pwd : "", "/", s); + else + us = ztrdup(s); + fixdir(us2 = us); + } else + us = unmeta(s); return !(access(us, X_OK) || stat(us, &buf) || !S_ISDIR(buf.st_mode)); + if (us2) + free(us2); } /**/ diff --git a/Src/glob.c b/Src/glob.c index ea4980b8b..cf22ef923 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -2724,6 +2724,9 @@ charmatch(Comp c, char *x, char *y) * Here we bypass tulower() and tuupper() for speed. */ int xi = (STOUC(UNMETA(x)) & 0xff), yi = (STOUC(UNMETA(y)) & 0xff); + /* A NULL is a real null, since a \000 would be metafied. */ + if (!*x || !*y) + return 0; return xi == yi || (((c->stat & C_IGNCASE) ? ((isupper(xi) ? tolower(xi) : xi) == @@ -2926,7 +2929,10 @@ rangematch(char **patptr, int ch, int rchar) * and optional ^ have already been skipped. */ char *pat = *patptr; -#ifdef HAVE_STRCOLL + /* We don't use strcoll() for ranges, since it can have side + * effects. It's less necessary now we have [:posix:] ranges. + */ +#if 0 char l_buf[2], r_buf[2], ch_buf[2]; ch_buf[0] = ch; @@ -2944,7 +2950,7 @@ rangematch(char **patptr, int ch, int rchar) break; } else if (*pat == '-' && pat[-1] != rchar && pat[1] != Outbrack) { -#ifdef HAVE_STRCOLL +#if 0 l_buf[0] = PPAT(-1); r_buf[0] = PAT(1); if (strcoll(l_buf, ch_buf) <= 0 && diff --git a/Src/lex.c b/Src/lex.c index 33b6598b9..069f9b39b 100644 --- a/Src/lex.c +++ b/Src/lex.c @@ -241,6 +241,7 @@ lexsave(void) cmdsp = 0; inredir = 0; hdocs = NULL; + histactive = 0; ls->next = lstack; lstack = ls; diff --git a/Src/options.c b/Src/options.c index 2eb73690e..0207cd232 100644 --- a/Src/options.c +++ b/Src/options.c @@ -91,6 +91,7 @@ static struct optname optns[] = { {NULL, "braceccl", 0, BRACECCL}, {NULL, "bsdecho", OPT_EMULATE|OPT_SH, BSDECHO}, {NULL, "cdablevars", 0, CDABLEVARS}, +{NULL, "chasedots", 0, CHASEDOTS}, {NULL, "chaselinks", 0, CHASELINKS}, {NULL, "clobber", OPT_ALL, CLOBBER}, {NULL, "completealiases", 0, COMPLETEALIASES}, diff --git a/Src/parse.c b/Src/parse.c index 626ffc982..658a66660 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -72,7 +72,13 @@ struct list dummy_list; #define YYERROR { tok = LEXERR; return NULL; } #define YYERRORV { tok = LEXERR; return; } -#define COND_ERROR(X,Y) do{herrflush();zerr(X,Y,0);YYERROR}while(0) +#define COND_ERROR(X,Y) do { \ + zwarn(X,Y,0); \ + herrflush(); \ + if (noerrs != 2) \ + errflag = 1; \ + YYERROR \ +} while(0) #define make_list() allocnode(N_LIST) #define make_sublist() allocnode(N_SUBLIST) @@ -140,11 +146,13 @@ par_event(void) } if (!l) { if (errflag) { - yyerror(); + yyerror(0); return NULL; } + yyerror(1); herrflush(); - yyerror(); + if (noerrs != 2) + errflag = 1; return NULL; } else { l->right = par_event(); @@ -163,7 +171,7 @@ parse_list(void) yylex(); ret = par_list(); if (tok == LEXERR) { - yyerror(); + yyerror(0); return NULL; } return ret; @@ -1480,7 +1488,7 @@ par_cond_multi(char *a, LinkList l) /**/ static void -yyerror(void) +yyerror(int noerr) { int t0; @@ -1488,9 +1496,11 @@ yyerror(void) if (!yytext || !yytext[t0] || yytext[t0] == '\n') break; if (t0 == 20) - zerr("parse error near `%l...'", yytext, 20); + zwarn("parse error near `%l...'", yytext, 20); else if (t0) - zerr("parse error near `%l'", yytext, t0); + zwarn("parse error near `%l'", yytext, t0); else - zerr("parse error", NULL, 0); + zwarn("parse error", NULL, 0); + if (!noerr && noerrs != 2) + errflag = 1; } diff --git a/Src/utils.c b/Src/utils.c index d82f62694..f86c18b16 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -30,23 +30,12 @@ #include "zsh.mdh" #include "utils.pro" -/* Print an error */ - -/**/ -void -zwarnnam(const char *cmd, const char *fmt, const char *str, int num) -{ - int waserr; - - waserr = errflag; - zerrnam(cmd, fmt, str, num); - errflag = waserr; -} - /* name of script being sourced */ /**/ char *scriptname; + +/* Print an error */ /**/ void @@ -57,7 +46,27 @@ zerr(const char *fmt, const char *str, int num) errflag = 1; return; } + zwarn(fmt, str, num); errflag = 1; +} + +/**/ +void +zerrnam(const char *cmd, const char *fmt, const char *str, int num) +{ + if (errflag || noerrs) + return; + + zwarnnam(cmd, fmt, str, num); + errflag = 1; +} + +/**/ +void +zwarn(const char *fmt, const char *str, int num) +{ + if (errflag || noerrs) + return; trashzle(); /* * scriptname is set when sourcing scripts, so that we get the @@ -68,25 +77,29 @@ zerr(const char *fmt, const char *str, int num) nicezputs((isset(SHINSTDIN) && !locallevel) ? "zsh" : scriptname ? scriptname : argzero, stderr); fputs(": ", stderr); - zerrnam(NULL, fmt, str, num); + zerrmsg(fmt, str, num); } /**/ void -zerrnam(const char *cmd, const char *fmt, const char *str, int num) +zwarnnam(const char *cmd, const char *fmt, const char *str, int num) { - if (cmd) { - if (errflag || noerrs) - return; - errflag = 1; - trashzle(); - if (unset(SHINSTDIN) || locallevel) { - nicezputs(scriptname ? scriptname : argzero, stderr); - fputs(": ", stderr); - } - nicezputs(cmd, stderr); + if (errflag || noerrs) + return; + trashzle(); + if (unset(SHINSTDIN) || locallevel) { + nicezputs(scriptname ? scriptname : argzero, stderr); fputs(": ", stderr); } + nicezputs(cmd, stderr); + fputs(": ", stderr); + zerrmsg(fmt, str, num); +} + +/**/ +void +zerrmsg(const char *fmt, const char *str, int num) +{ while (*fmt) if (*fmt == '%') { fmt++; @@ -302,7 +315,7 @@ slashsplit(char *s) /**/ static int -xsymlinks(char *s, int flag) +xsymlinks(char *s) { char **pp, **opp; char xbuf2[PATH_MAX*2], xbuf3[PATH_MAX*2]; @@ -325,15 +338,9 @@ xsymlinks(char *s, int flag) *p = '\0'; continue; } - if (unset(CHASELINKS)) { - strcat(xbuf, "/"); - strcat(xbuf, *pp); - zsfree(*pp); - continue; - } sprintf(xbuf2, "%s/%s", xbuf, *pp); t0 = readlink(unmeta(xbuf2), xbuf3, PATH_MAX); - if (t0 == -1 || !flag) { + if (t0 == -1) { strcat(xbuf, "/"); strcat(xbuf, *pp); zsfree(*pp); @@ -342,9 +349,9 @@ xsymlinks(char *s, int flag) metafy(xbuf3, t0, META_NOALLOC); if (*xbuf3 == '/') { strcpy(xbuf, ""); - xsymlinks(xbuf3 + 1, flag); + xsymlinks(xbuf3 + 1); } else - xsymlinks(xbuf3, flag); + xsymlinks(xbuf3); zsfree(*pp); } } @@ -352,19 +359,19 @@ xsymlinks(char *s, int flag) return ret; } -/* expand symlinks in s, and remove other weird things */ +/* + * expand symlinks in s, and remove other weird things: + * note that this always expands symlinks. + */ /**/ char * xsymlink(char *s) { - if (unset(CHASELINKS)) - return ztrdup(s); if (*s != '/') return NULL; *xbuf = '\0'; - if (!xsymlinks(s + 1, 1)) - return ztrdup(s); + xsymlinks(s + 1); if (!*xbuf) return ztrdup("/"); return ztrdup(xbuf); @@ -374,15 +381,10 @@ xsymlink(char *s) void print_if_link(char *s) { - int chase; - if (*s == '/') { - chase = opts[CHASELINKS]; - opts[CHASELINKS] = 1; *xbuf = '\0'; - if (xsymlinks(s + 1, 1)) + if (xsymlinks(s + 1)) printf(" -> "), zputs(*xbuf ? xbuf : "/", stdout); - opts[CHASELINKS] = chase; } } @@ -573,7 +575,8 @@ getnameddir(char *name) /* Retrieve an entry from the password table/database for this user. */ struct passwd *pw; if ((pw = getpwnam(name))) { - char *dir = xsymlink(pw->pw_dir); + char *dir = isset(CHASELINKS) ? xsymlink(pw->pw_dir) + : ztrdup(pw->pw_dir); adduserdir(name, dir, ND_USERNAME, 1); str = dupstring(dir); zsfree(dir); @@ -3202,7 +3205,7 @@ getkeystring(char *s, int *len, int fromwhere, int *misc) int meta = 0, control = 0; if (fromwhere == 6) - t = tmp; + t = buf = tmp; else if (fromwhere != 4) t = buf = zhalloc(strlen(s) + 1); else { diff --git a/Src/zsh.h b/Src/zsh.h index 2070e9b3f..d2b64b9bb 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1171,6 +1171,7 @@ enum { BRACECCL, BSDECHO, CDABLEVARS, + CHASEDOTS, CHASELINKS, CLOBBER, COMPLETEALIASES, -- cgit 1.4.1