diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/Zle/compctl.c | 4 | ||||
-rw-r--r-- | Src/Zle/complist.c | 106 | ||||
-rw-r--r-- | Src/Zle/zle.export | 10 | ||||
-rw-r--r-- | Src/Zle/zle_bindings.c | 8 | ||||
-rw-r--r-- | Src/Zle/zle_main.c | 8 | ||||
-rw-r--r-- | Src/Zle/zle_misc.c | 2 | ||||
-rw-r--r-- | Src/Zle/zle_params.c | 8 | ||||
-rw-r--r-- | Src/Zle/zle_refresh.c | 4 | ||||
-rw-r--r-- | Src/Zle/zle_thingy.c | 44 | ||||
-rw-r--r-- | Src/Zle/zle_tricky.c | 57 | ||||
-rw-r--r-- | Src/builtin.c | 170 | ||||
-rw-r--r-- | Src/exec.c | 41 | ||||
-rw-r--r-- | Src/hist.c | 2 | ||||
-rw-r--r-- | Src/jobs.c | 160 | ||||
-rw-r--r-- | Src/loop.c | 33 | ||||
-rw-r--r-- | Src/math.c | 6 | ||||
-rw-r--r-- | Src/params.c | 52 | ||||
-rw-r--r-- | Src/prompt.c | 81 | ||||
-rw-r--r-- | Src/utils.c | 26 | ||||
-rw-r--r-- | Src/zsh.h | 49 |
20 files changed, 636 insertions, 235 deletions
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 2b426492e..694af8429 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -2096,9 +2096,7 @@ bin_compset(char *name, char **argv, char *ops, int func) case 'P': test = CVT_PREPAT; break; case 's': test = CVT_SUFNUM; break; case 'S': test = CVT_SUFPAT; break; - case 'q': return !(compquote && *compquote && - (*compquote == '\'' || *compquote == '"') && - !set_comp_sepptr()); + case 'q': return set_comp_sepptr(); default: zerrnam(name, "bad option -%c", NULL, argv[0][1]); return 1; diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c index aac8b410d..0e7152866 100644 --- a/Src/Zle/complist.c +++ b/Src/Zle/complist.c @@ -309,7 +309,7 @@ complistmatches(Hookdef dummy, Chdata dat) 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; + int mc, ml = 0, cc, hasm = 0, cl; struct listcols col; if (minfo.asked == 2) { @@ -448,7 +448,12 @@ complistmatches(Hookdef dummy, Chdata dat) mgtab = (Cmgroup *) zalloc(i * sizeof(Cmgroup)); memset(mgtab, 0, i * sizeof(Cmgroup)); mcols = ncols; - mlines = nlines; + mlines = cl = nlines; + if (cl < 2) { + cl = -1; + if (tccan(TCCLEAREOD)) + tcout(TCCLEAREOD); + } } /* Now print the matches. */ g = amatches; @@ -456,14 +461,27 @@ complistmatches(Hookdef dummy, Chdata dat) char **pp = g->ylist; if ((e = g->expls)) { + int l; + while (*e) { if ((*e)->count) { if (pnl) { putc('\n', shout); pnl = 0; ml++; + if (cl >= 0 && --cl <= 1) { + cl = -1; + if (tccan(TCCLEAREOD)) + tcout(TCCLEAREOD); + } + } + l = printfmt((*e)->str, (*e)->count, 1); + ml += l; + if (cl >= 0 && (cl -= l) <= 1) { + cl = -1; + if (tccan(TCCLEAREOD)) + tcout(TCCLEAREOD); } - ml += printfmt((*e)->str, (*e)->count, 1); pnl = 1; } e++; @@ -474,6 +492,11 @@ complistmatches(Hookdef dummy, Chdata dat) putc('\n', shout); pnl = 0; ml++; + if (cl >= 0 && --cl <= 1) { + cl = -1; + if (tccan(TCCLEAREOD)) + tcout(TCCLEAREOD); + } } if (g->flags & CGF_LINES) { while (*pp) { @@ -504,6 +527,11 @@ complistmatches(Hookdef dummy, Chdata dat) if (n) { putc('\n', shout); ml++; + if (cl >= 0 && --cl <= 1) { + cl = -1; + if (tccan(TCCLEAREOD)) + tcout(TCCLEAREOD); + } } pp++; } @@ -517,6 +545,11 @@ complistmatches(Hookdef dummy, Chdata dat) putc('\n', shout); pnl = 0; ml++; + if (cl >= 0 && --cl <= 1) { + cl = -1; + if (tccan(TCCLEAREOD)) + tcout(TCCLEAREOD); + } } for (p = skipnolist(g->matches); n && nl--;) { i = ncols; @@ -607,6 +640,11 @@ complistmatches(Hookdef dummy, Chdata dat) if (n) { putc('\n', shout); ml++; + if (cl >= 0 && --cl <= 1) { + cl = -1; + if (tccan(TCCLEAREOD)) + tcout(TCCLEAREOD); + } if (n && nl) p = skipnolist(p + 1); } @@ -640,11 +678,13 @@ struct menustack { char *line; int cs; struct menuinfo info; + Cmgroup amatches, pmatches, lmatches; }; static int domenuselect(Hookdef dummy, Chdata dat) { + static Chdata fdat = NULL; Cmatch **p; Cmgroup *pg; Thingy cmd; @@ -652,10 +692,15 @@ domenuselect(Hookdef dummy, Chdata dat) int i = 0, acc = 0; char *s; - if (dummy && (!(s = getsparam("SELECTMIN")) || - (dat && dat->num < atoi(s)))) + if (fdat || (dummy && (!(s = getsparam("SELECTMIN")) || + (dat && dat->num < atoi(s))))) { + if (fdat) { + fdat->matches = dat->matches; + fdat->num = dat->num; + } return 0; - + } + fdat = dat; selectlocalmap(mskeymap); noselect = 0; mselect = (*(minfo.cur))->gnum; @@ -686,6 +731,32 @@ domenuselect(Hookdef dummy, Chdata dat) else if (cmd == Th(z_acceptline)) { acc = 1; break; + } else if (cmd == Th(z_acceptandinfernexthistory)) { + Menustack s = (Menustack) zhalloc(sizeof(*s)); + + s->prev = u; + u = s; + s->line = dupstring((char *) line); + s->cs = cs; + memcpy(&(s->info), &minfo, sizeof(struct menuinfo)); + s->amatches = amatches; + s->pmatches = pmatches; + s->lmatches = lmatches; + menucmp = 0; + fixsuffix(); + validlist = 0; + pmatches = NULL; + invalidatelist(); + menucomplete(zlenoargs); + if (dat->num < 2 || !minfo.cur || !*(minfo.cur)) { + noselect = 1; + clearlist = 1; + zrefresh(); + break; + } + clearlist = 1; + mselect = (*(minfo.cur))->gnum; + continue; } else if (cmd == Th(z_acceptandhold) || cmd == Th(z_acceptandmenucomplete)) { Menustack s = (Menustack) zhalloc(sizeof(*s)); @@ -695,6 +766,7 @@ domenuselect(Hookdef dummy, Chdata dat) s->line = dupstring((char *) line); s->cs = cs; memcpy(&(s->info), &minfo, sizeof(struct menuinfo)); + s->amatches = s->pmatches = s->lmatches = NULL; acceptlast(); do_menucmp(0); mselect = (*(minfo.cur))->gnum; @@ -712,7 +784,15 @@ domenuselect(Hookdef dummy, Chdata dat) cs = u->cs; memcpy(&minfo, &(u->info), sizeof(struct menuinfo)); p = &(minfo.cur); + if (u->pmatches && pmatches != u->pmatches) { + freematches(); + amatches = u->amatches; + pmatches = u->pmatches; + lmatches = u->lmatches; + hasperm = 1; + } u = u->prev; + clearlist = 1; } else if (cmd == Th(z_redisplay)) { redisplay(zlenoargs); continue; @@ -846,6 +926,19 @@ domenuselect(Hookdef dummy, Chdata dat) do_single(**p); mselect = (**p)->gnum; } + if (u) { + int hp = hasperm; + Cmgroup m = pmatches; + + for (; u; u = u->prev) { + if (u->pmatches != m) { + pmatches = u->pmatches; + freematches(); + } + } + pmatches = m; + hasperm = hp; + } selectlocalmap(NULL); mselect = -1; inselect = 0; @@ -858,6 +951,7 @@ domenuselect(Hookdef dummy, Chdata dat) showinglist = -2; zrefresh(); } + fdat = NULL; return (!noselect ^ acc); } diff --git a/Src/Zle/zle.export b/Src/Zle/zle.export index e6f469ad0..8bc049e16 100644 --- a/Src/Zle/zle.export +++ b/Src/Zle/zle.export @@ -1,23 +1,29 @@ #! acceptlast addzlefunction +amatches backdel backkill bindkey clearflag +clearlist clearscreen deletezlefunction do_menucmp do_single -feep +fixsuffix foredel forekill +freematches getkey getkeycmd getzlequery +hasperm +invalidatelist lastambig linkkeymap listshown +lmatches menucmp menucomplete menucur @@ -25,6 +31,7 @@ menugrp minfo newkeymap nlnct +pmatches printfmt redisplay refthingy @@ -39,6 +46,7 @@ thingies trashzle ungetkeycmd unlinkkeymap +validlist zlenoargs zmod zrefresh diff --git a/Src/Zle/zle_bindings.c b/Src/Zle/zle_bindings.c index 40e555ad1..940d578d9 100644 --- a/Src/Zle/zle_bindings.c +++ b/Src/Zle/zle_bindings.c @@ -200,9 +200,9 @@ int metabind[128] = { /* M-K */ z_undefinedkey, /* M-L */ z_downcaseword, /* M-M */ z_undefinedkey, - /* M-N */ z_historybeginningsearchforward, + /* M-N */ z_historysearchforward, /* M-O */ z_undefinedkey, - /* M-P */ z_historybeginningsearchbackward, + /* M-P */ z_historysearchbackward, /* M-Q */ z_pushline, /* M-R */ z_undefinedkey, /* M-S */ z_spellword, @@ -232,9 +232,9 @@ int metabind[128] = { /* M-k */ z_undefinedkey, /* M-l */ z_downcaseword, /* M-m */ z_undefinedkey, - /* M-n */ z_historybeginningsearchforward, + /* M-n */ z_historysearchforward, /* M-o */ z_undefinedkey, - /* M-p */ z_historybeginningsearchbackward, + /* M-p */ z_historysearchbackward, /* M-q */ z_pushline, /* M-r */ z_undefinedkey, /* M-s */ z_spellword, diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 8f6dfdf75..beef708fb 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -307,7 +307,7 @@ getkey(int keytmout) unsigned int ret; long exp100ths; int die = 0, r, icnt = 0; - int old_errno = errno; + int old_errno = errno, obreaks = breaks; #ifdef HAVE_SELECT fd_set foofd; @@ -397,6 +397,7 @@ getkey(int keytmout) if (!errflag && !retflag && !breaks) continue; errflag = 0; + breaks = obreaks; errno = old_errno; return EOF; } else if (errno == EWOULDBLOCK) { @@ -717,7 +718,7 @@ bin_vared(char *name, char **args, char *ops, int func) Value v; Param pm = 0; int create = 0; - int type = PM_SCALAR; + int type = PM_SCALAR, obreaks = breaks; char *p1 = NULL, *p2 = NULL; if (zleactive) { @@ -809,6 +810,7 @@ bin_vared(char *name, char **args, char *ops, int func) if (!t || errflag) { /* error in editing */ errflag = 0; + breaks = obreaks; return 1; } /* strip off trailing newline, if any */ @@ -948,7 +950,7 @@ trashzle(void) static struct builtin bintab[] = { BUILTIN("bindkey", 0, bin_bindkey, 0, -1, 0, "evaMldDANmrsLR", NULL), BUILTIN("vared", 0, bin_vared, 1, 7, 0, NULL, NULL), - BUILTIN("zle", 0, bin_zle, 0, -1, 0, "lDANCLmMgGcRa", NULL), + BUILTIN("zle", 0, bin_zle, 0, -1, 0, "lDANCLmMgGcRaU", NULL), }; /* The order of the entries in this table has to match the *HOOK diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index a51cdf92e..fedb9d5cf 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -736,6 +736,7 @@ executenamedcommand(char *prmt) statusll = l + len + 1; zmult = 1; listlist(cmdll); + showinglist = 0; zmult = zmultsav; } else if (!nextnode(firstnode(cmdll))) { strcpy(ptr = cmdbuf, peekfirst(cmdll)); @@ -754,6 +755,7 @@ executenamedcommand(char *prmt) statusll = l + cmdambig + 1; zmult = 1; listlist(cmdll); + showinglist = 0; zmult = zmultsav; } len = cmdambig; diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c index bac399e7d..dc4e27685 100644 --- a/Src/Zle/zle_params.c +++ b/Src/Zle/zle_params.c @@ -137,6 +137,8 @@ set_buffer(Param pm, char *x) cs = ll; } else cs = ll = 0; + fixsuffix(); + menucmp = 0; } /**/ @@ -156,6 +158,8 @@ set_cursor(Param pm, zlong x) cs = ll; else cs = x; + fixsuffix(); + menucmp = 0; } /**/ @@ -182,6 +186,8 @@ set_lbuffer(Param pm, char *x) ll = ll - cs + len; cs = len; zsfree(x); + fixsuffix(); + menucmp = 0; } /**/ @@ -205,6 +211,8 @@ set_rbuffer(Param pm, char *x) sizeline(ll = cs + len); memcpy(line + cs, y, len); zsfree(x); + fixsuffix(); + menucmp = 0; } /**/ diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index dd4310078..48e1071b8 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -281,7 +281,9 @@ zrefresh(void) clearflag = 0; resetneeded = 1; } - listshown = showinglist = 0; + listshown = 0; + if (showinglist != -2) + showinglist = 0; } clearlist = 0; diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c index cf01f2fc1..f753b4769 100644 --- a/Src/Zle/zle_thingy.c +++ b/Src/Zle/zle_thingy.c @@ -340,7 +340,8 @@ bin_zle(char *name, char **args, char *ops, int func) { 'A', bin_zle_link, 2, 2 }, { 'N', bin_zle_new, 1, 2 }, { 'C', bin_zle_complete, 3, 3 }, - { 'R', bin_zle_refresh, 0, 1 }, + { 'R', bin_zle_refresh, 0, -1 }, + { 'U', bin_zle_unget, 1, 1 }, { 0, bin_zle_call, 0, -1 }, }; struct opn const *op, *opp; @@ -396,23 +397,50 @@ static int bin_zle_refresh(char *name, char **args, char *ops, char func) { char *s = statusline; - int sl = statusll; + int sl = statusll, ocl = clearlist; + statusline = NULL; + statusll = 0; if (*args) { - statusline = *args; - statusll = strlen(statusline); - } else { - statusline = NULL; - statusll = 0; - } + if (**args) { + statusline = *args; + statusll = strlen(statusline); + } + if (*++args) { + LinkList l = newlinklist(); + int zmultsav = zmult; + + for (; *args; args++) + addlinknode(l, *args); + + zmult = 1; + listlist(l); + showinglist = clearlist = 0; + zmult = zmultsav; + } else if (ops['c']) + clearlist = 1; + } else if (ops['c']) + clearlist = 1; zrefresh(); + clearlist = ocl; statusline = s; statusll = sl; return 0; } /**/ +static int +bin_zle_unget(char *name, char **args, char *ops, char func) +{ + char *p = *args; + + while (*p) + ungetkey((int) *p++); + return 0; +} + +/**/ static void scanlistwidgets(HashNode hn, int list) { diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index f7b243d31..5461079cb 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -133,7 +133,8 @@ static LinkList matches, fmatches; /* This holds the list of matches-groups. lmatches is a pointer to the * * last element in this list. */ -static Cmgroup pmatches, amatches, lmatches; +/**/ +Cmgroup pmatches, amatches, lmatches; /* Non-zero if we have permanently allocated matches. */ @@ -150,7 +151,8 @@ static int nmatches, smatches; /* !=0 if we have a valid completion list. */ -static int validlist; +/**/ +int validlist; /* This flag is non-zero if we are completing a pattern (with globcomplete) */ @@ -818,7 +820,8 @@ docomplete(int lst) * string inserted by the last completion. */ if (fromcomp & FC_INWORD) - cs = lastend; + if ((cs = lastend) > ll) + cs = ll; /* Check if we have to start a menu-completion (via automenu). */ @@ -1773,6 +1776,7 @@ doexpansion(char *s, int lst, int olst, int explincmd) if (lst == COMP_LIST_EXPAND) { /* Only the list of expansions was requested. */ listlist(vl); + showinglist = 0; goto end; } /* Remove the current word and put the expansions there. */ @@ -2577,7 +2581,8 @@ comp_match(char *pfx, char *sfx, char *w, Comp cp, return NULL; r = (qu ? quotename(r, NULL) : dupstring(r)); - + if (qu == 2 && r[0] == '\\' && r[1] == '~') + chuck(r); /* We still break it into parts here, trying to build a sensible * cline list for these matches, too. */ wl = strlen(w); @@ -2590,6 +2595,8 @@ comp_match(char *pfx, char *sfx, char *w, Comp cp, int mpl, rpl, wl; w = (qu ? quotename(w, NULL) : dupstring(w)); + if (qu == 2 && w[0] == '\\' && w[1] == '~') + chuck(w); wl = strlen(w); @@ -3814,15 +3821,20 @@ addmatches(Cadata dat, char **argv) dat->rems = dupstring(dat->rems); /* Probably quote the prefix and suffix for testing. */ - if (!cp && (dat->aflags & CAF_MATCH) && - !(dat->aflags & CAF_QUOTE)) { - lpre = quotename(lpre, NULL); - lsuf = quotename(lsuf, NULL); + if (!(dat->aflags & CAF_QUOTE)) { + if (!cp && (dat->aflags & CAF_MATCH)) { + lpre = quotename(lpre, NULL); + lsuf = quotename(lsuf, NULL); + } + if (dat->ppre) { + dat->ppre = quotename(dat->ppre, NULL); + if ((dat->flags & CMF_FILE) && + dat->ppre[0] == '\\' && dat->ppre[1] == '~') + chuck(dat->ppre); + } + if (dat->psuf) + dat->psuf = quotename(dat->psuf, NULL); } - if (dat->ppre) - dat->ppre = quotename(dat->ppre, NULL); - if (dat->psuf) - dat->psuf = quotename(dat->psuf, NULL); } /* Walk through the matches given. */ for (; (s = *argv); argv++) { @@ -3855,7 +3867,9 @@ addmatches(Cadata dat, char **argv) lc = bld_parts(ms, sl, -1, NULL); isexact = 0; } else if (!(ms = comp_match(lpre, lsuf, s, cp, &lc, - !(dat->aflags & CAF_QUOTE), + (!(dat->aflags & CAF_QUOTE) ? + ((dat->ppre && dat->ppre) || + !(dat->flags & CMF_FILE) ? 1 : 2) : 0), &bpl, &bsl, &isexact))) { if (dparr && !*++dparr) dparr = NULL; @@ -3962,7 +3976,7 @@ addmatch(char *s, char *t) } ms = ((addwhat == CC_FILES || addwhat == -6 || addwhat == -5 || addwhat == -8) ? - comp_match(qfpre, qfsuf, s, filecomp, &lc, 1, + comp_match(qfpre, qfsuf, s, filecomp, &lc, (ppre && *ppre ? 1 : 2), &bpl, &bsl, &isexact) : comp_match(fpre, fsuf, s, filecomp, &lc, 0, &bpl, &bsl, &isexact)); @@ -4361,6 +4375,7 @@ docompletion(char *s, int lst, int incmd) cs = origcs; clearlist = 1; ret = 1; + minfo.cur = NULL; goto compend; } if (comppatmatch && *comppatmatch && comppatmatch != opm) @@ -5156,10 +5171,16 @@ sep_comp_string(char *ss, char *s, int noffs, int rec) zsfree(compisuffix); compisuffix = ztrdup(""); zsfree(compqiprefix); - compqiprefix = qp; zsfree(compqisuffix); - compqisuffix = qs; - + if (instring) { + compqiprefix = qp; + compqisuffix = qs; + } else { + compqiprefix = ztrdup(quotename(qp, NULL)); + zsfree(qp); + compqisuffix = ztrdup(quotename(qs, NULL)); + zsfree(qs); + } freearray(compwords); i = countlinknodes(foo); compwords = (char **) zalloc((i + 1) * sizeof(char *)); @@ -7028,7 +7049,7 @@ freematch(Cmatch m) /* This frees the groups of matches. */ /**/ -static void +void freematches(void) { Cmgroup g = pmatches, n; diff --git a/Src/builtin.c b/Src/builtin.c index 8fe112cb5..0e9baf9be 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -42,7 +42,7 @@ static struct builtin builtins[] = BUILTIN("[", 0, bin_test, 0, -1, BIN_BRACKET, NULL, NULL), BUILTIN(".", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL), BUILTIN(":", BINF_PSPECIAL, bin_true, 0, -1, 0, NULL, NULL), - BUILTIN("alias", BINF_MAGICEQUALS, bin_alias, 0, -1, 0, "Lgmr", NULL), + BUILTIN("alias", BINF_MAGICEQUALS | BINF_PLUSOPTS, bin_alias, 0, -1, 0, "Lgmr", NULL), BUILTIN("autoload", BINF_TYPEOPTS, bin_functions, 0, -1, 0, "tU", "u"), BUILTIN("bg", 0, bin_fg, 0, -1, BIN_BG, NULL, NULL), BUILTIN("break", BINF_PSPECIAL, bin_break, 0, 1, BIN_BREAK, NULL, NULL), @@ -87,7 +87,7 @@ static struct builtin builtins[] = #endif BUILTIN("popd", 0, bin_cd, 0, 2, BIN_POPD, NULL, NULL), - BUILTIN("print", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, "RDPnrslzNu0123456789pioOcm-", NULL), + BUILTIN("print", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, "RDPbnrslzNu0123456789pioOcm-", NULL), BUILTIN("pushd", 0, bin_cd, 0, 2, BIN_PUSHD, NULL, NULL), BUILTIN("pushln", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, NULL, "-nz"), BUILTIN("pwd", 0, bin_pwd, 0, 0, 0, "rLP", NULL), @@ -645,12 +645,14 @@ set_pwd_env(void) setsparam("OLDPWD", ztrdup(oldpwd)); pm = (Param) paramtab->getnode(paramtab, "PWD"); - if (!(pm->flags & PM_EXPORTED)) { + if (!(pm->flags & PM_EXPORTED) && + (!pm->level || (isset(ALLEXPORT) && !pm->old))) { pm->flags |= PM_EXPORTED; pm->env = addenv("PWD", pwd); } pm = (Param) paramtab->getnode(paramtab, "OLDPWD"); - if (!(pm->flags & PM_EXPORTED)) { + if (!(pm->flags & PM_EXPORTED) && + (!pm->level || (isset(ALLEXPORT) && !pm->old))) { pm->flags |= PM_EXPORTED; pm->env = addenv("OLDPWD", oldpwd); } @@ -1492,7 +1494,7 @@ Param typeset_single(char *cname, char *pname, Param pm, int func, int on, int off, int roff, char *value, Param altpm) { - int usepm, tc, keeplocal = 0; + int usepm, tc, keeplocal = 0, newspecial = 0; /* * Do we use the existing pm? Note that this isn't the end of the @@ -1503,22 +1505,31 @@ typeset_single(char *cname, char *pname, Param pm, int func, */ usepm = pm && !(pm->flags & PM_UNSET); - /* Always use an existing pm if special at current locallevel */ - if (pm && (pm->flags & PM_SPECIAL) && pm->level == locallevel) + /* + * We need to compare types with an existing pm if special, + * even if that's unset + */ + if (pm && (pm->flags & PM_SPECIAL)) usepm = 1; /* - * Don't use a non-special existing param if + * Don't use an existing param if * - the local level has changed, and * - we are really locallizing the parameter */ - if (usepm && !(pm->flags & PM_SPECIAL) && - locallevel != pm->level && (on & PM_LOCAL)) + if (usepm && locallevel != pm->level && (on & PM_LOCAL)) { + /* + * If the original parameter was special and we're creating + * a new one, we need to keep it special. + */ + newspecial = (pm->flags & PM_SPECIAL); usepm = 0; + } /* attempting a type conversion, or making a tied colonarray? */ - if ((tc = usepm && (((off & pm->flags) | (on & ~pm->flags)) & - (PM_INTEGER|PM_HASHED|PM_ARRAY|PM_TIED|PM_AUTOLOAD)))) + if ((tc = (usepm || newspecial) + && (((off & pm->flags) | (on & ~pm->flags)) & + (PM_INTEGER|PM_HASHED|PM_ARRAY|PM_TIED|PM_AUTOLOAD)))) usepm = 0; if (tc && (pm->flags & PM_SPECIAL)) { zerrnam(cname, "%s: can't change type of a special parameter", @@ -1526,13 +1537,27 @@ typeset_single(char *cname, char *pname, Param pm, int func, return NULL; } + /* + * According to the manual, local parameters don't get exported. + * A parameter will be local if + * 1. we are re-using an existing local parameter + * or + * 2. we are not using an existing parameter, but + * i. there is already a parameter, which will be hidden + * or + * ii. we are creating a new local parameter + */ + if ((usepm && pm->level) || + (!usepm && (pm || (locallevel && (on & PM_LOCAL))))) + on &= ~PM_EXPORTED; + if (usepm) { on &= ~PM_LOCAL; if (!on && !roff && !value) { paramtab->printnode((HashNode)pm, 0); return pm; } - if ((pm->flags & PM_RESTRICTED && isset(RESTRICTED))) { + if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) { zerrnam(cname, "%s: restricted", pname, 0); return pm; } @@ -1553,7 +1578,8 @@ typeset_single(char *cname, char *pname, Param pm, int func, if (pm->flags & PM_EXPORTED) { if (!(pm->flags & PM_UNSET) && !pm->env && !value) pm->env = addenv(pname, getsparam(pname)); - } else if (pm->env) { + } else if (pm->env && + (!pm->level || (isset(ALLEXPORT) && !pm->old))) { delenv(pm->env); zsfree(pm->env); pm->env = NULL; @@ -1593,13 +1619,68 @@ typeset_single(char *cname, char *pname, Param pm, int func, pname = dupstring(pname); unsetparam_pm(pm, 0, 1); } - /* - * Create a new node for a parameter with the flags in `on' minus the - * readonly flag - */ - pm = createparam(pname, on & ~PM_READONLY); - DPUTS(!pm, "BUG: parameter not created"); - pm->ct = auxlen; + + if (newspecial) { + Param tpm, pm2; + if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) { + zerrnam(cname, "%s: restricted", pname, 0); + return pm; + } + /* + * For specials, we keep the same struct but zero everything. + * Maybe it would be easier to create a new struct but copy + * the get/set methods. + */ + tpm = (Param) zalloc(sizeof *tpm); + + tpm->nam = pm->nam; + if (pm->ename && + (pm2 = (Param) paramtab->getnode(paramtab, pm->ename)) && + pm2->level == locallevel) { + /* This is getting silly, but anyway: if one of a path/PATH + * pair has already been made local at the current level, we + * have to make sure that the other one does not have its value + * saved: since that comes from an internal variable it will + * already reflect the local value, so restoring it on exit + * would be wrong. + * + * This problem is also why we make sure we have a copy + * of the environment entry in tpm->env, rather than relying + * on the restored value to provide it. + */ + tpm->flags = pm->flags | PM_NORESTORE; + } else { + copyparam(tpm, pm, 1); + } + tpm->old = pm->old; + tpm->level = pm->level; + tpm->ct = pm->ct; + tpm->env = pm->env; + + pm->old = tpm; + /* + * The remaining on/off flags should be harmless to use, + * because we've checked for unpleasant surprises above. + */ + pm->flags = (PM_TYPE(pm->flags) | on | PM_SPECIAL) & ~off; + /* + * Final tweak: if we've turned on one of the flags with + * numbers, we should use the appropriate integer. + */ + if (on & (PM_LEFT|PM_RIGHT_B|PM_RIGHT_Z|PM_INTEGER)) + pm->ct = auxlen; + else + pm->ct = 0; + pm->env = NULL; + } else { + /* + * Create a new node for a parameter with the flags in `on' minus the + * readonly flag + */ + pm = createparam(pname, on & ~PM_READONLY); + DPUTS(!pm, "BUG: parameter not created"); + pm->ct = auxlen; + } if (altpm && PM_TYPE(pm->flags) == PM_SCALAR) { /* @@ -1618,6 +1699,28 @@ typeset_single(char *cname, char *pname, Param pm, int func, pm->level = locallevel; if (value && !(pm->flags & (PM_ARRAY|PM_HASHED))) setsparam(pname, ztrdup(value)); + else if (newspecial && !(pm->old->flags & PM_NORESTORE)) { + /* + * We need to use the special setting function to re-initialise + * the special parameter to empty. + */ + HEAPALLOC { + switch (PM_TYPE(pm->flags)) { + case PM_SCALAR: + pm->sets.cfn(pm, ztrdup("")); + break; + case PM_INTEGER: + pm->sets.ifn(pm, 0); + break; + case PM_ARRAY: + pm->sets.afn(pm, mkarray(NULL)); + break; + case PM_HASHED: + pm->sets.hfn(pm, newparamtable(17, pm->nam)); + break; + } + } LASTALLOC; + } pm->flags |= (on & PM_READONLY); if (value && (pm->flags & (PM_ARRAY|PM_HASHED))) { zerrnam(cname, "%s: can't assign initial value for array", pname, 0); @@ -1839,7 +1942,7 @@ bin_functions(char *name, char **argv, char *ops, int func) Comp com; Shfunc shf; int i, returnval = 0; - int on = 0, off = 0; + int on = 0, off = 0, pflags = 0; /* Do we have any flags defined? */ if (ops['u'] == 1) @@ -1860,13 +1963,17 @@ bin_functions(char *name, char **argv, char *ops, int func) return 1; } + if (ops['f'] == 2 || ops['+']) + pflags |= PRINT_NAMEONLY; + /* If no arguments given, we will print functions. If flags * * are given, we will print only functions containing these * * flags, else we'll print them all. */ if (!*argv) { if (ops['U'] && !ops['u']) on &= ~PM_UNDEFINED; - scanhashtable(shfunctab, 1, on|off, DISABLED, shfunctab->printnode, 0); + scanhashtable(shfunctab, 1, on|off, DISABLED, shfunctab->printnode, + pflags); return 0; } @@ -1879,7 +1986,8 @@ bin_functions(char *name, char **argv, char *ops, int func) if ((com = parsereg(*argv))) { /* with no options, just print all functions matching the glob pattern */ if (!(on|off)) { - scanmatchtable(shfunctab, com, 0, DISABLED, shfunctab->printnode, 0); + scanmatchtable(shfunctab, com, 0, DISABLED, + shfunctab->printnode, pflags); } else { /* apply the options to all functions matching the glob pattern */ for (i = 0; i < shfunctab->hsize; i++) { @@ -1906,7 +2014,7 @@ bin_functions(char *name, char **argv, char *ops, int func) shf->flags = (shf->flags | (on & ~PM_UNDEFINED)) & ~off; else /* no flags, so just print */ - shfunctab->printnode((HashNode) shf, 0); + shfunctab->printnode((HashNode) shf, pflags); } else if (on & PM_UNDEFINED) { /* Add a new undefined (autoloaded) function to the * * hash table with the corresponding flags set. */ @@ -2407,6 +2515,8 @@ bin_alias(char *name, char **argv, char *ops, int func) if (ops['L']) printflags |= PRINT_LIST; + else if (ops['r'] == 2 || ops['g'] == 2 || ops['m'] == 2 || ops['+']) + printflags |= PRINT_NAMEONLY; /* In the absence of arguments, list all aliases. If a command * * line flag is specified, list only those of that type. */ @@ -2512,8 +2622,8 @@ bin_print(char *name, char **args, char *ops, int func) if (!ops['e'] && (ops['R'] || ops['r'] || ops['E'])) unmetafy(args[n], &len[n]); else - args[n] = getkeystring(args[n], &len[n], - func != BIN_ECHO && !ops['e'], &nnl); + args[n] = getkeystring(args[n], &len[n], ops['b'] ? 2 : + (func != BIN_ECHO && !ops['e']), &nnl); /* -P option -- interpret as a prompt sequence */ if(ops['P']) { /* @@ -3098,11 +3208,7 @@ bin_eval(char *nam, char **argv, char *ops, int func) { List list; - inpush(zjoin(argv, ' '), 0, NULL); - strinbeg(0); - list = parse_list(); - strinend(); - inpop(); + list = parse_string(zjoin(argv, ' '), 0); if (!list) { errflag = 0; return 1; diff --git a/Src/exec.c b/Src/exec.c index bc5548f1e..9c7a1ceb5 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -916,7 +916,7 @@ execpline(Sublist l, int how, int last1) } jn->stat &= ~(STAT_DONE | STAT_NOPRINT); - jn->stat |= STAT_STOPPED | STAT_CHANGED; + jn->stat |= STAT_STOPPED | STAT_CHANGED | STAT_LOCKED; printjob(jn, !!isset(LONGLISTJOBS), 1); } else if (newjob != list_pipe_job) @@ -1012,7 +1012,9 @@ execpline(Sublist l, int how, int last1) jn = jobtab + pj; killjb(jn, lastval & ~0200); } - if (list_pipe_child || (list_pipe && (jn->stat & STAT_DONE))) + if (list_pipe_child || + ((jn->stat & STAT_DONE) && + (list_pipe || (pline_level && !(jn->stat & STAT_SUBJOB))))) deletejob(jn); thisjob = pj; @@ -1530,6 +1532,9 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) /* Was this "exec < foobar"? */ nullexec = 1; break; + } else if (vars && nonempty(vars)) { + nullexec = 2; + break; } else if (!nullcmd || !*nullcmd || (cflags & BINF_PREFIX)) { zerr("redirection with no command", NULL, 0); @@ -1869,7 +1874,8 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) addfd(forked, save, mfds, fn->fd1, fil, 0); /* If this is 'exec < file', read from stdin, * * not terminal, unless `file' is a terminal. */ - if (nullexec && fn->fd1 == 0 && isset(SHINSTDIN) && interact) + if (nullexec == 1 && fn->fd1 == 0 && + isset(SHINSTDIN) && interact) init_io(); break; case CLOSE: @@ -1929,17 +1935,28 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) closemn(mfds, i); if (nullexec) { - for (i = 0; i < 10; i++) - if (save[i] != -2) - zclose(save[i]); + if (nullexec == 1) { + /* + * If nullexec is 1 we specifically *don't* restore the original + * fd's before returning. + */ + for (i = 0; i < 10; i++) + if (save[i] != -2) + zclose(save[i]); + return; + } /* - * Here we specifically *don't* restore the original fd's - * before returning. + * If nullexec is 2, we have variables to add with the redirections + * in place. */ - return; - } - - if (isset(EXECOPT) && !errflag) { + if (vars) + addvars(vars, 0); + lastval = errflag ? errflag : cmdoutval; + if (isset(XTRACE)) { + fputc('\n', stderr); + fflush(stderr); + } + } else if (isset(EXECOPT) && !errflag) { /* * We delay the entersubsh() to here when we are exec'ing * the current shell (including a fake exec to run a builtin then diff --git a/Src/hist.c b/Src/hist.c index edf74009e..167ffe171 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -291,7 +291,7 @@ safeinungetc(int c) void herrflush(void) { - while (!lexstop && inbufct) + while (!lexstop && inbufct && !strin) hwaddc(ingetc()); } diff --git a/Src/jobs.c b/Src/jobs.c index b2d7e9af1..fdf69a960 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -125,6 +125,86 @@ findproc(pid_t pid, Job *jptr, Process *pptr) return 0; } +/* Find the super-job of a sub-job. */ + +/**/ +static int +super_job(int sub) +{ + int i; + + for (i = 1; i < MAXJOB; i++) + if ((jobtab[i].stat & STAT_SUPERJOB) && + jobtab[i].other == sub && + jobtab[i].gleader) + return i; + return 0; +} + +/**/ +static int +handle_sub(int job, int fg) +{ + Job jn = jobtab + job, sj = jobtab + jn->other; + + if ((sj->stat & STAT_DONE) || !sj->procs) { + struct process *p; + + for (p = sj->procs; p; p = p->next) + if (WIFSIGNALED(p->status)) { + if (jn->gleader != mypgrp && jn->procs->next) + killpg(jn->gleader, WTERMSIG(p->status)); + else + kill(jn->procs->pid, WTERMSIG(p->status)); + kill(sj->other, SIGCONT); + kill(sj->other, WTERMSIG(p->status)); + break; + } + if (!p) { + int cp; + + jn->stat &= ~STAT_SUPERJOB; + jn->stat |= STAT_WASSUPER; + + if ((cp = ((WIFEXITED(jn->procs->status) || + WIFSIGNALED(jn->procs->status)) && + killpg(jn->gleader, 0) == -1))) { + Process p; + for (p = jn->procs; p->next; p = p->next); + jn->gleader = p->pid; + } + /* This deleted the job too early if the parent + shell waited for a command in a list that will + be executed by the sub-shell (e.g.: if we have + `ls|if true;then sleep 20;cat;fi' and ^Z the + sleep, the rest will be executed by a sub-shell, + but the parent shell gets notified for the + sleep. + deletejob(sj); */ + /* If this super-job contains only the sub-shell, + we have to attach the tty to its process group + now. */ + if ((fg || thisjob == job) && + (!jn->procs->next || cp || jn->procs->pid != jn->gleader)) + attachtty(jn->gleader); + kill(sj->other, SIGCONT); + } + curjob = jn - jobtab; + } else if (sj->stat & STAT_STOPPED) { + struct process *p; + + jn->stat |= STAT_STOPPED; + for (p = jn->procs; p; p = p->next) + if (p->status == SP_RUNNING || + (!WIFEXITED(p->status) && !WIFSIGNALED(p->status))) + p->status = sj->procs->status; + curjob = jn - jobtab; + printjob(jn, !!isset(LONGLISTJOBS), 1); + return 1; + } + return 0; +} + /* Update status of process that we have just WAIT'ed for */ /**/ @@ -183,13 +263,8 @@ update_job(Job jn) * or to exit. So we have to send it a SIGTSTP. */ int i; - for (i = 1; i < MAXJOB; i++) - if ((jobtab[i].stat & STAT_SUPERJOB) && - jobtab[i].other == job && - jobtab[i].gleader) { - killpg(jobtab[i].gleader, SIGTSTP); - break; - } + if ((i = super_job(job))) + killpg(jobtab[i].gleader, SIGTSTP); } return; } @@ -254,6 +329,13 @@ update_job(Job jn) return; jn->stat |= (somestopped) ? STAT_CHANGED | STAT_STOPPED : STAT_CHANGED | STAT_DONE; + if (!inforeground && + (jn->stat & (STAT_SUBJOB | STAT_DONE)) == (STAT_SUBJOB | STAT_DONE)) { + int su; + + if ((su = super_job(jn - jobtab))) + handle_sub(su, 0); + } if ((jn->stat & (STAT_DONE | STAT_STOPPED)) == STAT_STOPPED) { prevjob = curjob; curjob = job; @@ -303,13 +385,14 @@ setprevjob(void) for (i = MAXJOB - 1; i; i--) if ((jobtab[i].stat & STAT_INUSE) && (jobtab[i].stat & STAT_STOPPED) && - i != curjob && i != thisjob) { + !(jobtab[i].stat & STAT_SUBJOB) && i != curjob && i != thisjob) { prevjob = i; return; } for (i = MAXJOB - 1; i; i--) - if ((jobtab[i].stat & STAT_INUSE) && i != curjob && i != thisjob) { + if ((jobtab[i].stat & STAT_INUSE) && !(jobtab[i].stat & STAT_SUBJOB) && + i != curjob && i != thisjob) { prevjob = i; return; } @@ -791,64 +874,9 @@ waitjob(int job, int sig) killjb(jn, SIGCONT); jn->stat &= ~STAT_STOPPED; } - if (jn->stat & STAT_SUPERJOB) { - Job sj = jobtab + jn->other; - if ((sj->stat & STAT_DONE) || !sj->procs) { - struct process *p; - - for (p = sj->procs; p; p = p->next) - if (WIFSIGNALED(p->status)) { - if (jn->gleader != mypgrp && jn->procs->next) - killpg(jn->gleader, WTERMSIG(p->status)); - else - kill(jn->procs->pid, WTERMSIG(p->status)); - kill(sj->other, SIGCONT); - kill(sj->other, WTERMSIG(p->status)); - break; - } - if (!p) { - int cp; - - jn->stat &= ~STAT_SUPERJOB; - jn->stat |= STAT_WASSUPER; - - if ((cp = ((WIFEXITED(jn->procs->status) || - WIFSIGNALED(jn->procs->status)) && - killpg(jn->gleader, 0) == -1))) { - Process p; - for (p = jn->procs; p->next; p = p->next); - jn->gleader = p->pid; - } - /* This deleted the job too early if the parent - shell waited for a command in a list that will - be executed by the sub-shell (e.g.: if we have - `ls|if true;then sleep 20;cat;fi' and ^Z the - sleep, the rest will be executed by a sub-shell, - but the parent shell gets notified for the - sleep. - deletejob(sj); */ - /* If this super-job contains only the sub-shell, - we have to attach the tty to our process group - (which is shared by the sub-shell) now. */ - if (!jn->procs->next || cp || jn->procs->pid != jn->gleader) - attachtty(jn->gleader); - kill(sj->other, SIGCONT); - } - curjob = jn - jobtab; - } - else if (sj->stat & STAT_STOPPED) { - struct process *p; - - jn->stat |= STAT_STOPPED; - for (p = jn->procs; p; p = p->next) - if (p->status == SP_RUNNING || - (!WIFEXITED(p->status) && !WIFSIGNALED(p->status))) - p->status = sj->procs->status; - curjob = jn - jobtab; - printjob(jn, !!isset(LONGLISTJOBS), 1); + if (jn->stat & STAT_SUPERJOB) + if (handle_sub(jn - jobtab, 1)) break; - } - } child_block(); } } else diff --git a/Src/loop.c b/Src/loop.c index 16e4ff314..fd63edb5a 100644 --- a/Src/loop.c +++ b/Src/loop.c @@ -57,6 +57,13 @@ execfor(Cmd cmd, LinkList args, int flags) if (node->condition) { str = dupstring(node->name); singsub(&str); + if (isset(XTRACE)) { + char *str2 = dupstring(str); + untokenize(str2); + printprompt4(); + fprintf(stderr, "%s\n", str2); + fflush(stderr); + } if (!errflag) matheval(str); if (errflag) @@ -79,9 +86,14 @@ execfor(Cmd cmd, LinkList args, int flags) if (!errflag) { while (iblank(*str)) str++; - if (*str) + if (*str) { + if (isset(XTRACE)) { + printprompt4(); + fprintf(stderr, "%s\n", str); + fflush(stderr); + } val = matheval(str); - else + } else val = 1; } if (errflag) { @@ -95,6 +107,11 @@ execfor(Cmd cmd, LinkList args, int flags) } else { if (!args || !(str = (char *) ugetnode(args))) break; + if (isset(XTRACE)) { + printprompt4(); + fprintf(stderr, "%s=%s\n", node->name, str); + fflush(stderr); + } setsparam(node->name, ztrdup(str)); } execlist(node->list, 1, @@ -107,6 +124,11 @@ execfor(Cmd cmd, LinkList args, int flags) } if (node->condition && !errflag) { str = dupstring(node->advance); + if (isset(XTRACE)) { + printprompt4(); + fprintf(stderr, "%s\n", str); + fflush(stderr); + } singsub(&str); if (!errflag) matheval(str); @@ -410,6 +432,13 @@ execcase(Cmd cmd, LinkList args, int flags) while (*p) { char *pat = dupstring(*p + 1); singsub(&pat); + if (isset(XTRACE)) { + char *pat2 = dupstring(pat); + untokenize(pat2); + printprompt4(); + fprintf(stderr, "case %s (%s)\n", word, pat2); + fflush(stderr); + } if (matchpat(word, pat)) { do { execlist(*l++, 1, **p == ';' && (flags & CFLAG_EXEC)); diff --git a/Src/math.c b/Src/math.c index 7e7e557ed..10821b284 100644 --- a/Src/math.c +++ b/Src/math.c @@ -357,9 +357,11 @@ zzlex(void) } if (*ptr == '#') { if (*++ptr == '\\') { + int v; + ptr++; - yyval = *ptr == Meta ? *++ptr ^ 32 : *ptr; - ptr++; + ptr = getkeystring(ptr, NULL, 6, &v); + yyval = v; unary = 0; return NUM; } diff --git a/Src/params.c b/Src/params.c index d71cfb46e..094d7a166 100644 --- a/Src/params.c +++ b/Src/params.c @@ -1905,7 +1905,7 @@ arrhashsetfn(Param pm, char **val) if (alen % 2) { freearray(val); - zerr("bad set of key/value pairs for associative array\n", + zerr("bad set of key/value pairs for associative array", NULL, 0); return; } @@ -2500,11 +2500,17 @@ arrfixenv(char *s, char **t) Param pm; MUSTUSEHEAP("arrfixenv"); + pm = (Param) paramtab->getnode(paramtab, s); + /* + * Only one level of a parameter can be exported. Unless + * ALLEXPORT is set, this must be global. + */ if (t == path) cmdnamtab->emptytable(cmdnamtab); + if (isset(ALLEXPORT) ? !!pm->old : pm->level) + return; u = t ? zjoin(t, ':') : ""; len_s = strlen(s); - pm = (Param) paramtab->getnode(paramtab, s); for (ep = environ; *ep; ep++) if (!strncmp(*ep, s, len_s) && (*ep)[len_s] == '=') { pm->env = replenv(*ep, u); @@ -2685,8 +2691,46 @@ static void scanendscope(HashNode hn, int flags) { Param pm = (Param)hn; - if(pm->level > locallevel) - unsetparam_pm(pm, 0, 0); + if (pm->level > locallevel) { + if ((pm->flags & (PM_SPECIAL|PM_REMOVABLE)) == PM_SPECIAL) { + /* + * Removable specials are normal in that they can be removed + * to reveal an ordinary parameter beneath. Here we handle + * non-removable specials, which were made local by stealth + * (see newspecial code in typeset_single()). In fact the + * visible pm is always the same struct; the pm->old is + * just a place holder for old data and flags. + */ + Param tpm = pm->old; + + DPUTS(!tpm || PM_TYPE(pm->flags) != PM_TYPE(tpm->flags) || + !(tpm->flags & PM_SPECIAL), + "BUG: in restoring scope of special parameter"); + pm->old = tpm->old; + pm->flags = (tpm->flags & ~PM_NORESTORE); + pm->level = tpm->level; + pm->ct = tpm->ct; + pm->env = tpm->env; + + if (!(tpm->flags & PM_NORESTORE)) + switch (PM_TYPE(pm->flags)) { + case PM_SCALAR: + pm->sets.cfn(pm, tpm->u.str); + break; + case PM_INTEGER: + pm->sets.ifn(pm, tpm->u.val); + break; + case PM_ARRAY: + pm->sets.afn(pm, tpm->u.arr); + break; + case PM_HASHED: + pm->sets.hfn(pm, tpm->u.hash); + break; + } + zfree(tpm, sizeof(*tpm)); + } else + unsetparam_pm(pm, 0, 0); + } } diff --git a/Src/prompt.c b/Src/prompt.c index 89407694e..dcba16d56 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -97,6 +97,38 @@ static int dontcount; static char *rstring, *Rstring; +/* + * Expand path p; maximum is npath segments where 0 means the whole path. + * If tilde is 1, try and find a named directory to use. + */ + +static void +promptpath(char *p, int npath, int tilde) +{ + char *modp = p; + Nameddir nd; + + if (tilde && ((nd = finddir(p)))) + modp = tricat("~", nd->nam, p + strlen(nd->dir)); + + if (npath) { + char *sptr; + for (sptr = modp + strlen(modp); sptr > modp; sptr--) { + if (*sptr == '/' && !--npath) { + sptr++; + break; + } + } + if (*sptr == '/' && sptr[1] && sptr != modp) + sptr++; + stradd(sptr); + } else + stradd(modp); + + if (p != modp) + zsfree(modp); +} + /* Perform prompt expansion on a string, putting the result in a * * permanently-allocated string. If ns is non-zero, this string * * may have embedded Inpar and Outpar, which indicate a toggling * @@ -293,49 +325,21 @@ putpromptchar(int doprint, int endchar) } switch (*fm) { case '~': - if ((nd = finddir(pwd))) { - char *t = tricat("~", nd->nam, pwd + strlen(nd->dir)); - stradd(t); - zsfree(t); - break; - } + promptpath(pwd, arg, 1); + break; case 'd': case '/': - stradd(pwd); + promptpath(pwd, arg, 0); break; case 'c': case '.': - { - char *t; - - if ((nd = finddir(pwd))) - t = tricat("~", nd->nam, pwd + strlen(nd->dir)); - else - t = ztrdup(pwd); - if (!arg) - arg++; - for (ss = t + strlen(t); ss > t; ss--) - if (*ss == '/' && !--arg) { - ss++; - break; - } - if(*ss == '/' && ss[1] && ss != t) - ss++; - stradd(ss); - zsfree(t); - break; - } + promptpath(pwd, arg ? arg : 1, 1); + break; case 'C': - if (!arg) - arg++; - for (ss = pwd + strlen(pwd); ss > pwd; ss--) - if (*ss == '/' && !--arg) { - ss++; - break; - } - if (*ss == '/' && ss[1] && (ss != pwd)) - ss++; - stradd(ss); + promptpath(pwd, arg ? arg : 1, 0); + break; + case 'N': + promptpath(scriptname ? scriptname : argzero, arg, 0); break; case 'h': case '!': @@ -536,9 +540,6 @@ putpromptchar(int doprint, int endchar) sprintf(bp, "%ld", (long)lineno); bp += strlen(bp); break; - case 'N': - stradd(scriptname ? scriptname : argzero); - break; case '\0': return 0; case Meta: diff --git a/Src/utils.c b/Src/utils.c index a409ab03c..d82f62694 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -1735,10 +1735,11 @@ findsep(char **s, char *sep) if (!*t) return i; if (*(*s)++ == Meta) { - (*s)++; #ifdef DEBUG - if (! **s) + if (! *(*s)++) fprintf(stderr, "BUG: unexpected end of string in findsep()\n"); +#else + (*s)++; #endif } } @@ -3187,24 +3188,28 @@ dquotedzputs(char const *s, FILE *stream) * 4: Do $'...' quoting. Overwrites the existing string instead of * zhalloc'ing * 5: As 2, but \- is special. Expects misc to be defined. + * 6: As 2, but parses only one character and returns end-pointer + * and parsed character in *misc */ /**/ char * getkeystring(char *s, int *len, int fromwhere, int *misc) { - char *buf; + char *buf, tmp[1]; char *t, *u = NULL; char svchar = '\0'; int meta = 0, control = 0; - if (fromwhere != 4) - buf = zhalloc(strlen(s) + 1); + if (fromwhere == 6) + t = tmp; + else if (fromwhere != 4) + t = buf = zhalloc(strlen(s) + 1); else { - buf = s; + t = buf = s; s += 2; } - for (t = buf; *s; s++) { + for (; *s; s++) { if (*s == '\\' && s[1]) { switch (*++s) { case 'a': @@ -3303,7 +3308,8 @@ 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 || fromwhere == 5)) { + } else if (*s == '^' && + (fromwhere == 2 || fromwhere == 5 || fromwhere == 6)) { control = 1; continue; } else if (*s == Meta) @@ -3330,6 +3336,10 @@ getkeystring(char *s, int *len, int fromwhere, int *misc) t[-1] = Meta; t++; } + if (fromwhere == 6 && t != tmp) { + *misc = (int) tmp[0]; + return s + 1; + } } DPUTS(fromwhere == 4, "BUG: unterminated $' substitution"); *t = '\0'; diff --git a/Src/zsh.h b/Src/zsh.h index 88175eea6..2070e9b3f 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -951,40 +951,41 @@ struct param { /* flags for parameters */ /* parameter types */ -#define PM_SCALAR 0 /* scalar */ -#define PM_ARRAY (1<<0) /* array */ -#define PM_INTEGER (1<<1) /* integer */ -#define PM_HASHED (1<<2) /* association */ +#define PM_SCALAR 0 /* scalar */ +#define PM_ARRAY (1<<0) /* array */ +#define PM_INTEGER (1<<1) /* integer */ +#define PM_HASHED (1<<2) /* association */ #define PM_TYPE(X) (X & (PM_SCALAR|PM_INTEGER|PM_ARRAY|PM_HASHED)) -#define PM_LEFT (1<<3) /* left justify and remove leading blanks */ -#define PM_RIGHT_B (1<<4) /* right justify and fill with leading blanks */ -#define PM_RIGHT_Z (1<<5) /* right justify and fill with leading zeros */ -#define PM_LOWER (1<<6) /* all lower case */ +#define PM_LEFT (1<<3) /* left justify, remove leading blanks */ +#define PM_RIGHT_B (1<<4) /* right justify, fill with leading blanks */ +#define PM_RIGHT_Z (1<<5) /* right justify, fill with leading zeros */ +#define PM_LOWER (1<<6) /* all lower case */ /* The following are the same since they * * both represent -u option to typeset */ -#define PM_UPPER (1<<7) /* all upper case */ -#define PM_UNDEFINED (1<<7) /* undefined (autoloaded) shell function */ +#define PM_UPPER (1<<7) /* all upper case */ +#define PM_UNDEFINED (1<<7) /* undefined (autoloaded) shell function */ -#define PM_READONLY (1<<8) /* readonly */ -#define PM_TAGGED (1<<9) /* tagged */ -#define PM_EXPORTED (1<<10) /* exported */ +#define PM_READONLY (1<<8) /* readonly */ +#define PM_TAGGED (1<<9) /* tagged */ +#define PM_EXPORTED (1<<10) /* exported */ /* The following are the same since they * * both represent -U option to typeset */ -#define PM_UNIQUE (1<<11) /* remove duplicates */ -#define PM_UNALIASED (1<<11) /* do not expand aliases when autoloading */ - -#define PM_TIED (1<<12) /* array tied to colon-path or v.v. */ -#define PM_LOCAL (1<<13) /* this parameter will be made local */ -#define PM_SPECIAL (1<<14) /* special builtin parameter */ -#define PM_DONTIMPORT (1<<15) /* do not import this variable */ -#define PM_RESTRICTED (1<<16) /* cannot be changed in restricted mode */ -#define PM_UNSET (1<<17) /* has null value */ -#define PM_REMOVABLE (1<<18) /* special can be removed from paramtab */ -#define PM_AUTOLOAD (1<<19) /* autoloaded from module */ +#define PM_UNIQUE (1<<11) /* remove duplicates */ +#define PM_UNALIASED (1<<11) /* do not expand aliases when autoloading */ + +#define PM_TIED (1<<12) /* array tied to colon-path or v.v. */ +#define PM_LOCAL (1<<13) /* this parameter will be made local */ +#define PM_SPECIAL (1<<14) /* special builtin parameter */ +#define PM_DONTIMPORT (1<<15) /* do not import this variable */ +#define PM_RESTRICTED (1<<16) /* cannot be changed in restricted mode */ +#define PM_UNSET (1<<17) /* has null value */ +#define PM_REMOVABLE (1<<18) /* special can be removed from paramtab */ +#define PM_AUTOLOAD (1<<19) /* autoloaded from module */ +#define PM_NORESTORE (1<<20) /* do not restore value of local special */ /* Flags for extracting elements of arrays and associative arrays */ #define SCANPM_WANTVALS (1<<0) |