diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/Zle/comp.h | 5 | ||||
-rw-r--r-- | Src/Zle/comp1.c | 8 | ||||
-rw-r--r-- | Src/Zle/comp1.export | 3 | ||||
-rw-r--r-- | Src/Zle/compctl.c | 67 | ||||
-rw-r--r-- | Src/Zle/iwidgets.list | 2 | ||||
-rw-r--r-- | Src/Zle/zle.h | 24 | ||||
-rw-r--r-- | Src/Zle/zle_main.c | 29 | ||||
-rw-r--r-- | Src/Zle/zle_params.c | 23 | ||||
-rw-r--r-- | Src/Zle/zle_thingy.c | 57 | ||||
-rw-r--r-- | Src/Zle/zle_tricky.c | 847 | ||||
-rw-r--r-- | Src/builtin.c | 132 | ||||
-rw-r--r-- | Src/glob.c | 321 | ||||
-rw-r--r-- | Src/init.c | 45 | ||||
-rw-r--r-- | Src/lex.c | 5 | ||||
-rw-r--r-- | Src/params.c | 66 | ||||
-rw-r--r-- | Src/subst.c | 45 | ||||
-rw-r--r-- | Src/zsh.export | 1 | ||||
-rw-r--r-- | Src/zsh.h | 11 |
18 files changed, 1078 insertions, 613 deletions
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h index afd55b7f1..20e3d2cce 100644 --- a/Src/Zle/comp.h +++ b/Src/Zle/comp.h @@ -267,3 +267,8 @@ struct cline { #define CLF_MISS 4 #define CLF_DIFF 8 #define CLF_SUF 16 + +/* Flags for makecomplist*(). Things not to do. */ + +#define CFN_FIRST 1 +#define CFN_DEFAULT 2 diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c index 42bc92bb2..36588a385 100644 --- a/Src/Zle/comp1.c +++ b/Src/Zle/comp1.c @@ -44,12 +44,6 @@ Cmlist cmatcher; /* pointers to functions required by zle and defined by compctl */ /**/ -void (*printcompctlptr) _((char *, Compctl, int, int)); - -/**/ -Compctl (*compctl_widgetptr) _((char *, char **)); - -/**/ void (*makecompparamsptr) _((void)); /* pointers to functions required by compctl and defined by zle */ @@ -66,6 +60,8 @@ int (*getcpatptr) _((char *, int, char *, int)); /**/ void (*makecomplistcallptr) _((Compctl)); +/**/ +void (*makecomplistctlptr) _((int)); /* Hash table for completion info for commands */ diff --git a/Src/Zle/comp1.export b/Src/Zle/comp1.export index c90161740..72581173b 100644 --- a/Src/Zle/comp1.export +++ b/Src/Zle/comp1.export @@ -11,7 +11,6 @@ clwsize cmatcher compcommand compcontext -compctl_widgetptr compctltab compcurrent compiprefix @@ -28,8 +27,8 @@ incompctlfunc incompfunc instring makecomplistcallptr +makecomplistctlptr makecompparamsptr patcomps -printcompctlptr quotename rembslash diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 1913d3828..879042cf3 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -1638,38 +1638,6 @@ bin_compctl(char *name, char **argv, char *ops, int func) return ret; } -/* Externally callable version of get_compctl. Used for completion widgets */ - -/**/ -static Compctl -compctl_widget(char *name, char **argv) -{ - Compctl cc = (Compctl) zcalloc(sizeof(*cc)); - cclist = 0; - showmask = 0; - - if (get_compctl(name, &argv, cc, 1, 0, 0)) { - freecompctl(cc); - return NULL; - } - - if (cclist & COMP_REMOVE) { - zwarnnam(name, "use -D to delete widget", NULL, 0); - return NULL; - } else if (cclist) { - zwarnnam(name, "special options illegal in widget", NULL, 0); - freecompctl(cc); - return NULL; - } else if (*argv) { - zwarnnam(name, "command names illegal in widget", NULL, 0); - freecompctl(cc); - return NULL; - } - cc->refc++; - - return cc; -} - /**/ static int bin_complist(char *name, char **argv, char *ops, int func) @@ -1677,7 +1645,7 @@ bin_complist(char *name, char **argv, char *ops, int func) Compctl cc; int ret = 0; - if (!incompfunc) { + if (incompfunc != 1) { zerrnam(name, "can only be called from completion function", NULL, 0); return 1; } @@ -1706,7 +1674,7 @@ bin_compadd(char *name, char **argv, char *ops, int func) char *pre = NULL, *suf = NULL, *group = NULL; int f = 0, q = 0, m = 0, ns = 0, a = 0; - if (!incompfunc) { + if (incompfunc != 1) { zerrnam(name, "can only be called from completion function", NULL, 0); return 1; } @@ -1792,15 +1760,27 @@ bin_compadd(char *name, char **argv, char *ops, int func) } } ca_args: - if (!*argv) { - zerrnam(name, "missing completions", NULL, 0); + if (!*argv) return 1; - } + addmatchesptr(ipre, ppre, psuf, prpre, pre, suf, group, f, q, m, ns, a, argv); return 0; } +/**/ +static int +bin_compcall(char *name, char **argv, char *ops, int func) +{ + if (incompfunc != 1) { + zerrnam(name, "can only be called from completion function", NULL, 0); + return 1; + } + makecomplistctlptr((ops['T'] ? 0 : CFN_FIRST) | + (ops['D'] ? 0 : CFN_DEFAULT)); + return 0; +} + #define VAR(X) ((void *) (&(X))) static struct compparam { char *name; @@ -1823,7 +1803,7 @@ void makecompparams(void) struct compparam *cp; for (cp = compparams; cp->name; cp++) { - Param pm = createparam(cp->name, cp->type | PM_SPECIAL); + Param pm = createparam(cp->name, cp->type | PM_SPECIAL|PM_REMOVABLE); if (!pm) pm = (Param) paramtab->getnode(paramtab, cp->name); DPUTS(!pm, "param not set in makecompparams"); @@ -1856,7 +1836,7 @@ compunsetfn(Param pm, int exp) static int comp_wrapper(List list, FuncWrap w, char *name) { - if (!incompfunc) + if (incompfunc != 1) return 1; else { char *octxt, *ocmd, *opre, *osuf, *oipre; @@ -1907,7 +1887,7 @@ ignore_prefix(int l) static int comp_check(void) { - if (!incompfunc) { + if (incompfunc != 1) { zerr("condition can only be used in completion function", NULL, 0); return 0; } @@ -2119,7 +2099,8 @@ cond_nmatches(char **a, int id) static struct builtin bintab[] = { BUILTIN("compctl", 0, bin_compctl, 0, -1, 0, NULL, NULL), BUILTIN("complist", 0, bin_complist, 1, -1, 0, NULL, NULL), - BUILTIN("compadd", 0, bin_compadd, 1, -1, 0, NULL, NULL), + BUILTIN("compadd", 0, bin_compadd, 0, -1, 0, NULL, NULL), + BUILTIN("compcall", 0, bin_compcall, 0, 0, 0, "TD", NULL), }; static struct conddef cotab[] = { @@ -2149,8 +2130,6 @@ int setup_compctl(Module m) { compctltab->printnode = printcompctlp; - printcompctlptr = printcompctl; - compctl_widgetptr = compctl_widget; makecompparamsptr = makecompparams; return 0; } @@ -2183,8 +2162,6 @@ int finish_compctl(Module m) { compctltab->printnode = NULL; - printcompctlptr = NULL; - compctl_widgetptr = NULL; makecompparamsptr = NULL; return 0; } diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list index 12425d872..61ad0e24a 100644 --- a/Src/Zle/iwidgets.list +++ b/Src/Zle/iwidgets.list @@ -26,7 +26,7 @@ "capitalize-word", capitalizeword, 0 "clear-screen", clearscreen, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND "complete-word", completeword, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP -"copy-prev-word", copyprevword, 0 +"copy-prev-word", copyprevword, ZLE_KEEPSUFFIX "copy-region-as-kill", copyregionaskill, ZLE_KEEPSUFFIX "delete-char", deletechar, ZLE_KEEPSUFFIX "delete-char-or-list", deletecharorlist, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h index f12505bd3..144bb1996 100644 --- a/Src/Zle/zle.h +++ b/Src/Zle/zle.h @@ -46,7 +46,6 @@ struct widget { union { ZleIntFunc fn; /* pointer to internally implemented widget */ char *fnnam; /* name of the shell function for user-defined widget */ - Compctl cc; /* for use with a WIDGET_COMP widget */ struct { ZleIntFunc fn; /* internal widget function to call */ char *wid; /* name of widget to call */ @@ -56,20 +55,15 @@ struct widget { }; #define WIDGET_INT (1<<0) /* widget is internally implemented */ -#define WIDGET_COMP (1<<1) /* Special completion widget */ -#define WIDGET_NCOMP (1<<2) /* new style completion widget */ -#define ZLE_MENUCMP (1<<3) /* DON'T invalidate completion list */ -#define ZLE_YANK (1<<4) -#define ZLE_LINEMOVE (1<<5) /* command is a line-oriented movement */ -#define ZLE_LASTCOL (1<<6) /* command maintains lastcol correctly */ -#define ZLE_KILL (1<<7) -#define ZLE_KEEPSUFFIX (1<<9) /* DON'T remove added suffix */ -#define ZLE_USEMENU (1<<10) /* Do ) use menu completion for */ -#define ZLE_NOMENU (1<<11) /* Don't ) widget, else use default */ -#define ZLE_USEGLOB (1<<12) /* Do ) use glob completion for */ -#define ZLE_NOGLOB (1<<13) /* Don't ) widget, else use default */ -#define ZLE_NOTCOMMAND (1<<14) /* widget should not alter lastcmd */ -#define ZLE_ISCOMP (1<<15) /* usable for new style completion */ +#define WIDGET_NCOMP (1<<1) /* new style completion widget */ +#define ZLE_MENUCMP (1<<2) /* DON'T invalidate completion list */ +#define ZLE_YANK (1<<3) +#define ZLE_LINEMOVE (1<<4) /* command is a line-oriented movement */ +#define ZLE_LASTCOL (1<<5) /* command maintains lastcol correctly */ +#define ZLE_KILL (1<<6) +#define ZLE_KEEPSUFFIX (1<<7) /* DON'T remove added suffix */ +#define ZLE_NOTCOMMAND (1<<8) /* widget should not alter lastcmd */ +#define ZLE_ISCOMP (1<<9) /* usable for new style completion */ /* thingies */ struct thingy { diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 2c0d3655e..03549b5d0 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -45,10 +45,10 @@ int mark; /**/ int c; -/* the binding for this key */ +/* the bindings for the previous and for this key */ /**/ -Thingy bindk; +Thingy lbindk, bindk; /* insert mode/overwrite mode flag */ @@ -554,6 +554,7 @@ zleread(char *lp, char *rp, int ha) void execzlefunc(Thingy func) { + int r = 0; Widget w; if(func->flags & DISABLED) { @@ -565,14 +566,13 @@ execzlefunc(Thingy func) showmsg(msg); zsfree(msg); feep(); - } else if((w = func->widget)->flags & - (WIDGET_INT|WIDGET_COMP | WIDGET_NCOMP)) { + } else if((w = func->widget)->flags & (WIDGET_INT|WIDGET_NCOMP)) { int wflags = w->flags; if(!(wflags & ZLE_KEEPSUFFIX)) removesuffix(); if(!(wflags & ZLE_MENUCMP) || - ((wflags & (WIDGET_COMP|WIDGET_NCOMP)) && compwidget != w)) { + ((wflags & WIDGET_NCOMP) && compwidget != w)) { /* If we are doing a special completion, and the widget * is not the one currently in use for special completion, * we are starting a new completion. @@ -584,16 +584,14 @@ execzlefunc(Thingy func) vilinerange = 1; if(!(wflags & ZLE_LASTCOL)) lastcol = -1; - if (wflags & WIDGET_COMP) { - compwidget = w; - completespecial(); - } else if (wflags & WIDGET_NCOMP) { + if (wflags & WIDGET_NCOMP) { compwidget = w; completecall(); } else w->u.fn(); if (!(wflags & ZLE_NOTCOMMAND)) lastcmd = wflags; + r = 1; } else { List l = getshfunc(w->u.fnnam); @@ -610,14 +608,20 @@ execzlefunc(Thingy func) int osc = sfcontext; startparamscope(); - makezleparams(); + makezleparams(0); sfcontext = SFC_WIDGET; doshfunc(w->u.fnnam, l, NULL, 0, 1); sfcontext = osc; endparamscope(); lastcmd = 0; + r = 1; } } + if (r) { + unrefthingy(lbindk); + refthingy(func); + lbindk = func; + } } /* initialise command modifiers */ @@ -877,9 +881,11 @@ setup_zle(Module m) comp_strptr = comp_str; getcpatptr = getcpat; makecomplistcallptr = makecomplistcall; + makecomplistctlptr = makecomplistctl; /* initialise the thingies */ init_thingies(); + lbindk = NULL; /* miscellaneous initialisations */ stackhist = stackcs = -1; @@ -920,6 +926,8 @@ finish_zle(Module m) { int i; + unrefthingy(lbindk); + cleanup_keymaps(); deletehashtable(thingytab); @@ -944,6 +952,7 @@ finish_zle(Module m) comp_strptr = NULL; getcpatptr = NULL; makecomplistcallptr = NULL; + makecomplistctlptr = NULL; return 0; } diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c index e0c4e94ec..74f905ef4 100644 --- a/Src/Zle/zle_params.c +++ b/Src/Zle/zle_params.c @@ -61,17 +61,22 @@ static struct zleparam { zleunsetfn, NULL }, { "RBUFFER", PM_SCALAR, FN(set_rbuffer), FN(get_rbuffer), zleunsetfn, NULL }, + { "WIDGET", PM_SCALAR | PM_READONLY, NULL, FN(get_widget), + zleunsetfn, NULL }, + { "LASTWIDGET", PM_SCALAR | PM_READONLY, NULL, FN(get_lwidget), + zleunsetfn, NULL }, { NULL, 0, NULL, NULL, NULL, NULL } }; /**/ void -makezleparams(void) +makezleparams(int ro) { struct zleparam *zp; for(zp = zleparams; zp->name; zp++) { - Param pm = createparam(zp->name, zp->type | PM_SPECIAL); + Param pm = createparam(zp->name, (zp->type |PM_SPECIAL|PM_REMOVABLE| + (ro ? PM_READONLY : 0))); if (!pm) pm = (Param) paramtab->getnode(paramtab, zp->name); DPUTS(!pm, "param not set in makezleparams"); @@ -197,3 +202,17 @@ get_rbuffer(Param pm) { return metafy((char *)line + cs, ll - cs, META_HEAPDUP); } + +/**/ +static char * +get_widget(Param pm) +{ + return bindk->nam; +} + +/**/ +static char * +get_lwidget(Param pm) +{ + return (lbindk ? lbindk->nam : ""); +} diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c index 2e21b5add..629d5a84e 100644 --- a/Src/Zle/zle_thingy.c +++ b/Src/Zle/zle_thingy.c @@ -244,9 +244,7 @@ unbindwidget(Thingy t, int override) static void freewidget(Widget w) { - if ((w->flags & WIDGET_COMP) && w->u.cc) - freecompctl(w->u.cc); - else if (w->flags & WIDGET_NCOMP) { + if (w->flags & WIDGET_NCOMP) { zsfree(w->u.comp.wid); zsfree(w->u.comp.func); } else if(!(w->flags & WIDGET_INT)) @@ -339,7 +337,7 @@ bin_zle(char *name, char **args, char *ops, int func) { 'D', bin_zle_del, 1, -1 }, { 'A', bin_zle_link, 2, 2 }, { 'N', bin_zle_new, 1, 2 }, - { 'C', bin_zle_compctl, 1, -1}, + { 'C', bin_zle_complete, 3, 3 }, { 'c', bin_zle_complete, 3, 3 }, { 0, bin_zle_call, 0, -1 }, }; @@ -392,14 +390,11 @@ scanlistwidgets(HashNode hn, int list) if(w->flags & WIDGET_INT) return; if(list) { - fputs((w->flags & WIDGET_COMP) ? "zle -C " : "zle -N ", stdout); + fputs("zle -N ", stdout); if(t->nam[0] == '-') fputs("-- ", stdout); quotedzputs(t->nam, stdout); - if (w->flags & WIDGET_COMP) { - if (printcompctlptr && w->u.cc) - printcompctlptr(NULL, w->u.cc, PRINT_LIST, 0); - } else if (w->flags & WIDGET_NCOMP) { + if (w->flags & WIDGET_NCOMP) { fputc(' ', stdout); quotedzputs(w->u.comp.wid, stdout); fputc(' ', stdout); @@ -410,11 +405,7 @@ scanlistwidgets(HashNode hn, int list) } } else { nicezputs(t->nam, stdout); - if (w->flags & WIDGET_COMP) { - fputs(" -C", stdout); - if (printcompctlptr && w->u.cc) - printcompctlptr(NULL, w->u.cc, PRINT_TYPE, 0); - } else if (w->flags & WIDGET_NCOMP) { + if (w->flags & WIDGET_NCOMP) { fputs(" -c ", stdout); nicezputs(w->u.comp.wid, stdout); fputc(' ', stdout); @@ -482,44 +473,6 @@ bin_zle_new(char *name, char **args, char *ops, char func) /**/ static int -bin_zle_compctl(char *name, char **args, char *ops, char func) -{ - Compctl cc = NULL; - Widget w; - char *wname = args[0]; - - if (!compctl_widgetptr) { - zwarnnam(name, "compctl module is not loaded", NULL, 0); - return 1; - } - - args++; - - if (*args && !(cc = compctl_widgetptr(name, args))) - return 1; - - w = zalloc(sizeof(*w)); - w->flags = WIDGET_COMP|ZLE_MENUCMP|ZLE_KEEPSUFFIX; - w->first = NULL; - w->u.cc = cc; - if(bindwidget(w, rthingy(wname))) { - freewidget(w); - zerrnam(name, "widget name `%s' is protected", wname, 0); - return 1; - } - if (ops['m']) - w->flags |= ZLE_USEMENU; - else if (ops['M']) - w->flags |= ZLE_NOMENU; - if (ops['g']) - w->flags |= ZLE_USEGLOB; - else if (ops['G']) - w->flags |= ZLE_NOGLOB; - return 0; -} - -/**/ -static int bin_zle_complete(char *name, char **args, char *ops, char func) { Thingy t; diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index a958752ca..df3e11f46 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -98,10 +98,12 @@ static int menupos, menulen, menuend, menuwe, menuinsc; /* This is for completion inside a brace expansion. brbeg and brend hold * * strings that were temporarily removed from the string to complete. * - * brpl and brsl hold the offset of these strings. */ + * brpl and brsl hold the offset of these strings. * + * brpcs and brscs hold the positions of the re-inserted string in the * + * line. */ static char *brbeg = NULL, *brend = NULL; -static int brpl, brsl; +static int brpl, brsl, brpcs, brscs; /* The list of matches. fmatches contains the matches we first ignore * * because of fignore. */ @@ -261,7 +263,6 @@ usetab(void) } enum { COMP_COMPLETE, - COMP_WIDGET, COMP_LIST_COMPLETE, COMP_SPELL, COMP_EXPAND, @@ -271,18 +272,6 @@ enum { COMP_COMPLETE, /**/ void -completespecial(void) -{ - int flags = compwidget->flags; - usemenu = (flags & ZLE_USEMENU) ? 1 : (flags & ZLE_NOMENU) ? 0 - : isset(MENUCOMPLETE); - useglob = (flags & ZLE_USEGLOB) ? 1 : (flags & ZLE_NOGLOB) ? 0 - : isset(GLOBCOMPLETE); - docomplete(compwidget->u.cc ? COMP_WIDGET : COMP_COMPLETE); -} - -/**/ -void completecall(void) { compfunc = compwidget->u.comp.func; @@ -426,19 +415,30 @@ reversemenucomplete(void) void acceptandmenucomplete(void) { - int sl = suffixlen[' ']; - if (!menucmp) { feep(); return; } - cs = menupos + menulen + menuinsc; - if (sl) - backdel(sl); - inststrlen(" ", 1, 1); - menuinsc = menulen = 0; - menupos = cs; - menuwe = 1; + if (brbeg && *brbeg) { + int l = (brscs >= 0 ? brscs : cs) - brpcs; + + zsfree(brbeg); + brbeg = (char *) zalloc(l + 2); + memcpy(brbeg, line + brpcs, l); + brbeg[l] = ','; + brbeg[l + 1] = '\0'; + } else { + int sl = suffixlen[' ']; + + cs = menupos + menulen + menuinsc; + if (sl) + backdel(sl); + + inststrlen(" ", 1, 1); + menuinsc = menulen = 0; + menupos = cs; + menuwe = 1; + } menucomplete(); } @@ -447,6 +447,10 @@ acceptandmenucomplete(void) static int lincmd, linredir; +/* The string for the redirection operator. */ + +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 * @@ -998,6 +1002,8 @@ get_comp_string(void) oins = ins; /* Get the next token. */ ctxtlex(); + if (inredir) + rdstr = tokstrings[tok]; if (tok == DINPAR) tokstr = NULL; @@ -1859,7 +1865,8 @@ pattern_match(Cpattern p, char *s, unsigned char *in, unsigned char *out) /* Do the matching for a prefix. */ static char * -match_pfx(char *l, char *w, Cline *nlp, int *lp, Cline *rlp, int *bplp) +match_pfx(char *l, char *w, Cline *nlp, int *lp, Cline *rlp, int *bplp, + Cmatcher nm) { static unsigned char *ea; static int ealen = 0; @@ -1867,61 +1874,27 @@ match_pfx(char *l, char *w, Cline *nlp, int *lp, Cline *rlp, int *bplp) static int rwlen; int ll = strlen(l), lw = strlen(w), mlw; - int il = 0, iw = 0, t, stil, stiw, std, bc = brpl; - char *nw = rw, *stl = NULL, *stw; + int il = 0, iw = 0, t, bc = brpl; + char *nw = rw; Cmlist ms; - Cmatcher mp, stm; + Cmatcher mp, lm = NULL; Cline lr = NULL; - *nlp = NULL; + if (nlp) { + *nlp = NULL; - if (ll > ealen) { - /* This is the `in'/`out' string for pattern matching. */ - if (ealen) - zfree(ea, ealen); - ea = (unsigned char *) zalloc(ealen = ll + 20); + if (ll > ealen) { + /* This is the `in'/`out' string for pattern matching. */ + if (ealen) + zfree(ea, ealen); + ea = (unsigned char *) zalloc(ealen = ll + 20); + } } while (ll && lw) { - if (*l == *w) { - /* Same character, take it. */ - - if (stl) { - /* But first check, if we were collecting characters * - * for a `*'. */ - int sl = iw - stiw; - - nw = addtoword(&rw, &rwlen, nw, stm, stl, stw, sl, 0); - - addtocline(nlp, &lr, stl, stm->llen, - stw, sl, stm, (std ? CLF_SUF : 0)); - - stl = NULL; - - if (bc <= 0 && bplp) { - *bplp = nw - rw; - bplp = NULL; - } - } - nw = addtoword(&rw, &rwlen, nw, NULL, NULL, l, 1, 0); - - addtocline(nlp, &lr, l, 1, NULL, 0, NULL, 0); - - l++; - w++; - il++; - iw++; - ll--; - lw--; - bc--; - - if (bc <= 0 && bplp) { - *bplp = nw - rw; - bplp = NULL; - } - continue; - } for (ms = mstack; ms; ms = ms->next) { for (mp = ms->matcher; mp; mp = mp->next) { + if (nm == mp || lm == mp) + continue; t = 1; /* Try to match the prefix, if any. */ if (mp->flags & CMF_LEFT) { @@ -1947,22 +1920,42 @@ match_pfx(char *l, char *w, Cline *nlp, int *lp, Cline *rlp, int *bplp) else t = 0; } - if (t && !stl) { - /* We simply keep the current position * - * and start collecting characters until * - * another matcher matches. */ - std = (mp->flags & CMF_LEFT); - stl = l; - stil = il; - stw = w; - stiw = iw; - stm = mp; - t = 0; - l += mp->llen; - il += mp->llen; - ll -= mp->llen; - - break; + 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; + + for (; k; i++, j++, k--, q++) { + if (match_pfx(p, q, NULL, NULL, + NULL, NULL, mp)) + break; + } + if (k) { + if (nlp) { + nw = addtoword(&rw, &rwlen, nw, mp, + l, w, i, 0); + addtocline(nlp, &lr, l, mp->llen, + w, i, mp, + ((mp->flags & CMF_LEFT) ? + CLF_SUF : 0)); + } + w = q; + iw = j; + lw = k; + l = p; + il = jj; + ll = kk; + bc -= i; + + if (bc <= 0 && bplp) { + *bplp = nw - rw; + bplp = NULL; + } + lm = mp; + break; + } + else + t = 0; } else t = 0; @@ -1988,26 +1981,10 @@ match_pfx(char *l, char *w, Cline *nlp, int *lp, Cline *rlp, int *bplp) if (t) { /* If it matched, build a new chunk on the Cline list * * and add the string to the built match. */ - if (stl) { - int sl = iw - stiw; - - nw = addtoword(&rw, &rwlen, nw, stm, stl, stw, sl, 0); - - addtocline(nlp, &lr, - stl, stm->llen, stw, sl, stm, - (std ? CLF_SUF : 0)); - - stl = NULL; - - if (bc <= 0 && bplp) { - *bplp = nw - rw; - bplp = NULL; - } + if (nlp) { + nw = addtoword(&rw, &rwlen, nw, mp, l, w, mlw, 0); + addtocline(nlp, &lr, l, mp->llen, w, mlw, mp, 0); } - nw = addtoword(&rw, &rwlen, nw, mp, l, w, mlw, 0); - - addtocline(nlp, &lr, l, mp->llen, w, mlw, mp, 0); - l += mp->llen; w += mlw; ll -= mp->llen; @@ -2023,62 +2000,84 @@ match_pfx(char *l, char *w, Cline *nlp, int *lp, Cline *rlp, int *bplp) break; } } - if (mp) + if (mp) { + if (mp != lm) + lm = NULL; break; + } } - if (!stl && !t) { - if (*nlp) { + if (t) + continue; + if (*l == *w) { + /* Same character, take it. */ + if (nlp) { + nw = addtoword(&rw, &rwlen, nw, NULL, NULL, l, 1, 0); + addtocline(nlp, &lr, l, 1, NULL, 0, NULL, 0); + } + l++; + w++; + il++; + iw++; + ll--; + lw--; + bc--; + + if (bc <= 0 && bplp) { + *bplp = nw - rw; + bplp = NULL; + } + lm = NULL; + } else { + if (nlp && *nlp) { lr->next = freecl; freecl = *nlp; } return NULL; } - if (stl) { - /* We are collecting characters, just skip over. */ - w++; - lw--; - iw++; - } } - *lp = iw; + if (lp) + *lp = iw; if (lw) { - /* There is a unmatched portion in the word, keep it. */ - if (rlp) { - w = dupstring(w); - addtocline(nlp, &lr, w, lw, w, -1, NULL, CLF_MID); - - *rlp = lr; - } else { - addtocline(nlp, &lr, l, 0, dupstring(w), lw, NULL, CLF_END); + if (nlp) { + /* There is a unmatched portion in the word, keep it. */ + if (rlp) { + w = dupstring(w); + addtocline(nlp, &lr, w, lw, w, -1, NULL, CLF_MID); - nw = addtoword(&rw, &rwlen, nw, NULL, NULL, w, lw, 0); + *rlp = lr; + } else { + addtocline(nlp, &lr, l, 0, dupstring(w), lw, NULL, CLF_END); + nw = addtoword(&rw, &rwlen, nw, NULL, NULL, w, lw, 0); + } } - } - else if (rlp) { - if (lr) { + } else if (rlp) { + if (nlp && lr) { lr->next = freecl; freecl = *nlp; } return NULL; } - if (nw) + if (nlp && nw) *nw = '\0'; if (ll) { - if (*nlp) { + if (nlp && *nlp) { lr->next = freecl; freecl = *nlp; } - return 0; + return NULL; } - /* Finally, return the built match string. */ - return dupstring(rw); + if (nlp) + /* Finally, return the built match string. */ + return dupstring(rw); + + return ((char *) 1); } /* Do the matching for a suffix. */ static char * -match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp) +match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp, Cmatcher nm) { static unsigned char *ea; static int ealen = 0; @@ -2086,60 +2085,29 @@ match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp) static int rwlen; int ll = strlen(l), lw = strlen(w), mlw; - int il = 0, iw = 0, t, stil, stiw, std, bc = brsl; - char *nw = rw, *stl = NULL, *stw; + int il = 0, iw = 0, t, bc = brsl; + char *nw = rw; Cmlist ms; - Cmatcher mp, stm; + Cmatcher mp, lm = NULL; Cline lr = NULL; l += ll; w += lw; - *nlp = NULL; + if (nlp) { + *nlp = NULL; - if (ll > ealen) { - if (ealen) - zfree(ea, ealen); - ea = (unsigned char *) zalloc(ealen = ll + 20); + if (ll > ealen) { + if (ealen) + zfree(ea, ealen); + ea = (unsigned char *) zalloc(ealen = ll + 20); + } } while (ll && lw) { - if (l[-1] == w[-1]) { - if (stl) { - int sl = iw - stiw; - - stl -= stm->llen; - stw -= sl; - nw = addtoword(&rw, &rwlen, nw, stm, stl, stw, sl, 1); - - addtocline(nlp, &lr, stl, stm->llen, - stw, sl, stm, (std ? CLF_SUF : 0)); - - stl = NULL; - - if (bc <= 0 && bslp) { - *bslp = nw - rw; - bslp = NULL; - } - } - nw = addtoword(&rw, &rwlen, nw, NULL, NULL, l - 1, 1, 1); - - addtocline(nlp, &lr, l - 1, 1, NULL, 0, NULL, 0); - - l--; - w--; - il++; - iw++; - ll--; - lw--; - bc--; - if (bc <= 0 && bslp) { - *bslp = nw - rw; - bslp = NULL; - } - continue; - } for (ms = mstack; ms; ms = ms->next) { for (mp = ms->matcher; mp; mp = mp->next) { + if (nm == mp || lm == mp) + continue; t = 1; if (mp->flags & CMF_RIGHT) { if (il < mp->ralen || iw < mp->ralen) @@ -2164,22 +2132,43 @@ match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp) else t = 0; } - if (t && !stl) { - std = (mp->flags & CMF_LEFT); - stl = l; - stil = il; - stw = w; - stiw = iw; - stm = mp; - t = 0; - l -= mp->llen; - il += mp->llen; - ll -= mp->llen; - - break; + 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; + + for (; k; i++, j++, k--, q--) + if (match_sfx(p, q, NULL, NULL, + NULL, mp)) + break; + if (k) { + if (nlp) { + nw = addtoword(&rw, &rwlen, nw, mp, + l - mp->llen, w - i, + i, 1); + addtocline(nlp, &lr, l - mp->llen, + mp->llen, w - i, i, mp, + ((mp->flags & CMF_LEFT) ? + CLF_SUF : 0)); + } + w = q; + iw = j; + lw = k; + l = p; + il = jj; + ll = kk; + bc -= i; + + if (bc <= 0 && bslp) { + *bslp = nw - rw; + bslp = NULL; + } + lm = mp; + break; + } + else + t = 0; } - else - t = 0; } } else { t = pattern_match(mp->line, l - mp->llen, NULL, ea) && @@ -2199,30 +2188,11 @@ match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp) t = 0; } if (t) { - if (stl) { - int sl = iw - stiw; - - stl -= stm->llen; - stw -= sl; - - nw = addtoword(&rw, &rwlen, nw, stm, stl, stw, sl, 1); - - addtocline(nlp, &lr, - stl, stm->llen, stw, sl, stm, - (std ? CLF_SUF : 0)); - - stl = NULL; - - if (bc <= 0 && bslp) { - *bslp = nw - rw; - bslp = NULL; - } + if (nlp) { + nw = addtoword(&rw, &rwlen, nw, mp, l, w, mlw, 1); + addtocline(nlp, &lr, l - mp->llen, mp->llen, + w - mlw, mlw, mp, 0); } - nw = addtoword(&rw, &rwlen, nw, mp, l, w, mlw, 1); - - addtocline(nlp, &lr, l - mp->llen, mp->llen, - w - mlw, mlw, mp, 0); - l -= mp->llen; w -= mlw; ll -= mp->llen; @@ -2237,34 +2207,55 @@ match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp) break; } } - if (mp) + if (mp) { + if (mp != lm) + lm = NULL; break; + } } - if (!stl && !t) { - if (*nlp) { + if (t) + continue; + if (l[-1] == w[-1]) { + if (nlp) { + nw = addtoword(&rw, &rwlen, nw, NULL, NULL, l - 1, 1, 1); + addtocline(nlp, &lr, l - 1, 1, NULL, 0, NULL, 0); + } + l--; + w--; + il++; + iw++; + ll--; + lw--; + bc--; + if (bc <= 0 && bslp) { + *bslp = nw - rw; + bslp = NULL; + } + lm = NULL; + } else { + if (nlp && *nlp) { lr->next = freecl; freecl = *nlp; } return NULL; } - if (stl) { - w--; - lw--; - iw++; - } } - *lp = iw; - if (nw) + if (lp) + *lp = iw; + if (nlp && nw) *nw = '\0'; if (ll) { - if (*nlp) { + if (nlp && *nlp) { lr->next = freecl; freecl = *nlp; } - return 0; + return NULL; } - return dupstring(rw); + if (nlp) + return dupstring(rw); + + return ((char *) 1); } /* Check if the word `w' matches. */ @@ -2283,8 +2274,8 @@ comp_match(char *pfx, char *sfx, char *w, Cline *clp, int qu, int *bpl, int *bsl int sl; Cline sli, last; - if ((p = match_pfx(pfx, w, &pli, &pl, &last, bpl))) { - if ((s = match_sfx(sfx, w + pl, &sli, &sl, bsl))) { + if ((p = match_pfx(pfx, w, &pli, &pl, &last, bpl, NULL))) { + if ((s = match_sfx(sfx, w + pl, &sli, &sl, bsl, NULL))) { int pml, sml; last->llen -= sl; @@ -2305,7 +2296,7 @@ comp_match(char *pfx, char *sfx, char *w, Cline *clp, int qu, int *bpl, int *bsl } else return NULL; - } else if (!(r = match_pfx(pfx, w, &pli, &pl, NULL, bpl))) + } else if (!(r = match_pfx(pfx, w, &pli, &pl, NULL, bpl, NULL))) return NULL; if (lppre && *lppre) { @@ -2373,6 +2364,7 @@ instmatch(Cmatch m) if (brbeg && *brbeg) { cs = a + m->brpl + (m->pre ? strlen(m->pre) : 0); l = strlen(brbeg); + brpcs = cs; inststrlen(brbeg, 1, l); r += l; ocs += l; @@ -2385,12 +2377,13 @@ instmatch(Cmatch m) if (brend && *brend) { a = cs; cs -= m->brsl; - ocs = cs; + ocs = brscs = cs; l = strlen(brend); inststrlen(brend, 1, l); r += l; cs = a + l; - } + } else + brscs = -1; if (m->suf) { inststrlen(m->suf, 1, (l = strlen(m->suf))); r += l; @@ -2509,6 +2502,7 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, if (!ai->firstm) ai->firstm = cm; } + compnmatches = mnum; } LASTALLOC; } SWITCHBACKHEAPS; } @@ -3180,6 +3174,108 @@ docompletion(char *s, int lst, int incmd) } LASTALLOC; } +/* This calls the given function for new style completion. */ + +/**/ +static void +callcompfunc(char *s, char *fn) +{ + List list; + int lv = lastval; + + if ((list = getshfunc(fn)) != &dummy_list) { + LinkList args = newlinklist(); + char **p, *tmp; + int aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext; + + addlinknode(args, fn); + + zsfree(compcontext); + zsfree(compcommand); + compcommand = ""; + if (inwhat == IN_MATH) { + if (insubscr) { + compcontext = "subscript"; + compcommand = varname ? varname : ""; + } else + compcontext = "math"; + usea = 0; + } else if (lincmd) + compcontext = (insubscr ? "subscript" : "command"); + else if (linredir) { + compcontext = "redirect"; + if (rdstr) + compcommand = rdstr; + } else + switch (inwhat) { + case IN_ENV: + compcontext = "value"; + compcommand = varname; + usea = 0; + break; + case IN_COND: + compcontext = "condition"; + break; + default: + if (cmdstr) { + compcontext = "argument"; + compcommand = cmdstr; + } else { + compcontext = "value"; + if (clwords[0]) + compcommand = clwords[0]; + } + aadd = 1; + } + compcontext = ztrdup(compcontext); + tmp = quotename(compcommand, NULL, NULL, NULL); + untokenize(tmp); + compcommand = ztrdup(tmp); + if (usea && (!aadd || clwords[0])) + for (p = clwords + aadd; *p; p++) { + tmp = dupstring(*p); + untokenize(tmp); + addlinknode(args, tmp); + } + zsfree(compprefix); + zsfree(compsuffix); + if (unset(COMPLETEINWORD)) { + tmp = quotename(s, NULL, NULL, NULL); + untokenize(tmp); + compprefix = ztrdup(tmp); + compsuffix = ztrdup(""); + } else { + char *ss = s + offs, sav; + + tmp = quotename(s, &ss, NULL, NULL); + sav = *ss; + *ss = '\0'; + untokenize(tmp); + compprefix = ztrdup(tmp); + *ss = sav; + untokenize(ss); + compsuffix = ztrdup(ss); + } + zsfree(compiprefix); + compiprefix = ztrdup(""); + compcurrent = (usea ? (clwpos + 1 - aadd) : 1); + compnmatches = mnum; + incompfunc = 1; + startparamscope(); + makecompparamsptr(); + makezleparams(1); + sfcontext = SFC_CWIDGET; + NEWHEAPS(compheap) { + doshfunc(fn, list, args, 0, 1); + } OLDHEAPS; + sfcontext = osc; + endparamscope(); + lastcmd = 0; + incompfunc = icf; + } + lastval = lv; +} + /* The beginning and end of a word range to be used by -l. */ static int brange, erange; @@ -3232,98 +3328,10 @@ makecomplist(char *s, int incmd, int lst) ccused = newlinklist(); ccstack = newlinklist(); - if (compfunc) { - List list; - int lv = lastval; - - if ((list = getshfunc(compfunc)) != &dummy_list) { - LinkList args = newlinklist(); - char **p, *tmp; - int aadd = 0, usea = 1; - - addlinknode(args, compfunc); - - zsfree(compcontext); - zsfree(compcommand); - compcommand = ""; - if (inwhat == IN_MATH) { - if (insubscr) { - compcontext = "subscript"; - compcommand = varname ? varname : ""; - } else - compcontext = "math"; - usea = 0; - } else if (lincmd) - compcontext = (insubscr ? "subscript" : "command"); - else if (linredir) - compcontext = "redirect"; - else - switch (inwhat) { - case IN_ENV: - compcontext = "value"; - compcommand = varname; - usea = 0; - break; - case IN_COND: - compcontext = "condition"; - break; - default: - if (cmdstr) { - compcontext = "argument"; - compcommand = cmdstr; - } else { - compcontext = "value"; - if (clwords[0]) - compcommand = clwords[0]; - } - aadd = 1; - } - compcontext = ztrdup(compcontext); - tmp = quotename(compcommand, NULL, NULL, NULL); - untokenize(tmp); - compcommand = ztrdup(tmp); - if (usea && (!aadd || clwords[0])) - for (p = clwords + aadd; *p; p++) { - tmp = dupstring(*p); - untokenize(tmp); - addlinknode(args, tmp); - } - zsfree(compprefix); - zsfree(compsuffix); - if (unset(COMPLETEINWORD)) { - tmp = quotename(s, NULL, NULL, NULL); - untokenize(tmp); - compprefix = ztrdup(tmp); - compsuffix = ztrdup(""); - } else { - char *ss = s + offs, sav; - - tmp = quotename(s, &ss, NULL, NULL); - sav = *ss; - *ss = '\0'; - untokenize(tmp); - compprefix = ztrdup(tmp); - *ss = sav; - untokenize(ss); - compsuffix = ztrdup(ss); - } - zsfree(compiprefix); - compiprefix = ztrdup(""); - compcurrent = (usea ? (clwpos + 1 - aadd) : 1); - compnmatches = mnum; - incompfunc = 1; - startparamscope(); - makecompparamsptr(); - NEWHEAPS(compheap) { - doshfunc(compfunc, list, args, 0, 1); - } OLDHEAPS; - endparamscope(); - lastcmd = 9; - incompfunc = 0; - } - lastval = lv; - } else - makecomplistglobal(s, incmd, lst); + if (compfunc) + callcompfunc(s, compfunc); + else + makecomplistglobal(s, incmd, lst, 0); endcmgroup(NULL); @@ -3368,11 +3376,11 @@ ctokenize(char *p) if (*p == '\\') bslash = 1; else { - if (*p == '$') { + if (*p == '$' || *p == '=') { if (bslash) p[-1] = Bnull; else - *p = String; + *p = (*p == '$' ? String : Equals); } bslash = 0; } @@ -3431,22 +3439,75 @@ makecomplistcall(Compctl cc) } SWITCHBACKHEAPS; } +/* A simple counter to avoid endless recursion between old and new style * + * completion. */ + +static int cdepth = 0; + +#define MAX_CDEPTH 16 + +/**/ +void +makecomplistctl(int flags) +{ + if (cdepth == MAX_CDEPTH) + return; + + cdepth++; + SWITCHHEAPS(compheap) { + HEAPALLOC { + int ooffs = offs, lip, lp; + char *str = comp_str(&lip, &lp), *t; + char *os = cmdstr, **ow = clwords, **p, **q; + int on = clwnum, op = clwpos; + + clwnum = arrlen(pparams) + 1; + clwpos = compcurrent - 1; + cmdstr = ztrdup(compcommand); + clwords = (char **) zalloc((clwnum + 1) * sizeof(char *)); + clwords[0] = ztrdup(cmdstr); + for (p = pparams, q = clwords + 1; *p; p++, q++) { + t = dupstring(*p); + ctokenize(t); + remnulargs(t); + *q = ztrdup(t); + } + *q = NULL; + offs = lip + lp; + incompfunc = 2; + makecomplistglobal(str, + (!clwpos && !strcmp(compcontext, "command")), + COMP_COMPLETE, flags); + incompfunc = 1; + offs = ooffs; + compnmatches = mnum; + zsfree(cmdstr); + freearray(clwords); + cmdstr = os; + clwords = ow; + clwnum = on; + clwpos = op; + } LASTALLOC; + } SWITCHBACKHEAPS; + cdepth--; +} + /* This function gets the compctls for the given command line and * * adds all completions for them. */ /**/ static void -makecomplistglobal(char *os, int incmd, int lst) +makecomplistglobal(char *os, int incmd, int lst, int flags) { Compctl cc; char *s; - if (lst == COMP_WIDGET) { - cc = compwidget->u.cc; - } else if (inwhat == IN_ENV) + ccont = CC_CCCONT; + + if (inwhat == IN_ENV) { /* Default completion for parameter values. */ cc = &cc_default; - else if (inwhat == IN_MATH) { + } else if (inwhat == IN_MATH) { /* Parameter names inside mathematical expression. */ cc_dummy.mask = CC_PARAMS; cc = &cc_dummy; @@ -3469,16 +3530,17 @@ makecomplistglobal(char *os, int incmd, int lst) cc = &cc_default; else { /* Otherwise get the matches for the command. */ - makecomplistcmd(os, incmd); + makecomplistcmd(os, incmd, flags); cc = NULL; } if (cc) { /* First, use the -T compctl. */ - makecomplistcc(&cc_first, os, incmd); - - if (!(ccont & CC_CCCONT)) - return; + if (!(flags & CFN_FIRST)) { + makecomplistcc(&cc_first, os, incmd); + if (!(ccont & CC_CCCONT)) + return; + } makecomplistcc(cc, os, incmd); } } @@ -3487,18 +3549,19 @@ makecomplistglobal(char *os, int incmd, int lst) /**/ static void -makecomplistcmd(char *os, int incmd) +makecomplistcmd(char *os, int incmd, int flags) { Compctl cc; Compctlp ccp; char *s; /* First, use the -T compctl. */ - makecomplistcc(&cc_first, os, incmd); - - if (!(ccont & CC_CCCONT)) - return; + if (!(flags & CFN_FIRST)) { + makecomplistcc(&cc_first, os, incmd); + if (!(ccont & CC_CCCONT)) + return; + } /* Then search the pattern compctls, with the command name and the * * full pathname of the command. */ makecomplistpc(os, incmd); @@ -3526,9 +3589,11 @@ makecomplistcmd(char *os, int incmd) (cc = ccp->cc)) || ((s = dupstring(cmdstr)) && remlpaths(&s) && (ccp = (Compctlp) compctltab->getnode(compctltab, s)) && - (cc = ccp->cc))))) + (cc = ccp->cc))))) { + if (flags & CFN_DEFAULT) + return; cc = &cc_default; - + } makecomplistcc(cc, os, incmd); } @@ -3817,12 +3882,12 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) ccont |= (cc->mask2 & (CC_CCCONT | CC_DEFCONT | CC_PATCONT)); - if (!incompfunc && findnode(ccstack, cc)) + if (incompfunc != 1 && findnode(ccstack, cc)) return; addlinknode(ccstack, cc); - if (!incompfunc && allccs) { + if (incompfunc != 1 && allccs) { if (findnode(allccs, cc)) { uremnode(ccstack, firstnode(ccstack)); return; @@ -4430,45 +4495,50 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) /* Add user names. */ maketildelist(); if (cc->func) { - /* This handles the compctl -K flag. */ - List list; - char **r; - int lv = lastval; - - /* Get the function. */ - if ((list = getshfunc(cc->func)) != &dummy_list) { - /* We have it, so build a argument list. */ - LinkList args = newlinklist(); - int osc = sfcontext; - - addlinknode(args, cc->func); - - if (delit) { - p = dupstrpfx(os, ooffs); - untokenize(p); - addlinknode(args, p); - p = dupstring(os + ooffs); - untokenize(p); - addlinknode(args, p); - } else { - addlinknode(args, lpre); - addlinknode(args, lsuf); + if (cc->func[0] == ' ') + /* Temporary hack for access to new style completione. */ + callcompfunc(os, cc->func + 1); + else { + /* This handles the compctl -K flag. */ + List list; + char **r; + int lv = lastval; + + /* Get the function. */ + if ((list = getshfunc(cc->func)) != &dummy_list) { + /* We have it, so build a argument list. */ + LinkList args = newlinklist(); + int osc = sfcontext; + + addlinknode(args, cc->func); + + if (delit) { + p = dupstrpfx(os, ooffs); + untokenize(p); + addlinknode(args, p); + p = dupstring(os + ooffs); + untokenize(p); + addlinknode(args, p); + } else { + addlinknode(args, lpre); + addlinknode(args, lsuf); + } + + /* This flag allows us to use read -l and -c. */ + if (incompfunc != 1) + incompctlfunc = 1; + sfcontext = SFC_COMPLETE; + /* Call the function. */ + doshfunc(cc->func, list, args, 0, 1); + sfcontext = osc; + incompctlfunc = 0; + /* And get the result from the reply parameter. */ + if ((r = get_user_var("reply"))) + while (*r) + addmatch(*r++, NULL); } - - /* This flag allows us to use read -l and -c. */ - if (!incompfunc) - incompctlfunc = 1; - sfcontext = SFC_COMPLETE; - /* Call the function. */ - doshfunc(cc->func, list, args, 0, 1); - sfcontext = osc; - incompctlfunc = 0; - /* And get the result from the reply parameter. */ - if ((r = get_user_var("reply"))) - while (*r) - addmatch(*r++, NULL); + lastval = lv; } - lastval = lv; } if (cc->mask & (CC_JOBS | CC_RUNNING | CC_STOPPED)) { /* Get job names. */ @@ -4625,7 +4695,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) } /* No harm in allowing read -l and -c here, too */ - if (!incompfunc) + if (incompfunc != 1) incompctlfunc = 1; sfcontext = SFC_COMPLETE; doshfunc(cc->ylist, list, args, 0, 1); @@ -4692,7 +4762,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) clwords += brange; } /* Produce the matches. */ - makecomplistcmd(s, incmd); + makecomplistcmd(s, incmd, CFN_FIRST); /* And restore the things we changed. */ clwords = ow; @@ -5021,9 +5091,10 @@ permmatches(void) &nn, &nl); g->mcount = nn; g->lcount = nn - nl; - if (g->ylist) + if (g->ylist) { g->lcount = arrlen(g->ylist); - + smatches = 2; + } g->expls = (Cexpl *) makearray(g->lexpls, 0, &(g->ecount), NULL); g->ccount = 0; diff --git a/Src/builtin.c b/Src/builtin.c index f6941286d..ea1ac8ab9 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -50,7 +50,7 @@ static struct builtin builtins[] = BUILTIN("cd", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL), BUILTIN("chdir", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL), BUILTIN("continue", BINF_PSPECIAL, bin_break, 0, 1, BIN_CONTINUE, NULL, NULL), - BUILTIN("declare", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZafilrtux", NULL), + BUILTIN("declare", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRTUZafilrtux", NULL), BUILTIN("dirs", 0, bin_dirs, 0, -1, 0, "v", NULL), BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmr", NULL), BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL), @@ -60,7 +60,7 @@ static struct builtin builtins[] = BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmr", NULL), BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL), BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL), - BUILTIN("export", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "LRUZafilrtu", "x"), + BUILTIN("export", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "LRTUZafilrtu", "x"), BUILTIN("false", 0, bin_false, 0, -1, 0, NULL, NULL), BUILTIN("fc", BINF_FCOPTS, bin_fc, 0, -1, BIN_FC, "nlreIRWAdDfEim", NULL), BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL), @@ -78,7 +78,7 @@ static struct builtin builtins[] = BUILTIN("jobs", 0, bin_fg, 0, -1, BIN_JOBS, "dlpZrs", NULL), BUILTIN("kill", 0, bin_kill, 0, -1, 0, NULL, NULL), BUILTIN("let", 0, bin_let, 1, -1, 0, NULL, NULL), - BUILTIN("local", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZailrtu", NULL), + BUILTIN("local", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRTUZailrtu", NULL), BUILTIN("log", 0, bin_log, 0, 0, 0, NULL, NULL), BUILTIN("logout", 0, bin_break, 0, 1, BIN_LOGOUT, NULL, NULL), @@ -93,7 +93,7 @@ static struct builtin builtins[] = BUILTIN("pwd", 0, bin_pwd, 0, 0, 0, "rLP", NULL), BUILTIN("r", BINF_R, bin_fc, 0, -1, BIN_FC, "nrl", NULL), BUILTIN("read", 0, bin_read, 0, -1, 0, "rzu0123456789pkqecnAlE", NULL), - BUILTIN("readonly", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZafiltux", "r"), + BUILTIN("readonly", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRTUZafiltux", "r"), BUILTIN("rehash", 0, bin_hash, 0, 0, 0, "dfv", "r"), BUILTIN("return", BINF_PSPECIAL, bin_break, 0, 1, BIN_RETURN, NULL, NULL), BUILTIN("set", BINF_PSPECIAL, bin_set, 0, -1, 0, NULL, NULL), @@ -107,7 +107,7 @@ static struct builtin builtins[] = BUILTIN("trap", BINF_PSPECIAL, bin_trap, 0, -1, 0, NULL, NULL), BUILTIN("true", 0, bin_true, 0, -1, 0, NULL, NULL), BUILTIN("type", 0, bin_whence, 0, -1, 0, "ampfsw", "v"), - BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZafilrtuxm", NULL), + BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRTUZafilrtuxm", NULL), BUILTIN("umask", 0, bin_umask, 0, 1, 0, "S", NULL), BUILTIN("unalias", 0, bin_unhash, 1, -1, 0, "m", "a"), BUILTIN("unfunction", 0, bin_unhash, 1, -1, 0, "m", "f"), @@ -1468,11 +1468,11 @@ getasg(char *s) /* function to set a single parameter */ /**/ -int +Param typeset_single(char *cname, char *pname, Param pm, int func, - int on, int off, int roff, char *value) + int on, int off, int roff, char *value, Param altpm) { - int usepm, tc; + int usepm, tc, keeplocal = 0; /* use the existing pm? */ usepm = pm && !(pm->flags & PM_UNSET); @@ -1490,24 +1490,24 @@ typeset_single(char *cname, char *pname, Param pm, int func, locallevel != pm->level && func != BIN_EXPORT) usepm = 0; - /* attempting a type conversion? */ + /* 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_INTEGER|PM_HASHED|PM_ARRAY|PM_TIED)))) usepm = 0; if (tc && (pm->flags & PM_SPECIAL)) { zerrnam(cname, "%s: can't change type of a special parameter", pname, 0); - return 1; + return NULL; } if (usepm) { if (!on && !roff && !value) { paramtab->printnode((HashNode)pm, 0); - return 0; + return pm; } if ((pm->flags & PM_RESTRICTED && isset(RESTRICTED))) { zerrnam(cname, "%s: restricted", pname, 0); - return 1; + return pm; } if (PM_TYPE(pm->flags) == PM_ARRAY && (on & PM_UNIQUE) && !(pm->flags & PM_READONLY & ~off)) @@ -1530,9 +1530,9 @@ typeset_single(char *cname, char *pname, Param pm, int func, setsparam(pname, ztrdup(value)); } else if (value) { zwarnnam(cname, "can't assign new value for array %s", pname, 0); - return 1; + return NULL; } - return 0; + return pm; } /* @@ -1542,10 +1542,15 @@ typeset_single(char *cname, char *pname, Param pm, int func, * last case only, we need to delete the old parameter. */ if (tc) { - if (pm->flags & PM_READONLY) { - on |= ~off & PM_READONLY; - pm->flags &= ~PM_READONLY; - } + /* Maintain existing readonly/exported status... */ + on |= ~off & (PM_READONLY|PM_EXPORTED) & pm->flags; + /* ...but turn off existing readonly so we can delete it */ + pm->flags &= ~PM_READONLY; + /* + * If we're just changing the type, we should keep the + * variable at the current level of localness. + */ + keeplocal = pm->level; /* * Try to carry over a value, but not when changing from, * to, or between non-scalar types. @@ -1563,17 +1568,33 @@ typeset_single(char *cname, char *pname, Param pm, int func, pm = createparam(pname, on & ~PM_READONLY); DPUTS(!pm, "BUG: parameter not created"); pm->ct = auxlen; - if (func != BIN_EXPORT) + + if (altpm && PM_TYPE(pm->flags) == PM_SCALAR) { + /* + * It seems safer to set this here than in createparam(), + * to make sure we only ever use the colonarr functions + * when u.data is correctly set. + */ + pm->sets.cfn = colonarrsetfn; + pm->gets.cfn = colonarrgetfn; + pm->u.data = &altpm->u.arr; + } + + if (keeplocal) + pm->level = keeplocal; + else if (func != BIN_EXPORT) pm->level = locallevel; if (value && !(pm->flags & (PM_ARRAY|PM_HASHED))) setsparam(pname, ztrdup(value)); 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); - return 1; + /* the only safe thing to do here seems to be unset the param */ + unsetparam_pm(pm, 0, 1); + return NULL; } - return 0; + return pm; } /* declare, export, integer, local, readonly, typeset */ @@ -1585,7 +1606,7 @@ bin_typeset(char *name, char **argv, char *ops, int func) Param pm; Asgment asg; Comp com; - char *optstr = "aiALRZlurtxU"; + char *optstr = "aiALRZlurtxUT"; int on = 0, off = 0, roff, bit = PM_ARRAY; int i; int returnval = 0, printflags = 0; @@ -1619,6 +1640,9 @@ bin_typeset(char *name, char **argv, char *ops, int func) off |= PM_UPPER; if (on & PM_HASHED) off |= PM_ARRAY; + if (on & PM_TIED) + off |= PM_INTEGER | PM_ARRAY | PM_HASHED; + on &= ~off; /* Given no arguments, list whatever the options specify. */ @@ -1631,6 +1655,58 @@ bin_typeset(char *name, char **argv, char *ops, int func) return 0; } + if (on & PM_TIED) { + Param apm; + char *name1; + + if (ops['m']) { + zwarnnam(name, "incompatible options for -T", NULL, 0); + return 1; + } + on &= ~off; + if (!argv[1] || argv[2]) { + zwarnnam(name, "-T requires names of scalar and array", NULL, 0); + return 1; + } + + /* + * 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))) + 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, + (Param)paramtab->getnode(paramtab, + asg->name), + func, on, off, roff, asg->value, apm))) { + unsetparam_pm(apm, 1, 1); + return 1; + } + + pm->ename = name1; + apm->ename = ztrdup(asg->name); + + return 0; + } + if (off & PM_TIED) { + zerrnam(name, "use unset to remove tied variables", NULL, 0); + return 1; + } + /* With the -m option, treat arguments as glob patterns */ if (ops['m']) { MUSTUSEHEAP("typeset -m"); @@ -1664,8 +1740,8 @@ bin_typeset(char *name, char **argv, char *ops, int func) } for (pmnode = firstnode(pmlist); pmnode; incnode(pmnode)) { pm = (Param) getdata(pmnode); - if (typeset_single(name, pm->nam, pm, func, on, off, roff, - asg->value)) + if (!typeset_single(name, pm->nam, pm, func, on, off, roff, + asg->value, NULL)) returnval = 1; } } @@ -1680,9 +1756,9 @@ bin_typeset(char *name, char **argv, char *ops, int func) returnval = 1; continue; } - if (typeset_single(name, asg->name, - (Param)paramtab->getnode(paramtab, asg->name), - func, on, off, roff, asg->value)) + if (!typeset_single(name, asg->name, + (Param)paramtab->getnode(paramtab, asg->name), + func, on, off, roff, asg->value, NULL)) returnval = 1; } return returnval; diff --git a/Src/glob.c b/Src/glob.c index 6536e0f06..7a3839576 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -31,7 +31,42 @@ #include "glob.pro" /* flag for CSHNULLGLOB */ - + +typedef struct gmatch *Gmatch; + +struct gmatch { + char *name; + long size; + long atime; + long mtime; + long ctime; + long links; + long _size; + long _atime; + long _mtime; + long _ctime; + long _links; +}; + +#define GS_NAME 1 +#define GS_SIZE 2 +#define GS_ATIME 4 +#define GS_MTIME 8 +#define GS_CTIME 16 +#define GS_LINKS 32 + +#define GS_SHIFT 5 +#define GS__SIZE (GS_SIZE << GS_SHIFT) +#define GS__ATIME (GS_ATIME << GS_SHIFT) +#define GS__MTIME (GS_MTIME << GS_SHIFT) +#define GS__CTIME (GS_CTIME << GS_SHIFT) +#define GS__LINKS (GS_LINKS << GS_SHIFT) + +#define GS_DESC 2048 + +#define GS_NORMAL (GS_SIZE | GS_ATIME | GS_MTIME | GS_CTIME | GS_LINKS) +#define GS_LINKED (GS_NORMAL << GS_SHIFT) + /**/ int badcshglob; @@ -42,8 +77,8 @@ static int matchct; /* number of matches found */ static char *pathbuf; /* pathname buffer */ static int pathbufsz; /* size of pathbuf */ static int pathbufcwd; /* where did we chdir()'ed */ -static char **matchbuf; /* array of matches */ -static char **matchptr; /* &matchbuf[matchct] */ +static Gmatch matchbuf; /* array of matches */ +static Gmatch matchptr; /* &matchbuf[matchct] */ static char *colonmod; /* colon modifiers in qualifier list */ typedef struct stat *Statptr; /* This makes the Ultrix compiler happy. Go figure. */ @@ -81,6 +116,7 @@ static struct qual *quals; static int qualct, qualorct; static int range, amc, units; static int gf_nullglob, gf_markdirs, gf_noglobdots, gf_listtypes, gf_follow; +static int gf_sorts, gf_nsorts, gf_sortlist[11]; /* Prefix, suffix for doing zle trickery */ @@ -213,6 +249,7 @@ insert(char *s, int checked) if (!statted && statfullpath(s, &buf, 1)) return; + statted = 1; qo = quals; for (qn = qo; qn && qn->func;) { range = qn->range; @@ -237,19 +274,44 @@ insert(char *s, int checked) } qn = qn->next; } - } else if (!checked && statfullpath(s, NULL, 1)) - return; - + } else if (!checked) { + if (statfullpath(s, NULL, 1)) + return; + statted = 1; + } news = dyncat(pathbuf, news); if (colonmod) { /* Handle the remainder of the qualifer: e.g. (:r:s/foo/bar/). */ s = colonmod; modify(&news, &s); } - *matchptr++ = news; + if (!statted && (gf_sorts & GS_NORMAL)) { + statfullpath(s, &buf, 1); + statted = 1; + } + if (statted != 2 && (gf_sorts & GS_LINKED)) { + if (statted) { + if (!S_ISLNK(buf.st_mode) || statfullpath(s, &buf2, 0)) + memcpy(&buf2, &buf, sizeof(buf)); + } else if (statfullpath(s, &buf2, 0)) + statfullpath(s, &buf2, 1); + } + matchptr->name = news; + matchptr->size = buf.st_size; + matchptr->atime = buf.st_atime; + matchptr->mtime = buf.st_mtime; + matchptr->ctime = buf.st_ctime; + matchptr->links = buf.st_nlink; + matchptr->_size = buf2.st_size; + matchptr->_atime = buf2.st_atime; + matchptr->_mtime = buf2.st_mtime; + matchptr->_ctime = buf2.st_ctime; + matchptr->_links = buf2.st_nlink; + matchptr++; + if (++matchct == matchsz) { - matchbuf = (char **)realloc((char *)matchbuf, - sizeof(char **) * (matchsz *= 2)); + matchbuf = (Gmatch )realloc((char *)matchbuf, + sizeof(struct gmatch) * (matchsz *= 2)); matchptr = matchbuf + matchct; } @@ -944,21 +1006,144 @@ qgetnum(char **s) return v; } -/* get octal number after qualifier */ +/* get mode spec after qualifier */ /**/ static long -qgetoctnum(char **s) +qgetmodespec(char **s) { - long v = 0; + long yes = 0, no = 0, val, mask, t; + char *p = *s, c, how, end; - if (!idigit(**s)) { - zerr("octal number expected", NULL, 0); - return 0; + if ((c = *p) == '=' || c == Equals || c == '+' || c == '-' || + c == '?' || c == Quest || (c >= '0' && c <= '7')) { + end = 0; + c = 0; + } else { + end = (c == '<' ? '>' : + (c == '[' ? ']' : + (c == '{' ? '}' : + (c == Inang ? Outang : + (c == Inbrack ? Outbrack : + (c == Inbrace ? Outbrace : c)))))); + p++; } - while (**s >= '0' && **s <= '7') - v = v * 010 + *(*s)++ - '0'; - return v; + do { + mask = 0; + while (((c = *p) == 'u' || c == 'g' || c == 'o' || c == 'a') && end) { + switch (c) { + case 'o': mask |= 01007; break; + case 'g': mask |= 02070; break; + case 'u': mask |= 04700; break; + case 'a': mask |= 07777; break; + } + p++; + } + how = ((c == '+' || c == '-') ? c : '='); + if (c == '+' || c == '-' || c == '=' || c == Equals) + p++; + val = 0; + if (mask) { + while ((c = *p++) != ',' && c != end) { + switch (c) { + case 'x': val |= 00111; break; + case 'w': val |= 00222; break; + case 'r': val |= 00444; break; + case 's': val |= 06000; break; + case 't': val |= 01000; break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + t = ((long) c - '0'); + val |= t | (t << 3) | (t << 6); + break; + default: + zerr("invalid mode specification", NULL, 0); + return 0; + } + } + if (how == '=' || how == '+') { + yes |= val & mask; + val = ~val; + } + if (how == '=' || how == '-') + no |= val & mask; + } else { + t = 07777; + while ((c = *p) == '?' || c == Quest || + (c >= '0' && c <= '7')) { + if (c == '?' || c == Quest) { + t = (t << 3) | 7; + val <<= 3; + } else { + t <<= 3; + val = (val << 3) | ((long) c - '0'); + } + p++; + } + if (end && c != end && c != ',') { + zerr("invalid mode specification", NULL, 0); + return 0; + } + if (how == '=') { + yes = (yes & ~t) | val; + no = (no & ~t) | (~val & ~t); + } else if (how == '+') + yes |= val; + else + no |= val; + } + } while (end && c != end); + + *s = p; + return ((yes & 07777) | ((no & 07777) << 12)); +} + +static int +gmatchcmp(Gmatch a, Gmatch b) +{ + int i, *s; + long r; + + for (i = gf_nsorts, s = gf_sortlist; i; i--, s++) { + switch (*s & ~GS_DESC) { + case GS_NAME: + r = notstrcmp(&a->name, &b->name); + break; + case GS_SIZE: + r = b->size - a->size; + break; + case GS_ATIME: + r = a->atime - b->atime; + break; + case GS_MTIME: + r = a->mtime - b->mtime; + break; + case GS_CTIME: + r = a->ctime - b->ctime; + break; + case GS_LINKS: + r = b->links - a->links; + break; + case GS__SIZE: + r = b->_size - a->_size; + break; + case GS__ATIME: + r = a->_atime - b->_atime; + break; + case GS__MTIME: + r = a->_mtime - b->_mtime; + break; + case GS__CTIME: + r = a->_ctime - b->_ctime; + break; + case GS__LINKS: + r = b->_links - a->_links; + break; + } + if (r) + return (int) ((*s & GS_DESC) ? -r : r); + } + return 0; } /* Main entry point to the globbing code for filename globbing. * @@ -976,7 +1161,8 @@ glob(LinkList list, LinkNode np) Complist q; /* pattern after parsing */ char *ostr = (char *)getdata(np); /* the pattern before the parser */ /* chops it up */ - + int first = 0, last = -1; /* index of first/last match to */ + /* return */ MUSTUSEHEAP("glob"); if (unset(GLOBOPT) || !haswilds(ostr)) { untokenize(ostr); @@ -994,6 +1180,7 @@ glob(LinkList list, LinkNode np) gf_markdirs = isset(MARKDIRS); gf_listtypes = gf_follow = 0; gf_noglobdots = unset(GLOBDOTS); + gf_sorts = gf_nsorts = 0; /* Check for qualifiers */ if (isset(BAREGLOBQUAL) && str[sl - 1] == Outpar) { @@ -1246,10 +1433,9 @@ glob(LinkList list, LinkNode np) } break; case 'o': - /* Match octal mode of file exactly. * - * Currently undocumented. */ - func = qualeqflags; - data = qgetoctnum(&s); + /* Match modes with chmod-spec. */ + func = qualmodeflags; + data = qgetmodespec(&s); break; case 'M': /* Mark directories with a / */ @@ -1315,6 +1501,51 @@ glob(LinkList list, LinkNode np) data = qgetnum(&s); break; + case 'O': + { + int t; + + switch (*s) { + case 'n': t = GS_NAME; break; + case 'L': t = GS_SIZE; break; + case 'l': t = GS_LINKS; break; + case 'a': t = GS_ATIME; break; + case 'm': t = GS_MTIME; break; + case 'c': t = GS_CTIME; break; + default: + zerr("unknown sort specifier", NULL, 0); + return; + } + if ((sense & 2) && t != GS_NAME) + t <<= GS_SHIFT; + if (gf_sorts & t) { + zerr("doubled sort specifier", NULL, 0); + return; + } + gf_sorts |= t; + gf_sortlist[gf_nsorts++] = t | + ((sense & 1) ? GS_DESC : 0); + s++; + break; + } + case '[': + case Inbrack: + { + char *os = --s; + struct value v; + + v.isarr = SCANPM_WANTVALS; + v.pm = NULL; + v.b = -1; + v.inv = 0; + if (getindex(&s, &v) || s == os) { + zerr("invalid subscript", NULL, 0); + return; + } + first = v.a; + last = v.b; + break; + } default: zerr("unknown file attribute", NULL, 0); return; @@ -1353,10 +1584,14 @@ glob(LinkList list, LinkNode np) zerr("bad pattern: %s", ostr, 0); return; } - + if (!gf_nsorts) { + gf_sortlist[0] = gf_sorts = GS_NAME; + gf_nsorts = 1; + } /* Initialise receptacle for matched files, * * expanded by insert() where necessary. */ - matchptr = matchbuf = (char **)zalloc((matchsz = 16) * sizeof(char *)); + matchptr = matchbuf = (Gmatch)zalloc((matchsz = 16) * + sizeof(struct gmatch)); matchct = 0; /* The actual processing takes place here: matches go into * @@ -1375,18 +1610,32 @@ glob(LinkList list, LinkNode np) return; } else { /* treat as an ordinary string */ - untokenize(*matchptr++ = dupstring(ostr)); + untokenize(matchptr->name = dupstring(ostr)); + matchptr++; matchct = 1; } } /* Sort arguments in to lexical (and possibly numeric) order. * * This is reversed to facilitate insertion into the list. */ - qsort((void *) & matchbuf[0], matchct, sizeof(char *), - (int (*) _((const void *, const void *)))notstrcmp); - - matchptr = matchbuf; - while (matchct--) /* insert matches in the arg list */ - insertlinknode(list, node, *matchptr++); + qsort((void *) & matchbuf[0], matchct, sizeof(struct gmatch), + (int (*) _((const void *, const void *)))gmatchcmp); + + if (first < 0) + first += matchct; + if (last < 0) + last += matchct; + if (first < 0) + first = 0; + if (last >= matchct) + last = matchct - 1; + if (first <= last) { + matchptr = matchbuf + matchct - 1 - last; + last -= first; + while (last-- >= 0) { /* insert matches in the arg list */ + insertlinknode(list, node, matchptr->name); + matchptr++; + } + } free(matchbuf); } @@ -2918,13 +3167,15 @@ qualflags(struct stat *buf, long mod) return mode_to_octal(buf->st_mode) & mod; } -/* mode matches number supplied exactly */ +/* mode matches specification */ /**/ static int -qualeqflags(struct stat *buf, long mod) +qualmodeflags(struct stat *buf, long mod) { - return mode_to_octal(buf->st_mode) == mod; + long v = mode_to_octal(buf->st_mode), y = mod & 07777, n = mod >> 12; + + return ((v & y) == y && !(v & n)); } /* regular executable file? */ diff --git a/Src/init.c b/Src/init.c index 0c874eead..5e0a550dd 100644 --- a/Src/init.c +++ b/Src/init.c @@ -300,18 +300,61 @@ init_io(void) /* Make sure the tty is opened read/write. */ if (isatty(0)) { +#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) + 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 + * unable to open /dev/tty or /dev/pts/<terminal number here> + * because something in Sun's STREAMS modules doesn't like + * it. The open() call fails with EBUSY which is not even + * listed as a possibility in the open(2) man page. So we'll + * try to outsmart The Company. -- <dave@srce.hr> + * + * Presumably there's no harm trying this on any OS, given that + * isatty(0) worked but opening the tty didn't. Possibly we won't + * get the tty read/write, but it's the best we can do -- pws + * + * Try both stdin and stdout before trying /dev/tty. -- Bart + */ +#if defined(HAVE_FCNTL_H) && defined(F_GETFL) +#define rdwrtty(fd) ((fcntl(fd, F_GETFL) & O_RDWR) == O_RDWR) +#else +#define rdwrtty(fd) 1 +#endif + if (SHTTY == -1 && rdwrtty(0)) { + SHTTY = movefd(dup(0)); + } + } + if (SHTTY == -1 && isatty(1) && rdwrtty(1) && + (SHTTY = movefd(dup(1))) != -1) { + zsfree(ttystrname); + ttystrname = ztrdup(ttyname(1)); } if (SHTTY == -1 && (SHTTY = movefd(open("/dev/tty", O_RDWR | O_NOCTTY))) != -1) { zsfree(ttystrname); - ttystrname = ztrdup("/dev/tty"); + ttystrname = ztrdup(ttyname(SHTTY)); } if (SHTTY == -1) { zsfree(ttystrname); ttystrname = ztrdup(""); + } else if (!ttystrname) { + ttystrname = ztrdup("/dev/tty"); } /* We will only use zle if shell is interactive, * diff --git a/Src/lex.c b/Src/lex.c index b08dfed5b..7371243a7 100644 --- a/Src/lex.c +++ b/Src/lex.c @@ -109,7 +109,8 @@ int parend; /* text of puctuation tokens */ -static char *tokstrings[WHILE + 1] = { +/**/ +char *tokstrings[WHILE + 1] = { NULL, /* NULLTOK 0 */ ";", /* SEPER */ "\\n", /* NEWLIN */ @@ -120,7 +121,7 @@ static char *tokstrings[WHILE + 1] = { ")", /* OUTPAR */ "||", /* DBAR */ "&&", /* DAMPER */ - ")", /* OUTANG 10 */ + ">", /* OUTANG 10 */ ">|", /* OUTANGBANG */ ">>", /* DOUTANG */ ">>|", /* DOUTANGBANG */ diff --git a/Src/params.c b/Src/params.c index 3dc7e1a1b..f57413a2e 100644 --- a/Src/params.c +++ b/Src/params.c @@ -679,7 +679,7 @@ getarg(char **str, int *inv, Value v, int a2, long *w) Comp c; /* first parse any subscription flags */ - if (*s == '(' || *s == Inpar) { + if (v->pm && (*s == '(' || *s == Inpar)) { int escapes = 0; int waste; for (s++; *s != ')' && *s != Outpar && s != *str; s++) { @@ -765,7 +765,7 @@ getarg(char **str, int *inv, Value v, int a2, long *w) } else if (rev) { v->isarr |= SCANPM_WANTVALS; } - if (!down && PM_TYPE(v->pm->flags) == PM_HASHED) + if (!down && v->pm && PM_TYPE(v->pm->flags) == PM_HASHED) v->isarr &= ~SCANPM_MATCHMANY; *inv = ind; } @@ -785,7 +785,7 @@ getarg(char **str, int *inv, Value v, int a2, long *w) singsub(&s); if (!rev) { - if (PM_TYPE(v->pm->flags) == PM_HASHED) { + if (v->pm && PM_TYPE(v->pm->flags) == PM_HASHED) { HashTable ht = v->pm->gets.hfn(v->pm); if (!ht) { ht = newparamtable(17, v->pm->nam); @@ -1371,7 +1371,7 @@ setarrvalue(Value v, char **val) freearray(val); return; } - if (PM_TYPE(v->pm->flags) & ~(PM_ARRAY|PM_HASHED)) { + if (!(PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED))) { freearray(val); zerr("attempt to assign array value to non-array", NULL, 0); return; @@ -1501,7 +1501,7 @@ setsparam(char *s, char *val) if (!(v = getvalue(&s, 1))) createparam(t, PM_SCALAR); else if (PM_TYPE(v->pm->flags) == PM_ARRAY && - !(v->pm->flags & PM_SPECIAL) && unset(KSHARRAYS)) { + !(v->pm->flags & (PM_SPECIAL|PM_TIED)) && unset(KSHARRAYS)) { unsetparam(t); createparam(t, PM_SCALAR); v = NULL; @@ -1545,7 +1545,7 @@ setaparam(char *s, char **val) if (!(v = getvalue(&s, 1))) createparam(t, PM_ARRAY); else if (!(PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) && - !(v->pm->flags & PM_SPECIAL)) { + !(v->pm->flags & (PM_SPECIAL|PM_TIED))) { int uniq = v->pm->flags & PM_UNIQUE; unsetparam(t); createparam(t, PM_ARRAY | uniq); @@ -1662,26 +1662,36 @@ unsetparam_pm(Param pm, int altflag, int exp) unsetparam_pm(altpm, 1, exp); } - /* If this was a local variable, we need to keep the old * - * struct so that it is resurrected at the right level. * - * This is partly because when an array/scalar value is set * - * and the parameter used to be the other sort, unsetparam() * - * is called. Beyond that, there is an ambiguity: should * - * foo() { local bar; unset bar; } make the global bar * - * available or not? The following makes the answer "no". */ - if ((locallevel && locallevel >= pm->level) || (pm->flags & PM_SPECIAL)) + /* + * If this was a local variable, we need to keep the old + * struct so that it is resurrected at the right level. + * This is partly because when an array/scalar value is set + * and the parameter used to be the other sort, unsetparam() + * is called. Beyond that, there is an ambiguity: should + * foo() { local bar; unset bar; } make the global bar + * available or not? The following makes the answer "no". + * + * Some specials, such as those used in zle, still need removing + * from the parameter table; they have the PM_REMOVABLE flag. + */ + if ((locallevel && locallevel >= pm->level) || + (pm->flags & (PM_SPECIAL|PM_REMOVABLE)) == PM_SPECIAL) return; - paramtab->removenode(paramtab, pm->nam); /* remove parameter node from table */ + /* remove parameter node from table */ + paramtab->removenode(paramtab, pm->nam); if (pm->old) { oldpm = pm->old; paramtab->addnode(paramtab, oldpm->nam, oldpm); - if ((PM_TYPE(oldpm->flags) == PM_SCALAR) && oldpm->sets.cfn == strsetfn) + if ((PM_TYPE(oldpm->flags) == PM_SCALAR) && + oldpm->sets.cfn == strsetfn) adduserdir(oldpm->nam, oldpm->u.str, 0, 0); } - paramtab->freenode((HashNode) pm); /* free parameter node */ + /* Even removable specials shouldn't be deleted. */ + if (!(pm->flags & PM_SPECIAL)) + paramtab->freenode((HashNode) pm); /* free parameter node */ } /* Standard function to unset a parameter. This is mostly delegated to * @@ -1759,6 +1769,9 @@ arrsetfn(Param pm, char **x) if (pm->flags & PM_UNIQUE) uniqarray(x); pm->u.arr = x; + /* Arrays tied to colon-arrays may need to fix the environment */ + if (pm->ename && x) + arrfixenv(pm->ename, x); } /* Function to get value of an association parameter */ @@ -1950,7 +1963,8 @@ arrvarsetfn(Param pm, char **x) char * colonarrgetfn(Param pm) { - return zjoin(*(char ***)pm->u.data, ':'); + char ***dptr = (char ***)pm->u.data; + return *dptr ? zjoin(*dptr, ':') : ""; } /**/ @@ -1959,8 +1973,15 @@ colonarrsetfn(Param pm, char *x) { char ***dptr = (char ***)pm->u.data; - freearray(*dptr); - *dptr = x ? colonsplit(x, pm->flags & PM_UNIQUE) : mkarray(NULL); + /* + * If this is tied to a parameter (rather than internal) array, + * the array itself may be NULL. Otherwise, we have to make + * sure it doesn't ever get null. + */ + if (*dptr) + freearray(*dptr); + *dptr = x ? colonsplit(x, pm->flags & PM_UNIQUE) : + (pm->flags & PM_TIED) ? NULL : mkarray(NULL); if (pm->ename) arrfixenv(pm->nam, *dptr); zsfree(x); @@ -2399,7 +2420,7 @@ arrfixenv(char *s, char **t) MUSTUSEHEAP("arrfixenv"); if (t == path) cmdnamtab->emptytable(cmdnamtab); - u = zjoin(t, ':'); + u = t ? zjoin(t, ':') : ""; len_s = strlen(s); pm = (Param) paramtab->getnode(paramtab, s); for (ep = environ; *ep; ep++) @@ -2602,6 +2623,9 @@ freeparamnode(HashNode hn) if (delunset) pm->unsetfn(pm, 1); zsfree(pm->nam); + /* If this variable was tied by the user, ename was ztrdup'd */ + if (pm->flags & PM_TIED) + zsfree(pm->ename); zfree(pm, sizeof(struct param)); } diff --git a/Src/subst.c b/Src/subst.c index 5211ee0ee..b77dbd4a4 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -702,6 +702,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) int whichlen = 0; int chkset = 0; int vunset = 0; + int wantt = 0; int spbreak = isset(SHWORDSPLIT) && !ssub && !qt; char *val = NULL, **aval = NULL; unsigned int fwidth = 0; @@ -902,6 +903,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) hvals = SCANPM_WANTVALS; break; + case 't': + wantt = 1; + break; + default: flagerr: zerr("error in flags", NULL, 0); @@ -978,9 +983,47 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) *s = sav; v = (Value) NULL; } else { - if (!(v = fetchvalue(&s, (unset(KSHARRAYS) || inbrace) ? 1 : -1, + if (!(v = fetchvalue(&s, (wantt ? -1 : + ((unset(KSHARRAYS) || inbrace) ? 1 : -1)), hkeys|hvals))) vunset = 1; + + if (wantt) { + if (v) { + int f = v->pm->flags; + + switch (PM_TYPE(f)) { + case PM_SCALAR: val = "scalar"; break; + case PM_ARRAY: val = "array"; break; + case PM_INTEGER: val = "integer"; break; + case PM_HASHED: val = "association"; break; + } + val = dupstring(val); + if (f & PM_LEFT) + val = dyncat(val, "-left"); + if (f & PM_RIGHT_B) + val = dyncat(val, "-right_blanks"); + if (f & PM_RIGHT_Z) + val = dyncat(val, "-right_zeros"); + if (f & PM_LOWER) + val = dyncat(val, "-lower"); + if (f & PM_UPPER) + val = dyncat(val, "-upper"); + if (f & PM_READONLY) + val = dyncat(val, "-readonly"); + if (f & PM_TAGGED) + val = dyncat(val, "-tag"); + if (f & PM_EXPORTED) + val = dyncat(val, "-export"); + if (f & PM_UNIQUE) + val = dyncat(val, "-unique"); + vunset = 0; + } else + val = dupstring(""); + + v = NULL; + isarr = 0; + } } while (v || ((inbrace || (unset(KSHARRAYS) && vunset)) && isbrack(*s))) { if (!v) { diff --git a/Src/zsh.export b/Src/zsh.export index c85bfbad4..32c0e7d3c 100644 --- a/Src/zsh.export +++ b/Src/zsh.export @@ -214,6 +214,7 @@ tgoto tok tokenize tokstr +tokstrings tputs trashzleptr tricat diff --git a/Src/zsh.h b/Src/zsh.h index dabcd90c8..e23f9c895 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -780,6 +780,7 @@ struct shfunc { #define SFC_HOOK 2 /* one of the special functions */ #define SFC_WIDGET 3 /* user defined widget */ #define SFC_COMPLETE 4 /* called from completion code */ +#define SFC_CWIDGET 5 /* new style completion widget */ /* node in list of function call wrappers */ @@ -916,10 +917,12 @@ struct param { #define PM_TAGGED (1<<9) /* tagged */ #define PM_EXPORTED (1<<10) /* exported */ #define PM_UNIQUE (1<<11) /* remove duplicates */ -#define PM_SPECIAL (1<<12) /* special builtin parameter */ -#define PM_DONTIMPORT (1<<13) /* do not import this variable */ -#define PM_RESTRICTED (1<<14) /* cannot be changed in restricted mode */ -#define PM_UNSET (1<<15) /* has null value */ +#define PM_TIED (1<<12) /* array tied to colon-path or v.v. */ +#define PM_SPECIAL (1<<13) /* special builtin parameter */ +#define PM_DONTIMPORT (1<<14) /* do not import this variable */ +#define PM_RESTRICTED (1<<15) /* cannot be changed in restricted mode */ +#define PM_UNSET (1<<16) /* has null value */ +#define PM_REMOVABLE (1<<17) /* special can be removed from paramtab */ /* Flags for extracting elements of arrays and associative arrays */ #define SCANPM_WANTVALS (1<<0) |