diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/Modules/zftp.c | 4 | ||||
-rw-r--r-- | Src/Zle/comp.h | 72 | ||||
-rw-r--r-- | Src/Zle/comp1.c | 18 | ||||
-rw-r--r-- | Src/Zle/comp1.export | 3 | ||||
-rw-r--r-- | Src/Zle/compctl.c | 634 | ||||
-rw-r--r-- | Src/Zle/compctl.mdd | 4 | ||||
-rw-r--r-- | Src/Zle/zle_main.c | 2 | ||||
-rw-r--r-- | Src/Zle/zle_move.c | 2 | ||||
-rw-r--r-- | Src/Zle/zle_params.c | 11 | ||||
-rw-r--r-- | Src/Zle/zle_thingy.c | 2 | ||||
-rw-r--r-- | Src/Zle/zle_tricky.c | 4663 | ||||
-rw-r--r-- | Src/glob.c | 2 | ||||
-rw-r--r-- | Src/init.c | 24 | ||||
-rw-r--r-- | Src/options.c | 11 | ||||
-rw-r--r-- | Src/params.c | 2 | ||||
-rw-r--r-- | Src/subst.c | 6 | ||||
-rw-r--r-- | Src/utils.c | 6 | ||||
-rw-r--r-- | Src/zsh.h | 1 |
18 files changed, 2381 insertions, 3086 deletions
diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c index 413dd8f43..126aa061e 100644 --- a/Src/Modules/zftp.c +++ b/Src/Modules/zftp.c @@ -391,7 +391,7 @@ zfpipe() /**/ static void -zfunalarm() +zfunalarm(void) { if (oalremain) { /* @@ -670,7 +670,7 @@ zfgetline(char *ln, int lnsize, int tmout) /**/ static int -zfgetmsg() +zfgetmsg(void) { char line[256], *ptr, *verbose; int stopit, printing = 0, tmout; diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h index 1444197a3..42a647199 100644 --- a/Src/Zle/comp.h +++ b/Src/Zle/comp.h @@ -36,7 +36,6 @@ typedef struct patcomp *Patcomp; typedef struct cmatcher *Cmatcher; typedef struct cmlist *Cmlist; typedef struct cpattern *Cpattern; -typedef struct cline *Cline; /* node for compctl hash table (compctltab) */ @@ -203,6 +202,7 @@ struct cmatch { char *str; /* the match itself */ char *ipre; /* ignored prefix, has to be re-inserted */ char *ripre; /* ignored prefix, unquoted */ + char *isuf; /* ignored suffix */ char *ppre; /* the path prefix */ char *psuf; /* the path suffix */ char *prpre; /* path prefix for opendir */ @@ -255,28 +255,6 @@ struct cpattern { int equiv; /* if this is a {...} class */ }; - -struct cline { - Cline next; /* next chunk */ - char *line; /* string to insert if !word */ - int llen; /* length of line */ - char *word; /* prefered string to insert */ - int wlen; /* length of word */ - int flags; /* see CLF_* below */ - Cline prefix; /* prefix we've build for new parts */ - Cline suffix; /* suffix we've build for new parts */ -}; - -#define CLF_END 1 -#define CLF_MID 2 -#define CLF_MISS 4 -#define CLF_DIFF 8 -#define CLF_SUF 16 -#define CLF_PNEW 32 -#define CLF_SNEW 64 -#define CLF_VAR 128 -#define CLF_JOIN 256 - /* Flags for makecomplist*(). Things not to do. */ #define CFN_FIRST 1 @@ -296,27 +274,31 @@ struct cline { #define CP_PREFIX (1 << 2) #define CP_SUFFIX (1 << 3) #define CP_IPREFIX (1 << 4) -#define CP_COMPSTATE (1 << 5) - -#define CP_REALPARAMS 6 - -#define CP_NMATCHES (1 << 6) -#define CP_MATCHER (1 << 7) -#define CP_MATCHERSTR (1 << 8) -#define CP_MATCHERTOT (1 << 9) -#define CP_CONTEXT (1 << 10) -#define CP_PARAMETER (1 << 11) -#define CP_REDIRECT (1 << 12) -#define CP_QUOTE (1 << 13) -#define CP_QUOTING (1 << 14) -#define CP_RESTORE (1 << 15) -#define CP_LIST (1 << 16) -#define CP_FORCELIST (1 << 17) -#define CP_INSERT (1 << 18) -#define CP_EXACT (1 << 19) -#define CP_EXACTSTR (1 << 20) -#define CP_PATMATCH (1 << 21) - -#define CP_NUM 22 +#define CP_ISUFFIX (1 << 5) +#define CP_COMPSTATE (1 << 6) + +#define CP_REALPARAMS 7 + +#define CP_NMATCHES (1 << 7) +#define CP_MATCHER (1 << 8) +#define CP_MATCHERSTR (1 << 9) +#define CP_MATCHERTOT (1 << 10) +#define CP_CONTEXT (1 << 11) +#define CP_PARAMETER (1 << 12) +#define CP_REDIRECT (1 << 13) +#define CP_QUOTE (1 << 14) +#define CP_QUOTING (1 << 15) +#define CP_RESTORE (1 << 16) +#define CP_LIST (1 << 17) +#define CP_FORCELIST (1 << 18) +#define CP_INSERT (1 << 19) +#define CP_EXACT (1 << 20) +#define CP_EXACTSTR (1 << 21) +#define CP_PATMATCH (1 << 22) +#define CP_PATINSERT (1 << 23) +#define CP_UNAMBIG (1 << 24) +#define CP_UNAMBIGC (1 << 25) + +#define CP_NUM 26 #define CP_ALLMASK ((1 << CP_NUM) - 1) diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c index 29836fbac..904f66305 100644 --- a/Src/Zle/comp1.c +++ b/Src/Zle/comp1.c @@ -52,10 +52,10 @@ void (*comp_setunsetptr) _((int, int)); /* pointers to functions required by compctl and defined by zle */ /**/ -int (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char **)); +int (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char **)); /**/ -char *(*comp_strptr) _((int*, int*, int)); +char *(*comp_strptr) _((int *, int *, int)); /**/ int (*getcpatptr) _((char *, int, char *, int)); @@ -66,6 +66,9 @@ int (*makecomplistcallptr) _((Compctl)); /**/ int (*makecomplistctlptr) _((int)); +/**/ +char *(*unambig_dataptr) _((int *)); + /* Hash table for completion info for commands */ /**/ @@ -107,6 +110,7 @@ char **compwords, *compprefix, *compsuffix, *compiprefix, + *compisuffix, *compmatcherstr, *compcontext, *compparameter, @@ -119,7 +123,8 @@ char **compwords, *compinsert, *compexact, *compexactstr, - *comppatmatch; + *comppatmatch, + *comppatinsert; /**/ Param *comppms; @@ -430,10 +435,11 @@ setup_comp1(Module m) cc_first.mask2 = CC_CCCONT; comppms = NULL; compwords = NULL; - compprefix = compsuffix = compiprefix = compmatcherstr = + compprefix = compsuffix = compiprefix = compisuffix = compmatcherstr = compcontext = compparameter = compredirect = compquote = compquoting = comprestore = complist = compinsert = - compexact = compexactstr = comppatmatch = compforcelist = NULL; + compexact = compexactstr = comppatmatch = comppatinsert = + compforcelist = NULL; makecompparamsptr = NULL; comp_setunsetptr = NULL; return 0; @@ -466,6 +472,7 @@ finish_comp1(Module m) zsfree(compprefix); zsfree(compsuffix); zsfree(compiprefix); + zsfree(compisuffix); zsfree(compmatcherstr); zsfree(compcontext); zsfree(compparameter); @@ -479,6 +486,7 @@ finish_comp1(Module m) zsfree(compexact); zsfree(compexactstr); zsfree(comppatmatch); + zsfree(comppatinsert); return 0; } diff --git a/Src/Zle/comp1.export b/Src/Zle/comp1.export index 23d2d8dd2..1be9b6492 100644 --- a/Src/Zle/comp1.export +++ b/Src/Zle/comp1.export @@ -18,12 +18,14 @@ compexactstr compforcelist compinsert compiprefix +compisuffix complist compmatcher compmatcherstr compmatchertot compnmatches compparameter +comppatinsert comppatmatch comppms compprefix @@ -48,3 +50,4 @@ makecomplistctlptr makecompparamsptr patcomps rembslash +unambig_dataptr diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index df38dcc96..2ebe2d4a4 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -1406,7 +1406,7 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat) untokenize(p); quotedzputs(p, stdout); } else - quotedzputs(bslashquote(s, NULL, NULL, NULL, 0), stdout); + quotedzputs(bslashquote(s, NULL, 0), stdout); } /* loop through flags w/o args that are set, printing them if so */ @@ -1537,7 +1537,7 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat) char *p = dupstring(s); untokenize(p); - quotedzputs(bslashquote(p, NULL, NULL, NULL, 0), stdout); + quotedzputs(bslashquote(p, NULL, 0), stdout); } } putchar('\n'); @@ -1692,7 +1692,7 @@ static int bin_compadd(char *name, char **argv, char *ops, int func) { char *p, **sp, *e; - char *ipre = NULL, *ppre = NULL, *psuf = NULL, *prpre = NULL; + char *ipre = NULL, *isuf = NULL, *ppre = NULL, *psuf = NULL, *prpre = NULL; char *pre = NULL, *suf = NULL, *group = NULL, *m = NULL, *rs = NULL; char *ign = NULL, *rf = NULL, *expl = NULL; int f = 0, a = CAF_MATCH, dm; @@ -1753,6 +1753,10 @@ bin_compadd(char *name, char **argv, char *ops, int func) sp = &ipre; e = "string expected after -%c"; break; + case 'I': + sp = &isuf; + e = "string expected after -%c"; + break; case 'p': sp = &ppre; e = "string expected after -%c"; @@ -1821,13 +1825,286 @@ bin_compadd(char *name, char **argv, char *ops, int func) return 1; match = cpcmatcher(match); - a = addmatchesptr(ipre, ppre, psuf, prpre, pre, suf, group, + a = addmatchesptr(ipre, isuf, ppre, psuf, prpre, pre, suf, group, rs, rf, ign, f, a, match, expl, argv); freecmatcher(match); return a; } +#define CVT_RANGENUM 0 +#define CVT_RANGEPAT 1 +#define CVT_PRENUM 2 +#define CVT_PREPAT 3 +#define CVT_SUFNUM 4 +#define CVT_SUFPAT 5 + +static void +ignore_prefix(int l) +{ + char *tmp, sav = compprefix[l]; + + compprefix[l] = '\0'; + tmp = tricat(compiprefix, compprefix, ""); + zsfree(compiprefix); + compiprefix = tmp; + compprefix[l] = sav; + tmp = ztrdup(compprefix + l); + zsfree(compprefix); + compprefix = tmp; +} + +static void +ignore_suffix(int l) +{ + char *tmp, sav; + + l = strlen(compsuffix) - l; + tmp = tricat(compsuffix + l, compisuffix, ""); + zsfree(compisuffix); + compisuffix = tmp; + sav = compsuffix[l]; + compsuffix[l] = '\0'; + tmp = ztrdup(compsuffix); + compsuffix[l] = sav; + zsfree(compsuffix); + compsuffix = tmp; +} + +/**/ +static void +restrict_range(int b, int e) +{ + int i = e - b + 1; + char **p = (char **) zcalloc((i + 1) * sizeof(char *)), **q, **pp; + + for (q = p, pp = compwords + b; i; i--, q++, pp++) + *q = ztrdup(*pp); + freearray(compwords); + compwords = p; + compcurrent -= b; +} + +static int +do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod) +{ + switch (test) { + case CVT_RANGENUM: + { + int l = arrlen(compwords); + + if (na < 0) + na += l; + else + na--; + if (nb < 0) + nb += l; + else + nb--; + + if (compcurrent - 1 < na || compcurrent - 1 > nb) + return 0; + + restrict_range(na, nb); + return 1; + } + case CVT_RANGEPAT: + { + char **p; + int i, l = arrlen(compwords), t = 0, b = 0, e = l - 1; + Comp c; + + i = compcurrent - 1; + if (i < 0 || i >= l) + return 0; + + singsub(&sa); + c = parsereg(sa); + + for (i--, p = compwords + i; i >= 0; p--, i--) { + if (domatch(*p, c, 0)) { + b = i + 1; + t = 1; + break; + } + } + if (t && sb) { + int tt = 0; + + singsub(&sb); + c = parsereg(sb); + + for (i++, p = compwords + i; i < l; p++, i++) { + if (domatch(*p, c, 0)) { + e = i - 1; + tt = 1; + break; + } + } + if (tt && i < compcurrent) + t = 0; + } + if (e < b) + t = 0; + if (t) + restrict_range(b, e); + return t; + } + case CVT_PRENUM: + case CVT_SUFNUM: + if (!na) + return 1; + if (na > 0 && + strlen(test == CVT_PRENUM ? compprefix : compsuffix) >= na) { + if (mod) { + if (test == CVT_PRENUM) + ignore_prefix(na); + else + ignore_suffix(na); + return 1; + } + return 0; + } + case CVT_PREPAT: + case CVT_SUFPAT: + { + Comp c; + + if (!na) + return 0; + + if (!(c = parsereg(sa))) + return 0; + + if (test == CVT_PREPAT) { + int l, add; + char *p, sav; + + if (!(l = strlen(compprefix))) + return 0; + if (na < 0) { + p = compprefix + l; + na = -na; + add = -1; + } else { + p = compprefix + 1; + add = 1; + } + for (; l; l--, p += add) { + sav = *p; + *p = '\0'; + test = domatch(compprefix, c, 0); + *p = sav; + if (test && !--na) + break; + } + if (!l) + return 0; + + ignore_prefix(p - compprefix); + } else { + int l, ol, add; + char *p; + + if (!(ol = l = strlen(compsuffix))) + return 0; + if (na < 0) { + p = compsuffix; + na = -na; + add = 1; + } else { + p = compsuffix + l - 1; + add = -1; + } + for (; l; l--, p += add) + if (domatch(p, c, 0) && !--na) + break; + + if (!l) + return 0; + + ignore_suffix(ol - (p - compsuffix)); + } + return 1; + } + } + return 0; +} + +/**/ +static int +bin_compset(char *name, char **argv, char *ops, int func) +{ + int test = 0, na = 0, nb = 0; + char *sa = NULL, *sb = NULL; + + if (incompfunc != 1) { + zerrnam(name, "can only be called from completion function", NULL, 0); + return 1; + } + if (argv[0][0] != '-') { + zerrnam(name, "missing option", NULL, 0); + return 1; + } + switch (argv[0][1]) { + case 'n': test = CVT_RANGENUM; break; + case 'N': test = CVT_RANGEPAT; break; + case 'p': test = CVT_PRENUM; break; + case 'P': test = CVT_PREPAT; break; + case 's': test = CVT_SUFNUM; break; + case 'S': test = CVT_SUFPAT; break; + default: + zerrnam(name, "bad option -%c", NULL, argv[0][1]); + return 1; + } + if (argv[0][2]) { + sa = argv[0] + 2; + sb = argv[1]; + na = 2; + } else { + if (!(sa = argv[1])) { + zerrnam(name, "missing string for option -%c", NULL, argv[0][1]); + return 1; + } + sb = argv[2]; + na = 3; + } + if (((test == CVT_PRENUM || test == CVT_SUFNUM) ? !!sb : + (sb && argv[na]))) { + zerrnam(name, "too many arguments", NULL, 0); + return 1; + } + switch (test) { + case CVT_RANGENUM: + na = atoi(sa); + nb = (sb ? atoi(sb) : -1); + break; + case CVT_RANGEPAT: + tokenize(sa); + sa = rembslash(sa); + if (sb) { + tokenize(sb); + sb = rembslash(sb); + } + break; + case CVT_PRENUM: + case CVT_SUFNUM: + na = atoi(sa); + break; + case CVT_PREPAT: + case CVT_SUFPAT: + if (sb) { + na = atoi(sa); + sa = sb; + } else + na = -1; + tokenize(sa); + sa = rembslash(sa); + break; + } + return !do_comp_vars(test, na, sa, nb, sb, 1); +} + /**/ static int bin_compcall(char *name, char **argv, char *ops, int func) @@ -1843,36 +2120,40 @@ bin_compcall(char *name, char **argv, char *ops, int func) /* Definitions for the special parameters. Note that these have to match the * order of the CP_* bits in comp.h */ -#define VAR(X) ((void *) (&(X))) +#define VAL(X) ((void *) (&(X))) static struct compparam { char *name; int type; - void *var; + void *var, *set, *get; } compparams[] = { - { "words", PM_ARRAY, VAR(compwords) }, - { "CURRENT", PM_INTEGER, VAR(compcurrent) }, - { "PREFIX", PM_SCALAR, VAR(compprefix) }, - { "SUFFIX", PM_SCALAR, VAR(compsuffix) }, - { "IPREFIX", PM_SCALAR, VAR(compiprefix) }, - { NULL, 0, NULL }, - - { "nmatches", PM_INTEGER, VAR(compnmatches) }, - { "matcher", PM_INTEGER, VAR(compmatcher) }, - { "matcher_string", PM_SCALAR, VAR(compmatcherstr) }, - { "total_matchers", PM_INTEGER, VAR(compmatchertot) }, - { "context", PM_SCALAR, VAR(compcontext) }, - { "parameter", PM_SCALAR, VAR(compparameter) }, - { "redirect", PM_SCALAR, VAR(compredirect) }, - { "quote", PM_SCALAR, VAR(compquote) }, - { "quoting", PM_SCALAR, VAR(compquoting) }, - { "restore", PM_SCALAR, VAR(comprestore) }, - { "list", PM_SCALAR, VAR(complist) }, - { "force_list", PM_SCALAR, VAR(compforcelist) }, - { "insert", PM_SCALAR, VAR(compinsert) }, - { "exact", PM_SCALAR, VAR(compexact) }, - { "exact_string", PM_SCALAR, VAR(compexactstr) }, - { "pattern_match", PM_SCALAR, VAR(comppatmatch) }, - { NULL, 0, NULL } + { "words", PM_ARRAY, VAL(compwords), NULL, NULL }, + { "CURRENT", PM_INTEGER, VAL(compcurrent), NULL, NULL }, + { "PREFIX", PM_SCALAR, VAL(compprefix), NULL, NULL }, + { "SUFFIX", PM_SCALAR, VAL(compsuffix), NULL, NULL }, + { "IPREFIX", PM_SCALAR, VAL(compiprefix), NULL, NULL }, + { "ISUFFIX", PM_SCALAR, VAL(compisuffix), NULL, NULL }, + { NULL, 0, NULL, NULL, NULL }, + + { "nmatches", PM_INTEGER, VAL(compnmatches), NULL, NULL }, + { "matcher", PM_INTEGER, VAL(compmatcher), NULL, NULL }, + { "matcher_string", PM_SCALAR, VAL(compmatcherstr), NULL, NULL }, + { "total_matchers", PM_INTEGER, VAL(compmatchertot), NULL, NULL }, + { "context", PM_SCALAR, VAL(compcontext), NULL, NULL }, + { "parameter", PM_SCALAR, VAL(compparameter), NULL, NULL }, + { "redirect", PM_SCALAR, VAL(compredirect), NULL, NULL }, + { "quote", PM_SCALAR, VAL(compquote), NULL, NULL }, + { "quoting", PM_SCALAR, VAL(compquoting), NULL, NULL }, + { "restore", PM_SCALAR, VAL(comprestore), NULL, NULL }, + { "list", PM_SCALAR, VAL(complist), NULL, NULL }, + { "force_list", PM_SCALAR, VAL(compforcelist), NULL, NULL }, + { "insert", PM_SCALAR, VAL(compinsert), NULL, NULL }, + { "exact", PM_SCALAR, VAL(compexact), NULL, NULL }, + { "exact_string", PM_SCALAR, VAL(compexactstr), NULL, NULL }, + { "pattern_match", PM_SCALAR, VAL(comppatmatch), NULL, NULL }, + { "pattern_insert", PM_SCALAR, VAL(comppatinsert), NULL, NULL }, + { "unambiguous", PM_SCALAR | PM_READONLY, NULL, NULL, VAL(get_unambig) }, + { "unambiguous_cursor", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_unambig_curs) }, + { NULL, 0, NULL, NULL, NULL } }; #define COMPSTATENAME "compstate" @@ -1883,28 +2164,32 @@ addcompparams(struct compparam *cp) Param *pp = comppms + (cp - compparams); for (; cp->name; cp++, pp++) { - Param pm = createparam(cp->name, cp->type | PM_SPECIAL|PM_REMOVABLE); + 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 addcompparams"); *pp = pm; pm->level = locallevel; - pm->u.data = cp->var; - switch(PM_TYPE(cp->type)) { - case PM_SCALAR: - pm->sets.cfn = strvarsetfn; - pm->gets.cfn = strvargetfn; - break; - case PM_INTEGER: - pm->sets.ifn = intvarsetfn; - pm->gets.ifn = intvargetfn; - pm->ct = 10; - break; - case PM_ARRAY: - pm->sets.afn = arrvarsetfn; - pm->gets.afn = arrvargetfn; - break; + if ((pm->u.data = cp->var)) { + switch(PM_TYPE(cp->type)) { + case PM_SCALAR: + pm->sets.cfn = strvarsetfn; + pm->gets.cfn = strvargetfn; + break; + case PM_INTEGER: + pm->sets.ifn = intvarsetfn; + pm->gets.ifn = intvargetfn; + pm->ct = 10; + break; + case PM_ARRAY: + pm->sets.afn = arrvarsetfn; + pm->gets.afn = arrvargetfn; + break; + } + } else { + pm->sets.cfn = (void (*) _((Param, char *))) cp->set; + pm->gets.cfn = (char *(*) _((Param))) cp->get; } pm->unsetfn = compunsetfn; } @@ -1976,6 +2261,24 @@ set_compstate(Param pm, HashTable ht) } /**/ +static char * +get_unambig(Param pm) +{ + return unambig_dataptr(NULL); +} + +/**/ +static long +get_unambig_curs(Param pm) +{ + int c; + + unambig_dataptr(&c); + + return c; +} + +/**/ static void compunsetfn(Param pm, int exp) { @@ -2017,7 +2320,7 @@ comp_wrapper(List list, FuncWrap w, char *name) if (incompfunc != 1) return 1; else { - char *orest, *opre, *osuf, *oipre, **owords; + char *orest, *opre, *osuf, *oipre, *oisuf, **owords; long ocur; int unset = 0, m, sm; Param *pp; @@ -2034,6 +2337,7 @@ comp_wrapper(List list, FuncWrap w, char *name) opre = dupstring(compprefix); osuf = dupstring(compsuffix); oipre = dupstring(compiprefix); + oisuf = dupstring(compisuffix); HEAPALLOC { owords = arrdup(compwords); @@ -2049,6 +2353,8 @@ comp_wrapper(List list, FuncWrap w, char *name) compsuffix = ztrdup(osuf); zsfree(compiprefix); compiprefix = ztrdup(oipre); + zsfree(compisuffix); + compisuffix = ztrdup(oisuf); freearray(compwords); PERMALLOC { compwords = arrdup(owords); @@ -2068,22 +2374,6 @@ comp_wrapper(List list, FuncWrap w, char *name) } /**/ -static void -ignore_prefix(int l) -{ - char *o, sav = compprefix[l]; - - compprefix[l] = '\0'; - o = compiprefix; - compiprefix = tricat(o, compprefix, ""); - zsfree(o); - compprefix[l] = sav; - o = compprefix; - compprefix = ztrdup(o + l); - zsfree(o); -} - -/**/ static int comp_check(void) { @@ -2095,132 +2385,15 @@ comp_check(void) } /**/ -static void -restrict_range(int b, int e) -{ - int i = e - b + 1; - char **p = (char **) zcalloc((i + 1) * sizeof(char *)), **q, **pp; - - for (q = p, pp = compwords + b; i; i--, q++, pp++) - *q = ztrdup(*pp); - freearray(compwords); - compwords = p; - compcurrent -= b; -} - -/**/ -static int -cond_prefix(char **a, int id) -{ - if (comp_check()) - return strpfx(cond_str(a, 0), compprefix); - return 0; -} - -/**/ -static int -cond_iprefix(char **a, int id) -{ - if (comp_check()) { - char *s = cond_str(a, 0); - - if (strpfx(s, compprefix)) { - ignore_prefix(strlen(s)); - return 1; - } - } - return 0; -} - -/**/ -static int -cond_position(char **a, int id) -{ - if (comp_check()) { - int b = cond_val(a, 0), e = (a[1] ? cond_val(a, 1) : b); - int l = arrlen(compwords), t, i = compcurrent - 1; - - if (b > 0) - b--; - if (e > 0) - e--; - if (b < 0) - b += l; - if (e < 0) - e += l; - t = (b >= 0 && e >= 0 && i >= b && i <= e && b <= e); - - if (t && a[1]) { - if (b > l) - b = l; - if (e > l) - e = l; - restrict_range(b, e); - } - return t; - } - return 0; -} - -/**/ static int -cond_word(char **a, int id) +cond_psfix(char **a, int id) { if (comp_check()) { - int o = ((id & 2) ? compcurrent : 0) + cond_val(a, 0); - int l = arrlen(compwords); - char *s; - - if (o < 0) - o += l; - - o--; - if (o < 0 || o >= l) - return 0; - - s = compwords[o]; - return ((id & 1) ? cond_match(a, 1, s) : !strcmp(s, cond_str(a, 1))); - } - return 0; -} - -/**/ -static int -cond_strcl(char **a, int id) -{ - if (comp_check()) { - char *s; - int i, ipl; - - if (a[1]) { - s = cond_str(a, 1); - i = cond_val(a, 0); - } else { - s = cond_str(a, 0); - i = -1; - } - if (!getcpatptr) { - zerr("zle not loaded, zle condition not available", NULL, 0); - return 1; - } - i = getcpatptr(comp_strptr(&ipl, NULL, 1), i, s, id); - if (i != -1 && i >= ipl) { - ignore_prefix(i - ipl); - return 1; - } - } - return 0; -} - -/**/ -static int -cond_words(char **a, int id) -{ - if (comp_check()) { - int b = cond_val(a, 0), e = (a[1] ? cond_val(a, 1) : -1); - int l = arrlen(compwords); - - return (l >= b && l <= e); + if (a[1]) + return do_comp_vars(id, cond_val(a, 0), cond_str(a, 1), + 0, NULL, 0); + else + return do_comp_vars(id, -1, cond_str(a, 0), 0, NULL, 0); } return 0; } @@ -2229,100 +2402,23 @@ cond_words(char **a, int id) static int cond_range(char **a, int id) { - if (comp_check()) { - char *s, **p; - int i, l = arrlen(compwords), t = 0, b = 0, e = l - 1; - Comp c = NULL; - - i = compcurrent - 1; - if (i < 0 || i >= l) - return 0; - - if (id & 1) { - s = a[0]; - singsub(&s); - c = parsereg(s); - } else - s = cond_str(a, 0); - - for (i--, p = compwords + i; i >= 0; p--, i--) { - if (((id & 1) ? domatch(*p, c, 0) : !strcmp(*p, s))) { - b = i + 1; - t = 1; - break; - } - } - if (t && (id & 2)) { - int tt = 0; - - if (id & 1) { - s = a[1]; - singsub(&s); - c = parsereg(s); - } else - s = cond_str(a, 1); - - for (i++, p = compwords + i; i < l; p++, i++) { - if (((id & 1) ? domatch(*p, c, 0) : !strcmp(*p, s))) { - e = i - 1; - tt = 1; - break; - } - } - if (tt && i < compcurrent) - t = 0; - } - if (e < b) - t = 0; - if (t) - restrict_range(b, e); - return t; - } - return 0; -} - -/**/ -static int -cond_nmatches(char **a, int id) -{ - if (comp_check()) - return compnmatches == cond_val(a, 0); - return 0; -} - -/**/ -static int -cond_matcher(char **a, int id) -{ - if (comp_check()) - return compmatcher == cond_val(a, 0); - return 0; + return do_comp_vars(CVT_RANGEPAT, 0, cond_str(a, 0), 0, + (id ? cond_str(a, 1) : NULL), 0); } static struct builtin bintab[] = { BUILTIN("compctl", 0, bin_compctl, 0, -1, 0, NULL, NULL), BUILTIN("compgen", 0, bin_compgen, 1, -1, 0, NULL, NULL), BUILTIN("compadd", 0, bin_compadd, 0, -1, 0, NULL, NULL), + BUILTIN("compset", 0, bin_compset, 1, 3, 0, NULL, NULL), BUILTIN("compcall", 0, bin_compcall, 0, 0, 0, "TD", NULL), }; static struct conddef cotab[] = { - CONDDEF("prefix", 0, cond_prefix, 1, 1, 0), - CONDDEF("iprefix", 0, cond_iprefix, 1, 1, 0), - CONDDEF("position", 0, cond_position, 1, 2, 0), - CONDDEF("word", 0, cond_word, 2, 2, 0), - CONDDEF("mword", 0, cond_word, 2, 2, 1), - CONDDEF("current", 0, cond_word, 2, 2, 2), - CONDDEF("mcurrent", 0, cond_word, 2, 2, 3), - CONDDEF("string", 0, cond_strcl, 1, 2, 0), - CONDDEF("class", 0, cond_strcl, 1, 2, 1), - CONDDEF("words", 0, cond_words, 1, 2, 0), - CONDDEF("between", 0, cond_range, 2, 2, 2), - CONDDEF("mbetween", 0, cond_range, 2, 2, 3), + CONDDEF("prefix", 0, cond_psfix, 1, 2, CVT_PREPAT), + CONDDEF("suffix", 0, cond_psfix, 1, 2, CVT_SUFPAT), + CONDDEF("between", 0, cond_range, 2, 2, 1), CONDDEF("after", 0, cond_range, 1, 1, 0), - CONDDEF("mafter", 0, cond_range, 1, 1, 1), - CONDDEF("nmatches", 0, cond_nmatches, 1, 1, 0), - CONDDEF("matcher", 0, cond_matcher, 1, 1, 0), }; static struct funcwrap wrapper[] = { diff --git a/Src/Zle/compctl.mdd b/Src/Zle/compctl.mdd index 48aabe38a..113eef27e 100644 --- a/Src/Zle/compctl.mdd +++ b/Src/Zle/compctl.mdd @@ -1,7 +1,7 @@ moddeps="comp1" -autobins="compctl complist compadd" +autobins="compctl complist compadd compset" -autoprefixconds="prefix iprefix position word mword current mcurrent string class words between mbetween after mafter nmatches" +autoprefixconds="prefix suffix between after" objects="compctl.o" diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 7ac4a7126..479994249 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -918,6 +918,7 @@ setup_zle(Module m) getcpatptr = getcpat; makecomplistcallptr = makecomplistcall; makecomplistctlptr = makecomplistctl; + unambig_dataptr = unambig_data; /* initialise the thingies */ init_thingies(); @@ -989,6 +990,7 @@ finish_zle(Module m) getcpatptr = NULL; makecomplistcallptr = NULL; makecomplistctlptr = NULL; + unambig_dataptr = NULL; return 0; } diff --git a/Src/Zle/zle_move.c b/Src/Zle/zle_move.c index 8ed4c657a..d6e9c4b7d 100644 --- a/Src/Zle/zle_move.c +++ b/Src/Zle/zle_move.c @@ -30,7 +30,7 @@ #include "zle.mdh" #include "zle_move.pro" -static vimarkcs[27], vimarkline[27]; +static int vimarkcs[27], vimarkline[27]; /**/ void diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c index 2a35ac416..adde116f2 100644 --- a/Src/Zle/zle_params.c +++ b/Src/Zle/zle_params.c @@ -67,7 +67,9 @@ static struct zleparam { zleunsetfn, NULL }, { "keys", PM_ARRAY | PM_READONLY, NULL, FN(get_keys), zleunsetfn, NULL }, - { "NUMERIC", PM_INTEGER | PM_READONLY, FN(set_numeric), FN(get_numeric), + { "NUMERIC", PM_INTEGER, FN(set_numeric), FN(get_numeric), + zleunsetfn, NULL }, + { "HISTNO", PM_INTEGER | PM_READONLY, NULL, FN(get_histno), zleunsetfn, NULL }, { NULL, 0, NULL, NULL, NULL, NULL } }; @@ -261,3 +263,10 @@ get_numeric(Param pm) { return zmult; } + +/**/ +static long +get_histno(Param pm) +{ + return histline; +} diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c index 28781e7f0..b879669ac 100644 --- a/Src/Zle/zle_thingy.c +++ b/Src/Zle/zle_thingy.c @@ -492,7 +492,7 @@ bin_zle_complete(char *name, char **args, char *ops, char func) t = rthingy(args[1]); cw = t->widget; unrefthingy(t); - if (!(cw->flags & ZLE_ISCOMP)) { + if (!cw || !(cw->flags & ZLE_ISCOMP)) { zerrnam(name, "invalid widget `%s'", args[1], 0); return 1; } diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index c303fd97d..4ae7495c3 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -143,7 +143,8 @@ static Comp patcomp, filecomp; * lppre/lpsuf -- the path prefix/suffix, unexpanded * * fpre/fsuf -- prefix/suffix of the pathname component the cursor is in * * prpre -- ppre in expanded form usable for opendir * - * ipre,ripre -- the ignored prefix (quotes and unquoted) * + * ipre,ripre -- the ignored prefix (quoted and unquoted) * + * isuf -- the ignored suffix * * * * The integer variables hold the lengths of lpre, lsuf, rpre, rsuf, * * fpre, fsuf, lppre, and lpsuf. noreal is non-zero if we have rpre/rsuf. */ @@ -153,6 +154,7 @@ static char *rpre, *rsuf; static char *ppre, *psuf, *lppre, *lpsuf, *prpre; static char *fpre, *fsuf; static char *ipre, *ripre; +static char *isuf; static int lpl, lsl, rpl, rsl, fpl, fsl, lppl, lpsl; static int noreal; @@ -177,6 +179,10 @@ static Cmgroup mgroup; static int mnum; +/* The match counter when unambig_data() was called. */ + +static int unambig_mnum; + /* Match flags for all matches in this group. */ static int mflags; @@ -215,6 +221,39 @@ static Cmlist bmatchers; static LinkList matchers; +/* Information about what to put on the line as the unambiguous string. + * The code always keeps lists of these structs up to date while + * matches are added (in the aminfo structs below). + * The lists have two levels: in the first one we have one struct per + * word-part, where parts are separated by the anchors of `*' patterns. + * These structs have pointers (in the prefix and suffix fields) to + * lists of cline structs describing the strings before or after the + * the anchor. */ + +typedef struct cline *Cline; +typedef struct clsub Clsub; + +struct cline { + Cline next; + int flags; + char *line; + int llen; + char *word; + int wlen; + char *orig; + int olen; + int slen; + Cline prefix, suffix; +}; + +#define CLF_MISS 1 +#define CLF_DIFF 2 +#define CLF_SUF 4 +#define CLF_MID 8 +#define CLF_NEW 16 +#define CLF_LINE 32 +#define CLF_JOIN 64 + /* A heap of free Cline structures. */ static Cline freecl; @@ -225,19 +264,11 @@ static Cline freecl; typedef struct aminfo *Aminfo; struct aminfo { - int cpl, csl, icpl, icsl; /* common prefix/suffix lengths */ - int minlen; /* minimum match length */ - int suflen; /* minimum suffix length */ Cmatch firstm; /* the first match */ - char *pprefix; /* common part of the -P prefixes */ - char *aprefix; /* common line prefix */ - int noipre; /* if the was no ignored prefix */ - char *iprefix; /* common ignored prefix */ - char *iaprefix; /* like aprefix, without ignored prefixes */ int exact; /* if there was an exact match */ Cmatch exactm; /* the exact match (if any) */ - Cline linecl, ilinecl; /* what to put on the line as a Cline */ int count; /* number of matches */ + Cline line; /* unambiguous line string */ }; static Aminfo ainfo, fainfo; @@ -489,7 +520,7 @@ acceptandmenucomplete(void) /* These are flags saying if we are completing in the command * * position, in a redirection, or in a parameter expansion. */ -static int lincmd, linredir, ispar; +static int lincmd, linredir, ispar, linwhat; /* The string for the redirection operator. */ @@ -516,7 +547,7 @@ int instring, inbackt; /* Convenience macro for calling bslashquote() (formerly quotename()). * * This uses the instring variable above. */ -#define quotename(s, e, te, pl) bslashquote(s, e, te, pl, instring) +#define quotename(s, e) bslashquote(s, e, instring) /* Check if the given string is the name of a parameter and if this * * parameter is one worth expanding. */ @@ -658,12 +689,12 @@ check_param(char *s, int set) mflags |= CMF_PARBR; /* Get the prefix (anything up to the character before the name). */ - lpsuf = dupstring(quotename(e, NULL, NULL, NULL)); + lpsuf = dupstring(quotename(e, NULL)); *e = '\0'; lpsl = strlen(lpsuf); ripre = dupstring(s); ripre[b - s] = '\0'; - ipre = dupstring(quotename(ripre, NULL, NULL, NULL)); + ipre = dupstring(quotename(ripre, NULL)); untokenize(ipre); } /* And adjust wb, we, and offs again. */ @@ -1008,7 +1039,7 @@ static char * dupstrspace(const char *str) { int len = strlen((char *)str); - char *t = (char *)ncalloc(len + 2); + char *t = (char *) ncalloc(len + 2); strcpy(t, str); strcpy(t+len, " "); return t; @@ -1572,7 +1603,7 @@ doexpansion(char *s, int lst, int olst, int explincmd) foredel(we - wb); while ((ss = (char *)ugetnode(vl))) { untokenize(ss); - ss = quotename(ss, NULL, NULL, NULL); + ss = quotename(ss, NULL); inststr(ss); #if 0 if (nonempty(vl)) { @@ -1604,99 +1635,6 @@ gotword(void) } } -/* This adds a string to the currently built match. The last argument * - * is non zero if we are building the suffix, where we have to prepend * - * the given string. */ - -static char * -addtoword(char **rwp, int *rwlenp, char *nw, - Cmatcher m, char *l, char *w, int wl, int prep) -{ - int al, rwlen = *rwlenp, nl; - char *as, *rw = *rwp; - - /* Get the string and length to insert: either from the line - * or from the match. */ - if (m && (m->flags & CMF_LINE)) { - al = m->llen; - as = l; - } else { - al = wl; - as = w; - } - /* Allocate some more space if needed. */ - if (!rwlen || (nl = al + (nw - rw)) >= rwlen) { - char *np; - - if (!rwlen) - nl = al + 20; - - np = (char *) zalloc(nl + 1); - - *rwlenp = nl; - if (rwlen) { - memcpy(np, rw, rwlen); - nw += np - rw; - zfree(rw, rwlen); - } else - nw = np; - *rwp = rw = np; - rwlen = nl; - } - /* Copy it in the buffer. */ - if (prep) { - memmove(rw + al, rw, rwlen - al); - memcpy(rw, as, al); - } else - memcpy(nw, as, al); - - return nw + al; -} - -/* This returns a new Cline structure. */ - -static Cline -getcline(char *l, int ll, char *w, int wl, int fl) -{ - Cline r; - - /* Preverably take it from the buffer list (freecl), if there - * is none, allocate a new one. */ - if ((r = freecl)) - freecl = r->next; - else - r = (Cline) zhalloc(sizeof(*r)); - - r->next = NULL; - r->line = l; - r->llen = ll; - r->word = w; - r->wlen = wl; - r->flags = fl; - r->prefix = r->suffix = NULL; - - return r; -} - -/* This adds a Cline structure with the given parameters to the list we - * are building during matching. */ - -static void -addtocline(Cline *retp, Cline *lrp, - char *l, int ll, char *w, int wl, Cmatcher m, int fl) -{ - Cline ln = getcline(l, ll, w, wl, fl); - - if (m && (m->flags & CMF_LINE)) - ln->word = NULL; - if (*retp) - (*lrp)->next = ln; - else - *retp = ln; - - *lrp = ln; -} - /* This compares two cpattern lists and returns non-zero if they are * equal. */ @@ -1774,18 +1712,119 @@ update_bmatchers(void) } } -/* When building up cline lists that are to be inserted at the end of the - * string or on the left hand side in the middle, we do this separately for - * multiple runs of characters separated by the anchors of `*' match patterns. - * This function builds such a list from the given string. */ +/* This returns a new Cline structure. */ + +static Cline +get_cline(char *l, int ll, char *w, int wl, char *o, int ol, int fl) +{ + Cline r; + + /* Preverably take it from the buffer list (freecl), if there + * is none, allocate a new one. */ + + if ((r = freecl)) + freecl = r->next; + else + r = (Cline) zhalloc(sizeof(*r)); + + r->next = NULL; + r->line = l; r->llen = ll; + r->word = w; r->wlen = wl; + r->orig = o; r->olen = ol; + r->slen = 0; + r->flags = fl; + r->prefix = r->suffix = NULL; + return r; +} + +/* This frees a cline list. */ + +static void +free_cline(Cline l) +{ + Cline n; + + while (l) { + n = l->next; + l->next = freecl; + freecl = l; + free_cline(l->prefix); + free_cline(l->suffix); + l = n; + } +} + +/* This reverts the order of the elements of the given cline list and + * returns a pointer to the new head. */ static Cline -end_list(int len, char *str) +revert_cline(Cline p) { - Cline ret = NULL, *q = &ret; + Cline r = NULL, n; + + while (p) { + n = p->next; + p->next = r; + r = p; + p = n; + } + return r; +} + +/* Check if the given pattern matches the given string. * + * `in' and `out' are used for {...} classes. In `out' we store the * + * character number that was matched. In the word pattern this is * + * given in `in' so that we can easily test if we found the * + * corresponding character. */ + +/**/ +static int +pattern_match(Cpattern p, char *s, unsigned char *in, unsigned char *out) +{ + unsigned char c; + + while (p) { + c = *((unsigned char *) s); + + if (out) + *out = 0; + + if (p->equiv) { + if (in) { + c = p->tab[c]; + if ((*in && *in != c) || (!*in && !c)) + return 0; + } else if (out) { + if (!(*out = p->tab[c])) + return 0; + } else if (!p->tab[c]) + return 0; + + if (in && *in) + in++; + if (out) + out++; + } else if (!p->tab[c]) + return 0; + + s++; + p = p->next; + } + return 1; +} + +/* This splits the given string into a list of cline structs, separated + * at those places where one of the anchors of an `*' pattern was found. + * plen gives the number of characters on the line that matched this + * string. In lp we return a pointer to the last cline struct we build. */ + +static Cline +bld_parts(char *str, int len, int plen, Cline *lp) +{ + Cline ret = NULL, *q = &ret, n; Cmlist ms; Cmatcher mp; - int t; + int t, op = plen; char *p = str; while (len) { @@ -1794,250 +1833,678 @@ end_list(int len, char *str) if (mp->flags == CMF_RIGHT && mp->wlen == -1 && !mp->llen && len >= mp->ralen && mp->ralen && pattern_match(mp->right, str, NULL, NULL)) { - /* This is one of those patterns, so add a cline struct. - * We store the anchor string in the line and the contents - * (i.e. the strings between the anchors) in the word field. */ - *q = getcline(str, mp->ralen, p, str - p, 0); - q = &((*q)->next); - str += mp->ralen; - len -= mp->ralen; + int olen = str - p, llen; + + /* We found an anchor, create a new cline. The NEW flag + * is set if the characters before the anchor were not + * on the line. */ + *q = n = get_cline(NULL, mp->ralen, str, mp->ralen, NULL, 0, + ((plen < 0) ? CLF_NEW : 0)); + + /* If there were any characters before the anchor, add + * them as a cline struct. */ + + if (p != str) { + llen = (op < 0 ? 0 : op); + + if (llen > olen) + llen = olen; + n->prefix = get_cline(NULL, llen, p, olen, NULL, 0, 0); + } + q = &(n->next); + str += mp->ralen; len -= mp->ralen; + plen -= mp->ralen; + op -= olen; p = str; t = 1; } } if (!t) { - str++; - len--; + /* No anchor was found here, skip. */ + str++; len--; + plen--; } } /* This is the cline struct for the remaining string at the end. */ + + *q = n = get_cline(NULL, 0, NULL, 0, NULL, 0, (plen < 0 ? CLF_NEW : 0)); if (p != str) { - *q = getcline("", 0, p, str - p, 0); - q = &((*q)->next); + int olen = str - p, llen = (op < 0 ? 0 : op); + + if (llen > olen) + llen = olen; + n->prefix = get_cline(NULL, llen, p, olen, NULL, 0, 0); } - *q = NULL; + n->next = NULL; + + if (lp) + *lp = n; return ret; } -/* This builds a string that may be put on the line that fully matches the - * given strings. The return value is NULL if no such string could be built - * or that string in local static memory, dup it. - * All this is a lot like the procedure in bld_new_pfx(), only slightly - * simpler, see that function for more comments. */ +/* Global variables used during matching: a char-buffer for the string to + * use for the match, and two cline lists for the two levels we use. */ -static char * -join_strs(int la, char *sa, int lb, char *sb) +static char *matchbuf = NULL; +static int matchbuflen = 0, matchbufadded; + +static Cline matchparts, matchlastpart; +static Cline matchsubs, matchlastsub; + +/* This initialises the variables above. */ + +static void +start_match(void) { - static unsigned char *ea = NULL; - static int ealen = 0; - static char *line = NULL; - static int llen = 0; - static char *rs = NULL; - static int rl = 0; + if (matchbuf) + *matchbuf = '\0'; + matchbufadded = 0; + matchparts = matchlastpart = matchsubs = matchlastsub = NULL; +} + +/* This aborts a matching, freeing the cline lists build. */ + +static void +abort_match(void) +{ + free_cline(matchparts); + free_cline(matchsubs); +} + +/* This adds a new string in the static char buffer. The arguments are + * the matcher used (if any), the strings from the line and the word + * and the length of the string from the word. The last argument is + * non-zero if we are matching a suffix (where the given string has to + * be prepended to the contents of the buffer). */ +static void +add_match_str(Cmatcher m, char *l, char *w, int wl, int sfx) +{ + /* Get the string and length to insert: either from the line + * or from the match. */ + if (m && (m->flags & CMF_LINE)) { + wl = m->llen; w = l; + } + if (wl) { + /* Probably resie the buffer. */ + if (matchbuflen - matchbufadded <= wl) { + int blen = matchbuflen + wl + 20; + char *buf; + + buf = (char *) zalloc(blen); + memcpy(buf, matchbuf, matchbuflen); + zfree(matchbuf, matchbuflen); + matchbuf = buf; + matchbuflen = blen; + } + /* Insert the string. */ + if (sfx) { + memmove(matchbuf + wl, matchbuf, matchbufadded + 1); + memcpy(matchbuf, w, wl); + } else + memcpy(matchbuf + matchbufadded, w, wl); + matchbufadded += wl; + matchbuf[matchbufadded] = '\0'; + } +} + +/* This adds a cline for a word-part during matching. Arguments are the + * matcher used, pointers to the line and word strings for the anchor, + * a pointer to the original line string for the whole part, the string + * before (or after) the anchor that has not yet been added, the length + * of the line-string for that, and a flag saying if we are matching a + * suffix. */ + +static void +add_match_part(Cmatcher m, char *l, char *w, int wl, + char *o, int ol, char *s, int sl, int osl, int sfx) +{ + Cline p, lp; + + /* If the anchors are equal, we keep only one. */ + + if (!strncmp(l, w, wl)) + l = NULL; + + /* Split the new part into parts and turn the last one into a `suffix' + * if we have a left anchor. */ + + p = bld_parts(s, sl, osl, &lp); + + p->flags &= ~CLF_NEW; + if (m && (m->flags & CMF_LEFT)) { + lp->flags |= CLF_SUF; + lp->suffix = lp->prefix; + lp->prefix = NULL; + } + /* cline lists for suffixes are sorted from back to front, so we have + * to revert the list we got. */ + if (sfx) + p = revert_cline(lp = p); + /* Now add the sub-clines we already had. */ + if (matchsubs) { + matchlastsub->next = p->prefix; + p->prefix = matchsubs; + matchsubs = matchlastsub = NULL; + } + /* Store the arguments in the last part-cline. */ + lp->line = l; lp->llen = wl; + lp->word = w; lp->wlen = wl; + lp->orig = o; lp->olen = ol; + lp->flags &= ~CLF_NEW; + + /* Finally, put the new parts on the list. */ + if (matchlastpart) + matchlastpart->next = p; + else + matchparts = p; + matchlastpart = lp; +} + +/* This adds a new sub-cline. Arguments are the matcher and the strings from + * the line and the word. */ + +static void +add_match_sub(Cmatcher m, char *l, int ll, char *w, int wl) +{ + int flags; + Cline n; + + /* Check if we are interested only in the string from the line. */ + if (m && (m->flags & CMF_LINE)) { + w = NULL; wl = 0; + flags = CLF_LINE; + } else + flags = 0; + + /* And add the cline. */ + if (wl || ll) { + n = get_cline(l, ll, w, wl, NULL, 0, flags); + if (matchlastsub) + matchlastsub->next = n; + else + matchsubs = n; + matchlastsub = n; + } +} + +/* This tests if the string from the line l matches the word w. In bp + * the offset for the brace is returned, in rwlp the length of the + * matched prefix or suffix, not including the stuff before or after + * the last anchor is given. When sfx is non-zero matching is done from + * the ends of the strings backward, if test is zero, the global variables + * above are used to build the string for the match and the cline. */ + +static int +match_str(char *l, char *w, int *bp, int *rwlp, int sfx, int test) +{ + int ll = strlen(l), lw = strlen(w), oll = ll, olw = lw; + int il = 0, iw = 0, t, ind, add, bc; + VARARR(unsigned char, ea, ll + 1); + char *ow; Cmlist ms; - Cmatcher mp; - int t, bl, rr = rl; - char *rp = rs; + Cmatcher mp, lm = NULL; + + if (!test) + start_match(); - /* This is a buffer for the characters to use for pairs of correspondence - * classes. */ - if (la + 1 > ealen || lb + 1 > ealen) { - if (ealen) - zfree(ea, ealen); - ea = (unsigned char *) zalloc(ealen = (la > lb ? la : lb) + 20); + /* Adjust the pointers and get the values for subscripting and + * incrementing. */ + + if (sfx) { + l += ll; w += lw; + ind = -1; add = -1; bc = brsl; + } else { + ind = 0; add = 1; bc = brpl; } - while (la && lb) { - if (*sa != *sb) { - for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) { - mp = ms->matcher; - if (!mp->flags && mp->wlen > 0 && mp->llen > 0 && - mp->wlen <= la && mp->wlen <= lb) { - if (pattern_match(mp->word, sa, NULL, ea)) { - if (mp->llen + 1 > llen) { - if (llen) - zfree(line, llen); - line = (char *) zalloc(llen = mp->llen + 20); - } - if ((bl = bld_line_pfx(mp->line, line, line, - lb, sb, ea))) { - line[mp->llen] = '\0'; - if (rr <= mp->llen) { - char *or = rs; + /* ow will always point to the beginning (or end) of that sub-string + * in w that wasn't put in the match-variables yet. */ - rs = realloc(rs, (rl += 20)); - rr += 20; - rp += rs - or; - } - memcpy(rp, line, mp->llen); - rp += mp->llen; - rr -= mp->llen; - sa += mp->wlen; - sb += bl; - la -= mp->wlen; - lb -= bl; - t = 1; + ow = w; + + /* If the brace is at the beginning, we have to treat it now. */ + + if (!test && !bc && bp) { + *bp = 0; + bp = NULL; + } + while (ll && lw) { + /* First try the matchers. */ + for (mp = NULL, ms = mstack; !mp && ms; ms = ms->next) { + for (mp = ms->matcher; mp; mp = mp->next) { + t = 1; + if (lm == mp || + ((oll == ll || olw == lw) && test && mp->wlen < 0)) + /* If we were called recursively, don't use `*' patterns + * at the beginning (avoiding infinite recursion). */ + continue; + + if (mp->wlen < 0) { + int both, loff, aoff, llen, alen, zoff, moff, ct, ict; + char *tp, savl = '\0', savw; + Cpattern ap; + + /* This is for `*' patterns, first initialise some + * local variables. */ + llen = mp->llen; + alen = (mp->flags & CMF_LEFT ? mp->lalen : mp->ralen); + + /* Give up if we don't have enough characters for the + * line-string and the anchor. */ + if (ll < llen + alen || lw < alen) + continue; + + if (mp->flags & CMF_LEFT) { + ap = mp->left; zoff = 0; moff = alen; + if (sfx) { + both = 0; loff = -llen; aoff = -(llen + alen); + } else { + both = 1; loff = alen; aoff = 0; } - } else if (pattern_match(mp->word, sb, NULL, ea)) { - if (mp->llen + 1 > llen) { - if (llen) - zfree(line, llen); - line = (char *) zalloc(llen = mp->llen + 20); + } else { + ap = mp->right; zoff = alen; moff = 0; + if (sfx) { + both = 1; loff = -(llen + alen); aoff = -alen; + } else { + both = 0; loff = 0; aoff = llen; } - if ((bl = bld_line_pfx(mp->line, line, line, - la, sa, ea))) { - line[mp->llen] = '\0'; - if (rr <= mp->llen) { - char *or = rs; + } + /* Try to match the line pattern and the anchor. */ + if (!pattern_match(mp->line, l + loff, NULL, NULL)) + continue; + if (ap) { + if (!pattern_match(ap, l + aoff, NULL, NULL) || + (both && !pattern_match(ap, w + aoff, NULL, NULL))) + continue; + } else if (!both || il || iw) + continue; - rs = realloc(rs, (rl += 20)); - rr += 20; - rp += rs - or; + /* Fine, now we call ourselves recursively to find the + * string matched by the `*'. */ + if (sfx) { + savl = l[-(llen + zoff)]; + l[-(llen + zoff)] = '\0'; + } + for (t = 0, tp = w, ct = 0, ict = lw - alen; + ict; + tp += add, ct++, ict--) { + if (both || + pattern_match(ap, tp - moff, NULL, NULL)) { + if (sfx) { + savw = tp[-zoff]; + tp[-zoff] = '\0'; + t = match_str(l - ll, w - lw, + NULL, NULL, 1, 1); + tp[-zoff] = savw; + } else + t = match_str(l + llen + moff, tp + moff, + NULL, NULL, 0, 1); + if (t || !both) + break; + } + } + ict = ct; + if (sfx) + l[-(llen + zoff)] = savl; + + /* Have we found a position in w where the rest of l + * matches? */ + if (!t) + continue; + + /* Yes, add the strings and clines if this is a + * top-level call. */ + if (!test) { + char *op, *lp, *map, *wap, *wmp; + int ol; + + if (sfx) { + op = w; ol = ow - w; lp = l - (llen + alen); + map = tp - alen; + if (mp->flags & CMF_LEFT) { + wap = tp - alen; wmp = tp; + } else { + wap = w - alen; wmp = tp - alen; } - memcpy(rp, line, mp->llen); - rp += mp->llen; - rr -= mp->llen; - sa += bl; - sb += mp->wlen; - la -= bl; - lb -= mp->wlen; - t = 1; + } else { + op = ow; ol = w - ow; lp = l; + map = ow; + if (mp->flags & CMF_LEFT) { + wap = w; wmp = w + alen; + } else { + wap = tp; wmp = ow; + } + } + /* If the matcher says that we are only interested + * in the line pattern, we just add that and the + * anchor and the string not added yet. Otherwise + * we add a new part. */ + if (mp->flags & CMF_LINE) { + add_match_str(NULL, NULL, op, ol, sfx); + add_match_str(NULL, NULL, lp, llen + alen, sfx); + add_match_sub(NULL, NULL, ol, op, ol); + add_match_sub(NULL, NULL, llen + alen, + lp, llen + alen); + } else { + add_match_str(NULL, NULL, + map, ct + ol + alen, sfx); + if (both) { + add_match_sub(NULL, NULL, ol, op, ol); + ol = -1; + } else + ct += ol; + add_match_part(mp, l + aoff, wap, alen, + l + loff, llen, wmp, ct, ol, sfx); } } + /* Now skip over the matched portion and the anchor. */ + llen += alen; alen += ict; + if (sfx) { + l -= llen; w -= alen; + } else { + l += llen; w += alen; + } + ll -= llen; il += llen; + lw -= alen; iw += alen; + bc -= llen; + + if (!test && bc <= 0 && bp) { + *bp = matchbufadded + bc; + bp = NULL; + } + ow = w; + + if (!ict) + lm = mp; + else + lm = NULL; + break; + } else if (ll >= mp->llen && lw >= mp->wlen) { + /* Non-`*'-pattern. */ + char *tl, *tw; + int tll, tlw, til, tiw; + + /* We do this only if the line- and word-substrings + * are not equal. */ + if (!(mp->flags & (CMF_LEFT | CMF_RIGHT)) && + mp->llen == mp->wlen && + !(sfx ? strncmp(l - mp->llen, w - mp->wlen, mp->llen) : + strncmp(l, w, mp->llen))) + continue; + + /* Using local variables to make the following + * independent of whether we match a prefix or a + * suffix. */ + if (sfx) { + tl = l - mp->llen; tw = w - mp->wlen; + til = ll - mp->llen; tiw = lw - mp->wlen; + tll = il + mp->llen; tlw = iw + mp->wlen; + } else { + tl = l; tw = w; + til = il; tiw = iw; + tll = ll; tlw = lw; + } + if (mp->flags & CMF_LEFT) { + /* Try to match the left anchor, if any. */ + if (til < mp->lalen || tiw < mp->lalen) + continue; + else if (mp->left) + t = pattern_match(mp->left, tl - mp->lalen, + NULL, NULL) && + pattern_match(mp->left, tw - mp->lalen, + NULL, NULL); + else + t = (!sfx && !il && !iw); + } + if (mp->flags & CMF_RIGHT) { + /* Try to match the right anchor, if any. */ + if (tll < mp->llen + mp->ralen || + tlw < mp->wlen + mp->ralen) + continue; + else if (mp->left) + t = pattern_match(mp->right, + tl + mp->llen - mp->ralen, + NULL, NULL) && + pattern_match(mp->right, + tw + mp->wlen - mp->ralen, + NULL, NULL); + else + t = (sfx && !il && !iw); + } + /* Now try to match the line and word patterns. */ + if (!t || + !pattern_match(mp->line, tl, NULL, ea) || + !pattern_match(mp->word, tw, ea, NULL)) + continue; + + /* Probably add the matched strings. */ + if (!test) { + if (sfx) + add_match_str(NULL, NULL, w, ow - w, 0); + else + add_match_str(NULL, NULL, ow, w - ow, 0); + add_match_str(mp, tl, tw, mp->wlen, 0); + if (sfx) + add_match_sub(NULL, NULL, 0, w, ow - w); + else + add_match_sub(NULL, NULL, 0, ow, w - ow); + + add_match_sub(mp, tl, mp->llen, tw, mp->wlen); + } + if (sfx) { + l = tl; w = tw; + } else { + l += mp->llen; w += mp->wlen; + } + il += mp->llen; iw += mp->wlen; + ll -= mp->llen; lw -= mp->wlen; + bc -= mp->llen; + + if (!test && bc <= 0 && bp) { + *bp = matchbufadded + bc; + bp = NULL; + } + ow = w; + lm = NULL; + break; } } - if (!t) - break; - } else { - if (rr <= 1) { - char *or = rs; + } + if (mp) + continue; - rs = realloc(rs, (rl += 20)); - rr += 20; - rp += rs - or; + if (l[ind] == w[ind]) { + /* No matcher could be used, but the strings have the same + * character here, skip over it. */ + l += add; w += add; + il++; iw++; + ll--; lw--; + bc--; + if (!test && bc <= 0 && bp) { + *bp = matchbufadded + (sfx ? (ow - w) : (w - ow)); + bp = NULL; } - *rp++ = *sa; - rr--; - sa++; - sb++; - la--; - lb--; + lm = NULL; + } else { + /* No matcher and different characters: l does not match w. */ + abort_match(); + + return (test ? 0 : -1); } } - if (la || lb) - return NULL; + /* If this is a recursive call, we just return if l matched w or not. */ + if (test) + return !ll; - *rp = '\0'; + /* In top-level calls, if ll is non-zero (unmatched portion in l), + * we have to free the collected clines. */ + if (ll) { + abort_match(); - return rs; + return -1; + } + if (rwlp) + *rwlp = iw - (sfx ? ow - w : w - ow); + + /* If we matched a suffix, the anchors stored in the top-clines + * will be in the wrong clines: shifted by one. Adjust this. */ + if (sfx && matchparts) { + Cline t, tn, s; + + if (matchparts->prefix || matchparts->suffix) { + t = get_cline(NULL, 0, NULL, 0, NULL, 0, 0); + t->next = matchparts; + if (matchparts->prefix) + t->prefix = (Cline) 1; + else + t->suffix = (Cline) 1; + matchparts = t; + } + for (t = matchparts; (tn = t->next); t = tn) { + s = (tn->prefix ? tn->prefix : tn->suffix); + if (t->prefix) + t->prefix = s; + else + t->suffix = s; + } + t->prefix = t->suffix = NULL; + } + /* Finally, return the number of matched characters. */ + + return iw; } -/* This gets two cline lists with separated runs and joins the corresponding - * elements in these lists. In olp and nlp we return the lengths of the matched - * portions in o and n respectively. As always the list in o is the one that - * contains the joined result after this function. */ +/* Check if the word w is matched by the strings in pfx and sfx (the prefix + * and the suffix from the line) or the pattern cp. In clp a cline list for + * w is returned. + * qu is non-zero if the words has to be quoted before processed any further. + * bpl and bsl are used to report the positions where the brace-strings in + * the prefix and the suffix have to be re-inserted if this match is inserted + * in the line. + * The return value is the string to use as a completion or NULL if the prefix + * and the suffix don't match the word w. */ -static Cline -join_ends(Cline o, Cline n, int *olp, int *nlp) +static char * +comp_match(char *pfx, char *sfx, char *w, Comp cp, + Cline *clp, int qu, int *bpl, int *bsl, int *exact) { - Cline ret = o; - int mol, mnl, smol = 0, smnl = 0; - char *j; + char *r = NULL; - while (o && n) { - if (o->llen == n->llen && !strncmp(o->line, n->line, o->llen)) { - /* The anchors are the same, so join the contents. */ - bld_pfx(o, n, &mol, &mnl); - smol += mol + o->llen; - smnl += mnl + n->llen; - } else if (!(o->flags & CLF_JOIN) && - (j = join_strs(o->llen, o->line, n->llen, n->line))) { - /* We could build a string matching both anchors, so use that - * and mark the cline so that we don't try to join it again. */ - o->flags |= CLF_JOIN; - o->llen = strlen(j); - o->line = dupstring(j); - bld_pfx(o, n, &mol, &mnl); - smol += mol + o->llen; - smnl += mnl + n->llen; - } else { - /* Different anchors, see if we can find matching anchors - * further down the lists. */ - Cline to, tn = NULL; - int t = 0; - - /* But first build the common prefix. */ - bld_pfx(o, n, &mol, &mnl); - smol += mol; - smnl += mnl; - - for (to = o; to && !t; to = to->next) { - for (tn = n; tn && !t; tn = tn->next) { - if ((t = ((to->llen == tn->llen && - !strncmp(to->line, tn->line, to->llen)) || - (!(to->flags & CLF_JOIN) && - join_strs(to->llen, to->line, - tn->llen, tn->line))))) - break; - } - if (t) - break; + if (cp) { + /* We have a globcomplete-like pattern, just use that. */ + int wl; + + r = w; + if (!domatch(r, cp, 0)) + return NULL; + + r = (qu ? quotename(r, NULL) : dupstring(r)); + + /* We still break it into parts here, trying to build a sensible + * cline list for these matches, too. */ + wl = strlen(w); + *clp = bld_parts(w, wl, wl, NULL); + *exact = 0; + } else { + Cline pli, plil; + int mpl, rpl, wl; + + if (qu) + w = quotename(w, NULL); + + wl = strlen(w); + + /* Always try to match the prefix. */ + + if ((mpl = match_str(pfx, w, bpl, &rpl, 0, 0)) < 0) + return NULL; + + if (sfx && *sfx) { + int wpl = matchbufadded, msl, rsl; + VARARR(char, wpfx, wpl); + Cline mli, mlil; + + /* We also have a suffix to match, so first save the + * contents of the global matching variables. */ + memcpy(wpfx, matchbuf, wpl); + if (matchsubs) { + Cline tmp = get_cline(NULL, 0, NULL, 0, NULL, 0, 0); + + tmp->prefix = matchsubs; + if (matchlastpart) + matchlastpart->next = tmp; + else + matchparts = tmp; } - if (t) { - /* Found matching anchors, continue with them. */ - o->line = to->line; - o->llen = to->llen; - o->next = to->next; - o->flags |= CLF_MISS; - n = tn; - } else { - /* No matching anchors found, shorten the list. */ - o->flags |= CLF_MISS; - o->next = NULL; - o->llen = 0; - if (olp) - *olp = smol; - if (nlp) - *nlp = smnl; - return ret; + pli = matchparts; + plil = matchlastpart; + + /* The try to match the suffix. */ + if ((msl = match_str(sfx, w + mpl, bsl, &rsl, 1, 0)) < 0) { + free_cline(pli); + + return NULL; + } + /* Matched, so add the string in the middle and the saved + * string for the prefix, and build a combined cline list + * for the prefix and the suffix. */ + if (matchsubs) { + Cline tmp = get_cline(NULL, 0, NULL, 0, NULL, 0, CLF_SUF); + + tmp->suffix = matchsubs; + if (matchlastpart) + matchlastpart->next = tmp; + else + matchparts = tmp; } + add_match_str(NULL, NULL, w + rpl, wl - rpl - rsl, 1); + add_match_str(NULL, NULL, wpfx, wpl, 1); + + mli = bld_parts(w + rpl, wl - rpl - rsl, (mpl - rpl), &mlil); + mlil->flags |= CLF_MID; + mlil->slen = msl - rsl; + mlil->next = revert_cline(matchparts); + + if (plil) + plil->next = mli; + else + pli = mli; + } else { + /* Only a prefix, add the string and a part-cline for it. */ + add_match_str(NULL, NULL, w + rpl, wl - rpl, 0); + + add_match_part(NULL, NULL, NULL, 0, NULL, 0, w + rpl, wl - rpl, + mpl - rpl, 0); + pli = matchparts; } - /* If we reached the end of the new list but not the end of the old - * list, we mark the old list (saying that characters are missing - * here). */ - if (!(n = n->next) && o->next) - o->flags |= CLF_MISS; - o = o->next; - } - if (o) { - /* Shorten the list if we haven't reached the end. */ - if (n) - o->flags |= CLF_MISS; - o->next = NULL; - o->llen = 0; + r = dupstring(matchbuf); + *clp = pli; + + /* Test if the string built is equal to the one from the line. */ + if (sfx && *sfx) { + int pl = strlen(pfx); + + *exact = (!strncmp(pfx, w, pl) && !strcmp(sfx, w + pl)); + } else + *exact = !strcmp(pfx, w); } - if (olp) - *olp = smol; - if (nlp) - *nlp = smnl; - return ret; + return r; } /* This builds all the possible line patterns for the pattern pat in the * buffer line. Initially line is the same as lp, but during recursive * calls lp is incremented for storing successive characters. Whenever * a full possible string is build, we test if this line matches the - * string given by wlen and word. The last argument contains the characters + * string given by wlen and word. The in argument contains the characters * to use for the correspondence classes, it was filled by a call to * pattern_match() in the calling function. * The return value is the length of the string matched in the word, it * is zero if we couldn't build a line that matches the word. */ -/**/ static int -bld_line_pfx(Cpattern pat, char *line, char *lp, - int wlen, char *word, unsigned char *in) +bld_line(Cpattern pat, char *line, char *lp, + char *word, int wlen, unsigned char *in, int sfx) { if (pat) { /* Still working on the pattern. */ @@ -2058,53 +2525,52 @@ bld_line_pfx(Cpattern pat, char *line, char *lp, *lp = i; /* We stored the character, now call ourselves to build * the rest. */ - if ((l = bld_line_pfx(pat->next, line, lp + 1, - wlen, word, in))) + if ((l = bld_line(pat->next, line, lp + 1, word, wlen, + in, sfx))) return l; } } else { /* We reached the end, i.e. the line string is fully build, now * see if it matches the given word. */ - static unsigned char *ea = NULL; - static int ealen = 0; Cmlist ms; Cmatcher mp; - int l = lp - line, t, rl = 0; + int l = lp - line, t, rl = 0, ind, add; + VARARR(unsigned char, ea, l + 1); /* Quick test if the strings are exactly the same. */ if (l == wlen && !strncmp(line, word, l)) return l; - /* We need another buffer for correspondence classes. */ - if (l + 1 > ealen) { - if (ealen) - zfree(ea, ealen); - ea = (unsigned char *) zalloc(ealen = l + 20); + if (sfx) { + line = lp; word += wlen; + ind = -1; add = -1; + } else { + ind = 0; add = 1; } /* We loop through the whole line string built. */ while (l && wlen) { - if (*word == *line) { + if (word[ind] == line[ind]) { /* The same character in both strings, skip over. */ - line++; - word++; - l--; - wlen--; - rl++; + line += add; word += add; + l--; wlen--; rl++; } else { t = 0; for (ms = bmatchers; ms && !t; ms = ms->next) { mp = ms->matcher; if (!mp->flags && mp->wlen <= wlen && mp->llen <= l && - pattern_match(mp->line, line, NULL, ea) && - pattern_match(mp->word, word, ea, NULL)) { + pattern_match(mp->line, (sfx ? line - mp->llen : line), + NULL, ea) && + pattern_match(mp->word, (sfx ? word - mp->wlen : word), + ea, NULL)) { /* Both the line and the word pattern matched, * now skip over the matched portions. */ - line += mp->llen; - word += mp->wlen; - l -= mp->llen; - wlen -= mp->wlen; - rl += mp->wlen; + if (sfx) { + line -= mp->llen; word -= mp->wlen; + } else { + line += mp->llen; word += mp->wlen; + } + l -= mp->llen; wlen -= mp->wlen; rl += mp->wlen; t = 1; } } @@ -2114,1916 +2580,822 @@ bld_line_pfx(Cpattern pat, char *line, char *lp, } } if (!l) - /* Unmatched portion in the line built, return no-match. */ + /* Unmatched portion in the line built, return matched length. */ return rl; } return 0; } -/* This builds a list of cline structs describing a string to insert in - * the line in a place where we didn't had something on the line when - * completion was invoked. This is called after we get the second match - * so we have two strings to start with given by (ol,ow) and (nl,nw) and - * the cline list returned describes a string that matches both of these - * strings. - * In olp and nlp we return the number of characters in ow and nw that - * are not matched by the cline list returned. Especially this means that - * they are non-zero if there are such unmatched portions. - * In lp we return a pointer to the last cline struct created. */ +/* This builds a string that may be put on the line that fully matches the + * given strings. The return value is NULL if no such string could be built + * or that string in local static memory, dup it. */ -static Cline -bld_new_pfx(int ol, char *ow, int nl, char *nw, int *olp, int *nlp, Cline *lp) +static char * +join_strs(int la, char *sa, int lb, char *sb) { - static unsigned char *ea = NULL; - static int ealen = 0; - static char *line = NULL; - static int llen = 0; + static char *rs = NULL; + static int rl = 0; + VARARR(unsigned char, ea, (la > lb ? la : lb) + 1); Cmlist ms; Cmatcher mp; - Cline ret = NULL, l = NULL, n; - char *p = ow; - int t, bl; - - /* This is a buffer for the characters to use for pairs of correspondence - * classes. */ - if (ol + 1 > ealen || nl + 1 > ealen) { - if (ealen) - zfree(ea, ealen); - ea = (unsigned char *) zalloc(ealen = (ol > nl ? ol : nl) + 20); - } - /* Loop through the strings. */ - while (ol && nl) { - if (*ow != *nw) { - /* Not the same character, use the patterns. */ + int t, bl, rr = rl; + char *rp = rs; + + while (la && lb) { + if (*sa != *sb) { + /* Different characters, try the matchers. */ for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) { mp = ms->matcher; - /* We use only those patterns that match a non-empty - * string in both the line and the word, that match - * strings no longer than the string we still have - * to compare, that don't have anchors, and that don't - * use the line strings for insertion. */ if (!mp->flags && mp->wlen > 0 && mp->llen > 0 && - mp->wlen <= ol && mp->wlen <= nl) { - /* Try the pattern only if the word-pattern matches - * one of the strings. */ - if (pattern_match(mp->word, ow, NULL, ea)) { - /* Make the buffer where we build the possible - * line patterns big enough. */ - if (mp->llen + 1 > llen) { - if (llen) - zfree(line, llen); - line = (char *) zalloc(llen = mp->llen + 20); + mp->wlen <= la && mp->wlen <= lb) { + /* The pattern has no anchors and the word + * pattern fits, try it. */ + if ((t = pattern_match(mp->word, sa, NULL, ea)) || + pattern_match(mp->word, sb, NULL, ea)) { + /* It matched one of the strings, t says which one. */ + VARARR(char, line, mp->llen + 1); + char **ap, **bp; + int *alp, *blp; + + if (t) { + ap = &sa; alp = &la; + bp = &sb; blp = &lb; + } else { + ap = &sb; alp = &lb; + bp = &sa; blp = &la; } - /* Then build all the possible lines and see - * if one of them matches the othe string. */ - if ((bl = bld_line_pfx(mp->line, line, line, - nl, nw, ea))) { - /* Yep, one of the lines matched the other - * string. */ - if (p != ow) { - /* There is still a substring that is - * the same in both strings, so add - * a cline for it. */ - char sav = *ow; - - *ow = '\0'; - n = getcline(NULL, 0, dupstring(p), - ow - p, 0); - *ow = sav; - if (l) - l->next = n; - else - ret = n; - l = n; - } - /* Then we add the line string built. */ + /* Now try to build a string that matches the other + * string. */ + if ((bl = bld_line(mp->line, line, line, + *bp, *blp, ea, 0))) { + /* Found one, put it into the return string. */ line[mp->llen] = '\0'; - n = getcline(dupstring(line), mp->llen, - NULL, 0, CLF_DIFF); - if (l) - l->next = n; - else - ret = n; - l = n; - ow += mp->wlen; - nw += bl; - ol -= mp->wlen; - nl -= bl; - p = ow; - t = 1; - } - } else if (pattern_match(mp->word, nw, NULL, ea)) { - /* Now do the same for the other string. */ - if (mp->llen + 1 > llen) { - if (llen) - zfree(line, llen); - line = (char *) zalloc(llen = mp->llen + 20); - } - if ((bl = bld_line_pfx(mp->line, line, line, - ol, ow, ea))) { - if (p != ow) { - char sav = *ow; - - *ow = '\0'; - n = getcline(NULL, 0, dupstring(p), - ow - p, 0); - *ow = sav; - if (l) - l->next = n; - else - ret = n; - l = n; + if (rr <= mp->llen) { + char *or = rs; + + rs = realloc(rs, (rl += 20)); + rr += 20; + rp += rs - or; } - line[mp->llen] = '\0'; - n = getcline(dupstring(line), mp->llen, - NULL, 0, CLF_DIFF); - if (l) - l->next = n; - else - ret = n; - l = n; - ow += bl; - nw += mp->wlen; - ol -= bl; - nl -= mp->wlen; - p = ow; + memcpy(rp, line, mp->llen); + rp += mp->llen; rr -= mp->llen; + *ap += mp->wlen; *alp -= mp->wlen; + *bp += bl; *blp -= bl; t = 1; } } } } if (!t) - /* No pattern matched, so give up. */ break; } else { - /* Same character, skip over. */ - ow++; - nw++; - ol--; - nl--; - } - } - if (p != ow) { - /* There is a equal substring in both strings, build a cline - * for it. */ - char sav = *ow; - - *ow = '\0'; - n = getcline(NULL, 0, dupstring(p), ow - p, 0); - *ow = sav; - if (l) - l->next = n; - else - ret = n; - l = n; - } - if (l) - l->next = NULL; - else - ret = NULL; - - if (olp) - *olp = ol; - if (nlp) - *nlp = nl; - if (lp) - *lp = l; - - return ret; -} - -/* Given a cline list for an unmatched part of the string to insert in the - * line and a new match substring, modify the cline list so that it also - * matches this string. The cline list is shortened in the place where - * we can't build a cline matching the new string. - * However, the resulting cline list is returned. The string is described - * by len and word. In missp we return non-zero if the cline list returned - * had to be shortened (and hence doesn't fully match the strings it was - * built from anymore) or if it doesn't fully match the given string. - * This function checks the string left to right and thus is to be used - * for strings where we want a common prefix. */ + /* Same character, just take it. */ + if (rr <= 1) { + char *or = rs; -static Cline -join_new_pfx(Cline line, int len, char *word, int *missp) -{ - static unsigned char *ea = NULL; - static int ealen = 0; - - Cline ret = NULL, l = NULL, next; - int miss = 0; - - /* Walk through the list and the string. */ - while (line && len) { - next = line->next; - /* The line element is used in those places where a new line - * string was built. */ - if (line->line) { - Cmlist ms; - Cmatcher mp; - int ll = line->llen, t; - char *p = line->line; - - /* Make the buffer for the correspondence classes big enough. */ - if (line->llen + 1 > ealen) { - if (ealen) - zfree(ea, ealen); - ea = (unsigned char *) zalloc(ealen = line->llen + 20); - } - /* Check if the line string from the cline list matches the - * new string. */ - while (ll && len) { - if (*p == *word) { - p++; - word++; - ll--; - len--; - } else { - for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) { - mp = ms->matcher; - if (!mp->flags && mp->wlen > 0 && mp->llen > 0 && - mp->wlen <= len && mp->llen <= len && - pattern_match(mp->word, word, NULL, ea) && - pattern_match(mp->line, p, ea, NULL)) { - /* We have a matched substring, skip over. */ - p += mp->llen; - word += mp->wlen; - ll -= mp->llen; - len -= mp->wlen; - t = 1; - } - } - if (!t) - /* No match, give up. */ - break; - } - } - if (p == line->line) { - /* We couldn't match any character from the string in the - * cline, so shorten the list and don't even keep this - * struct. */ - miss = 1; - len = 0; - } else { - /* At least the beginning of the cline string can be used. */ - if (ll) { - /* But there is a portion of the string that can't be - * used, so we have to shorten the list. */ - miss = 1; - *p = '\0'; - line->llen -= ll; - len = 0; - } - line->next = NULL; - if (l) - l->next = line; - else - ret = line; - l = line; - } - } else { - /* The cline doesn't have a string built by reverse matching, - * so we have to work on the original substring in the cline - * and the new string. */ - if (line->wlen == len && !strncmp(line->word, word, len)) { - /* They are equal, accept and return. If there was - * another element in the list, shorten the list. */ - if (next) - miss = 1; - line->next = NULL; - if (l) - l->next = line; - else - ret = line; - l = line; - len = 0; - } else { - char sav = word[len]; - - /* Check if one is the prefix of the other one. */ - word[len] = '\0'; - if (strpfx(word, line->word)) { - word[len] = sav; - - line->word[len] = '\0'; - line->wlen = len; - miss = 1; - line->next = NULL; - if (l) - l->next = line; - else - ret = line; - l = line; - len = 0; - } else if (strpfx(line->word, word)) { - word[len] = sav; - - miss = 1; - line->next = NULL; - if (l) - l->next = line; - else - ret = line; - l = line; - len = 0; - } else { - /* Not the same and no prefix, so we try to build a - * new line string matching the string in the cline - * and the new string. */ - int mol, mnl; - Cline sl, send; - - word[len] = sav; - - if ((sl = bld_new_pfx(line->wlen, line->word, - len, word, &mol, &mnl, &send))) { - /* We could build such a string, use it in the - * cline structure. */ - if (l) - l->next = sl; - else - ret = sl; - l = sl; - if (!mol) { - send->next = next; - word += len - mnl; - len = mnl; - } else - len = 0; - l = send; - } else - len = 0; - } + rs = realloc(rs, (rl += 20)); + rr += 20; + rp += rs - or; } + *rp++ = *sa; rr--; + sa++; sb++; + la--; lb--; } - line = next; } - *missp = (line || len || miss); - - return ret; -} - -/* This function gets two cline structs for which we want to build a - * common prefix to put on the line. The result is placed in the cline - * struct given as first argument. - * In olp and nlp we return the matched lengths for o and n, respectively - * (but this is only guaranteed to give correct results if this is the - * first call for the given o and n). */ - -/**/ -static void -bld_pfx(Cline o, Cline n, int *olp, int *nlp) -{ - if (olp) - *olp = 0; - if (nlp) - *nlp = 0; - if (o->flags & CLF_PNEW) { - if (o->flags & (CLF_END | CLF_MID)) - /* We split the suffix in the middle and at the end into - * separate runs. */ - o->prefix = join_ends(o->prefix, end_list(n->wlen, n->word), - NULL, NULL); - else { - /* This flag is set if we already built a cline list for such - * a prefix. We join it with the string from the other cline - * struct. */ - int miss; - - o->prefix = join_new_pfx(o->prefix, n->wlen, n->word, &miss); - if (miss) - o->flags |= CLF_MISS; - } - } else if (o->flags & (CLF_END | CLF_MID)) { - o->flags |= CLF_PNEW; - o->prefix = join_ends(end_list(o->wlen, o->word), - end_list(n->wlen, n->word), olp, nlp); - } else if (o->wlen && n->wlen) { - /* We haven't built a cline list for it yet. */ - char so = o->word[o->wlen], sn = n->word[n->wlen]; - char *new = o->word; - int newl = o->wlen, mol, mnl; - - /* If one of the strings is a prefix of the other one, just keep - * that prefix. */ - o->word[o->wlen] = n->word[n->wlen] = '\0'; - if (strpfx(n->word, o->word)) { - new = dupstring(n->word); - newl = n->wlen; - if (olp) - *olp = *nlp = n->wlen; - } else if (strpfx(o->word, n->word)) { - if (olp) - *olp = *nlp = o->wlen; - } else { - /* Otherwise build a cline list describing a string that - * matches both strings from the original cline structs - * and thus can be put in the command line to represent - * them. This cline list is stored in o. */ - o->flags |= CLF_PNEW; - o->prefix = bld_new_pfx(o->wlen, o->word, n->wlen, n->word, - &mol, &mnl, NULL); - newl = 0; - new = ""; - if (mol || mnl) - o->flags |= CLF_MISS; - if (olp) { - *olp = o->wlen - mol; - *nlp = n->wlen - mnl; - } - } - o->word[o->wlen] = so; - n->word[n->wlen] = sn; + if (la || lb) + return NULL; - o->word = new; - o->wlen = newl; + *rp = '\0'; - if (!o->prefix && n->wlen != o->wlen) - o->flags |= CLF_MISS; - } else - o->wlen = 0; + return rs; } -/* The following function are like their counterparts above, only for - * the other direction. */ +/* This compares the anchors stored in two top-level clines. */ static int -bld_line_sfx(Cpattern pat, char *line, char *lp, - int wlen, char *word, unsigned char *in) +cmp_anchors(Cline o, Cline n, int join) { - if (pat) { - int i, l; - unsigned char c = 0; - - if (pat->equiv) - if ((c = *in)) - in++; - - for (i = 0; i < 256; i++) - if ((pat->equiv && c) ? (c == pat->tab[i]) : pat->tab[i]) { - *lp = i; - if ((l = bld_line_pfx(pat->next, line, lp + 1, - wlen, word, in))) - return l; - } - } else { - static unsigned char *ea = NULL; - static int ealen = 0; - - Cmlist ms; - Cmatcher mp; - int l = lp - line, t, rl = 0; - - if (l == wlen && !strncmp(line, word, l)) - return l; + int line = 0; + char *j; - line = lp; - word += wlen; - - if (l + 1 > ealen) { - if (ealen) - zfree(ea, ealen); - ea = (unsigned char *) zalloc(ealen = l + 20); + /* First try the exact strings. */ + if ((!(o->flags & CLF_LINE) && o->wlen == n->wlen && + (!o->word || !strncmp(o->word, n->word, o->wlen))) || + (line = ((!o->line && !n->line) || + (o->llen == n->llen && o->line && n->line && + !strncmp(o->line, n->line, o->llen))))) { + if (line) { + o->flags |= CLF_LINE; + o->word = NULL; + n->wlen = 0; } - while (l && wlen) { - if (word[-1] == line[-1]) { - line--; - word--; - l--; - wlen--; - rl++; - } else { - t = 0; - for (ms = bmatchers; ms && !t; ms = ms->next) { - mp = ms->matcher; - if (!mp->flags && mp->wlen <= wlen && mp->llen <= l && - pattern_match(mp->line, line - mp->llen, - NULL, ea) && - pattern_match(mp->word, word - mp->wlen, - ea, NULL)) { - line -= mp->llen; - word -= mp->wlen; - l -= mp->llen; - wlen -= mp->wlen; - rl += mp->wlen; - t = 1; - } - } - if (!t) - return 0; - } - } - if (!l) - return rl; + return 1; + } + /* Didn't work, try to build a string matching both anchors. */ + if (join && !(o->flags & CLF_JOIN) && + (j = join_strs(o->wlen, o->word, n->wlen, n->word))) { + o->flags |= CLF_JOIN; + o->wlen = strlen(j); + o->word = dupstring(j); + + return 2; } return 0; } -static Cline -bld_new_sfx(int ol, char *ow, int nl, char *nw, int *olp, int *nlp, Cline *lp) -{ - static unsigned char *ea = NULL; - static int ealen = 0; - static char *line = NULL; - static int llen = 0; +/* Below is the code to join two cline lists. This struct is used to walk + * through a sub-list. */ - Cmlist ms; - Cmatcher mp; - Cline ret = NULL, l = NULL, n; - char *p; - int t, bl; - - ow += ol; - nw += nl; - p = ow; - - if (ol + 1 > ealen || nl + 1 > ealen) { - if (ealen) - zfree(ea, ealen); - ea = (unsigned char *) zalloc((ealen = (ol > nl ? ol : nl) + 20)); - } - while (ol && nl) { - if (ow[-1] != nw[-1]) { - for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) { - mp = ms->matcher; - if (!mp->flags && mp->wlen > 0 && mp->llen > 0 && - mp->wlen <= ol && mp->wlen <= nl) { - if (pattern_match(mp->word, ow - mp->wlen, - NULL, ea)) { - if (mp->llen + 1 > llen) { - if (llen) - zfree(line, llen); - line = (char *) zalloc(llen = mp->llen + 20); - } - if ((bl = bld_line_sfx(mp->line, line, line, - nl, nw, ea))) { - if (p != ow) { - char sav = *p; - - *p = '\0'; - n = getcline(NULL, 0, dupstring(ow), - p - ow, 0); - *p = sav; - if (l) - l->next = n; - else - ret = n; - l = n; - } - line[mp->llen] = '\0'; - n = getcline(dupstring(line), mp->llen, - NULL, 0, CLF_DIFF); - if (l) - l->next = n; - else - ret = n; - l = n; - ow -= mp->wlen; - nw -= bl; - ol -= mp->wlen; - nl -= bl; - p = ow; - t = 1; - } - } else if (pattern_match(mp->word, nw - mp->wlen, - NULL, ea)) { - if (mp->llen + 1 > llen) { - if (llen) - zfree(line, llen); - line = (char *) zalloc(llen = mp->llen + 20); - } - if ((bl = bld_line_sfx(mp->line, line, line, - ol, ow, ea))) { - if (p != ow) { - char sav = *p; - - *p = '\0'; - n = getcline(NULL, 0, dupstring(ow), - p - ow, 0); - *p = sav; - if (l) - l->next = n; - else - ret = n; - l = n; - } - line[mp->llen] = '\0'; - n = getcline(dupstring(line), mp->llen, - NULL, 0, CLF_DIFF); - if (l) - l->next = n; - else - ret = n; - l = n; - ow -= bl; - nw -= mp->wlen; - ol -= bl; - nl -= mp->wlen; - p = ow; - t = 1; - } - } - } - } - if (!t) - break; - } else { - ow--; - nw--; - ol--; - nl--; - } - } - if (p != ow) { - char sav = *p; - - *p = '\0'; - n = getcline(NULL, 0, dupstring(ow), p - ow, 0); - *p = sav; - if (l) - l->next = n; - else - ret = n; - l = n; - } - if (l) - l->next = NULL; - else - ret = NULL; +typedef struct cmdata *Cmdata; - if (olp) - *olp = ol; - if (nlp) - *nlp = nl; - if (lp) - *lp = l; +struct cmdata { + Cline cl, pcl; + char *str, *astr; + int len, alen, olen, line; +}; - return ret; -} +/* This is used to ensure that a cmdata struct contains usable data. + * The return value is non-zero if we reached the end. */ -static Cline -join_new_sfx(Cline line, int len, char *word, int *missp) +static int +check_cmdata(Cmdata md, int sfx) { - static unsigned char *ea = NULL; - static int ealen = 0; - - Cline ret = NULL, l = NULL, next; - int miss = 0, ind = 0; - - word += len; - - while (line && len) { - next = line->next; - if (line->line) { - Cmlist ms; - Cmatcher mp; - int ll = line->llen, t; - char *p = line->line + ll; - - if (line->llen + 1 > ealen) { - if (ealen) - zfree(ea, ealen); - ea = (unsigned char *) zalloc(ealen = line->llen + 20); - } - while (ll && len) { - if (p[-1] == word[-1]) { - p--; - word--; - ll--; - len--; - ind++; - } else { - for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) { - mp = ms->matcher; - if (!mp->flags && mp->wlen > 0 && mp->llen > 0 && - mp->wlen <= len && mp->llen <= len && - pattern_match(mp->word, word - mp->wlen, - NULL, ea) && - pattern_match(mp->line, p - mp->llen, - ea, NULL)) { - p -= mp->llen; - word -= mp->wlen; - ll -= mp->llen; - len -= mp->wlen; - ind += mp->wlen; - t = 1; - } - } - if (!t) - break; - } - } - if (p == line->line + line->llen) { - miss = 1; - len = 0; - } else { - if (ll) { - miss = 1; - line->line = p; - line->llen -= ll; - len = 0; - } - line->next = NULL; - if (l) - l->next = line; - else - ret = line; - } + /* We will use the str and len fields to contain the next sub-string + * in the list. If len is zero, we have to use the next cline. */ + if (!md->len) { + /* If there is none, we reached the end. */ + if (!md->cl) + return 1; + + /* Otherwise, get the string. Only the line-string or both. + * We also have to adjust the pointer if this is for a suffix. */ + if (md->cl->flags & CLF_LINE) { + md->line = 1; + md->len = md->cl->llen; + md->str = md->cl->line; } else { - if (line->wlen == len && !strncmp(line->word, word - len, len)) { - if (next) - miss = 1; - line->next = NULL; - if (l) - l->next = line; - else - ret = line; - len = 0; - } else { - char sav = word[ind]; - - word[ind] = '\0'; - if (strpfx(word - len, line->word)) { - word[ind] = sav; - - line->word += line->wlen - len; - line->wlen = ind; - miss = 1; - line->next = NULL; - if (l) - l->next = line; - else - ret = line; - len = 0; - } else if (strpfx(line->word, word - len)) { - word[ind] = sav; - - miss = 1; - line->next = NULL; - if (l) - l->next = line; - else - ret = line; - len = 0; - } else { - int mol, mnl; - Cline sl, send; - - word[len] = sav; - - if ((sl = bld_new_sfx(line->wlen, line->word, - len, word - len, - &mol, &mnl, &send))) { - if (l) - l->next = sl; - else - ret = sl; - if (!mol) { - send->next = next; - word -= len - mnl; - len = mnl; - } else - len = 0; - l = send; - } else - len = 0; - } - } + md->line = 0; + md->len = md->olen = md->cl->wlen; + if ((md->str = md->cl->word) && sfx) + md->str += md->len; + md->alen = md->cl->llen; + if ((md->astr = md->cl->line) && sfx) + md->astr += md->alen; } - line = next; + md->pcl = md->cl; + md->cl = md->cl->next; } - *missp = (line || len || miss); - - return ret; + return 0; } -/**/ -static void -bld_sfx(Cline o, Cline n) -{ - if (o->flags & CLF_SNEW) { - int miss; - - o->suffix = join_new_sfx(o->suffix, n->wlen, n->word, &miss); - if (miss) - o->flags |= CLF_MISS; - } else if (o->wlen && n->wlen) { - char so = o->word[o->wlen], sn = n->word[n->wlen]; - char *new = o->word; - int newl = o->wlen, mol, mnl; - - o->word[o->wlen] = n->word[n->wlen] = '\0'; - if (strpfx(n->word, o->word)) { - new = dupstring(n->word); - newl = n->wlen; - } else if (!strpfx(o->word, n->word)) { - o->flags |= CLF_SNEW; - o->suffix = bld_new_sfx(o->wlen, o->word, n->wlen, n->word, - &mol, &mnl, NULL); - newl = 0; - new = ""; - if (mol || mnl) - o->flags |= CLF_MISS; - } - o->word[o->wlen] = so; - n->word[n->wlen] = sn; - - o->word = new; - o->wlen = newl; +/* This puts the not-yet-matched portion back into the last cline and + * returns that. */ - if (!o->suffix && n->wlen != o->wlen) - o->flags |= CLF_MISS; - } else - o->wlen = 0; +static Cline +undo_cmdata(Cmdata md, int sfx) +{ + Cline r = md->pcl; + + if (md->line) { + r->word = NULL; + r->wlen = 0; + r->flags |= CLF_LINE; + r->llen = md->len; + r->line = md->str - (sfx ? md->len : 0); + } else if (md->len != md->olen) { + r->wlen = md->len; + r->word = md->str - (sfx ? md->len : 0); + } + return r; } -/* Joins two Cline lists, building the most specific line string * - * that is possible and returns it. This is done by modifying the - * cline list given as the first argument. */ +/* This tries to build a string matching a sub-string in a sub-cline + * that could not be matched otherwise. */ static Cline -join_clines(Cline o, Cline n) +join_sub(Cmdata md, char *str, int len, int *mlen, int sfx, int join) { - Cline oo = o; - - if (!o) - /* This is the first time we are being called, so just return - * the second list. In future calls we will get this list as - * the first argument. */ - return n; - else { - Cline f = freecl, q, op = NULL; - int ol, nl; - - freecl = NULL; + if (!check_cmdata(md, sfx)) { + char *ow = str, *nw = md->str; + int ol = len, nl = md->len; + Cmlist ms; + Cmatcher mp; + VARARR(unsigned char, ea, (ol > nl ? ol : nl) + 1); + int t; - while (o && n) { - /* CLF_MID is set in the cline struct where the prefix and the - * suffix from the line meet. If we have reached the cline - * for it in one of the lists, search the corresponding - * cline in the other list, removing all structs up to it. */ - if (o->flags & CLF_MID) { - while (n && !(n->flags & CLF_MID)) { - q = n->next; - n->next = f; - f = n; - - n = q; - } - } - if (n && n->flags & CLF_MID) { - while (o && !(o->flags & CLF_MID)) { - o->word = NULL; - o->flags |= CLF_DIFF; + if (sfx) { + ow += ol; nw += nl; + } + for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) { + mp = ms->matcher; + /* We use only those patterns that match a non-empty + * string in both the line and the word and that have + * no anchors. */ + if (!mp->flags && mp->wlen > 0 && mp->llen > 0) { + /* We first test, if the old string matches already the + * new one. */ + if (mp->llen <= ol && mp->wlen <= nl && + pattern_match(mp->line, ow - (sfx ? mp->llen : 0), + NULL, ea) && + pattern_match(mp->word, nw - (sfx ? mp->wlen : 0), + ea, NULL)) { + /* It did, update the contents of the cmdata struct + * and return a cline for the matched part. */ + if (sfx) + md->str -= mp->wlen; + else + md->str += mp->wlen; + md->len -= mp->wlen; + *mlen = mp->llen; - o = o->next; + return get_cline(NULL, 0, ow - (sfx ? mp->llen : 0), + mp->llen, NULL, 0, 0); } - } - if (o && n && !((o->flags | n->flags) & CLF_MID)) { - ol = o->llen; - nl = n->llen; - - while (o && n && ol != nl) { - /* The matched strings have different lengths, so * - * continue walking the lists until we have the same * - * matched lengths. */ - o->word = NULL; - o->flags |= CLF_DIFF; - if (ol < nl) { - op = o; - if ((o = o->next)) - ol += o->llen; - } else { - q = n->next; - n->next = f; - f = n; + /* Otherwise we will try to build a string that matches + * both strings. But try the pattern only if the word- + * pattern matches one of the strings. */ + if (join && mp->wlen <= ol && mp->wlen <= nl && + ((t = pattern_match(mp->word, ow - (sfx ? mp->wlen : 0), + NULL, ea)) || + pattern_match(mp->word, nw - (sfx ? mp->wlen : 0), + NULL, ea))) { + VARARR(char, line, mp->llen + 1); + int bl; + + /* Then build all the possible lines and see + * if one of them matches the other string. */ + if ((bl = bld_line(mp->line, line, line, + (t ? nw : ow), (t ? nl : ol), + ea, sfx))) { + /* Yep, one of the lines matched the other + * string. */ + line[mp->llen] = '\0'; + + if (t) { + ol = mp->wlen; nl = bl; + } else { + ol = bl; nl = mp->wlen; + } + if (sfx) + md->str -= nl; + else + md->str += nl; + md->len -= nl; + *mlen = ol; - if ((n = q)) - nl += n->llen; + return get_cline(NULL, 0, dupstring(line), mp->llen, + NULL, 0, CLF_JOIN); } } } - if (!o || !n) - break; - if (o->flags & CLF_MID) { - /* These are the structs in the middle, so simplify the - * prefix and the suffix in it to their longest common - * versions. */ - - char *os, *ns, *oss = o->line, *nss = n->line; - int ol, nl, mol, mnl, oll = o->llen, nll = n->llen; - - os = o->word; - ol = o->wlen; - ns = n->word; - nl = n->wlen; - - o->word = o->line; - o->wlen = o->llen; - n->word = n->line; - n->wlen = n->llen; - bld_pfx(o, n, &mol, &mnl); - o->line = o->word; - o->llen = o->wlen; - - o->word = os; - o->wlen = ol; - n->word = ns; - n->wlen = nl; - - if (o->wlen < 0) { - o->word = oss + mol; - o->wlen = oll - mol; - } - if (n->wlen < 0) { - n->word = nss + mnl; - n->wlen = nll - mnl; - } - bld_sfx(o, n); - } else if (o->word) { - if (n->word) { - if (o->llen == n->llen && - (o->flags & CLF_VAR) && (n->flags & CLF_VAR) && - (o->flags & (CLF_END | CLF_SUF)) == - (n->flags & (CLF_END | CLF_SUF))) { - /* We have two chunks from `*' patterns, - * reduce them to the common prefix/suffix. */ - if (o->flags & CLF_SUF) - bld_sfx(o, n); - else - bld_pfx(o, n, NULL, NULL); - } else if (o->wlen == n->wlen) { - /* Otherwise keep them if they are equal. */ - if (strncmp(o->word, n->word, o->wlen)) { - /* If they are not equal, we make them * - * be left unchanged on the line. */ - o->word = NULL; - o->flags |= CLF_DIFF; - } - } else { - o->word = NULL; - o->flags |= CLF_DIFF; - } - } else { - o->word = NULL; - o->flags |= CLF_DIFF; - } - } else if (n->word) - o->flags |= CLF_DIFF; - - q = n->next; - n->next = f; - f = n; - - n = q; - op = o; - o = o->next; - } - if (o) { - /* The old list has elements not matched by the second list - * we put all these elements in the free list. */ - for (q = o; q->next; q = q->next); - - q->next = f; - f = o; - - if (op) - op->next = NULL; - else - return NULL; - } - if (n) { - /* We always put the chunks from the second list back on * - * the free list. */ - for (q = n; q->next; q = q->next); - - q->next = f; - f = n; } - freecl = f; } - return oo; -} - -/* This returns a Cline for the given string. In lp we return a pointer to - * the last cline struct created. */ - -static Cline -str_cline(char *s, int l, Cline *lp) -{ - Cline r = NULL, *p = &r, n = NULL; - - if (l < 0) - l = strlen(s); - /* We build one struct per character, this makes joining it faster - * and easier. */ - while (l) { - *p = n = getcline(s, 1, NULL, 0, 0); - - p = &(n->next); - s++; - l--; - } - if (lp) - *lp = n; - - return r; + return NULL; } -/* This reverts the order of the elements of the given cline list and - * returns a pointer to the new head. */ +/* This is used to match a sub-string in a sub-cline. The length of the + * matched portion is returned. This tests only for exact equality. */ -static Cline -revert_clines(Cline p) +static int +sub_match(Cmdata md, char *str, int len, int sfx) { - Cline r = NULL, n; + int ret = 0, l, ind, add; + char *p, *q; - while (p) { - n = p->next; - p->next = r; - r = p; - p = n; + if (sfx) { + str += len; + ind = -1; add = -1; + } else { + ind = 0; add = 1; } - return r; -} - -/* Prepend a string to a Cline and return a pointer to the new cline list. */ - -static Cline -prepend_cline(char *s, Cline l) -{ - Cline n, r = str_cline(s, -1, &n), *p = &(n->next); + /* str and len describe the old string, in md we have the new one. */ + while (len) { + if (check_cmdata(md, sfx)) + return ret; - while (l) { - *p = n = getcline(l->line, l->llen, l->word, l->wlen, - l->flags); + for (l = 0, p = str, q = md->str; + l < len && l < md->len && p[ind] == q[ind]; + l++, p += add, q += add); - p = &(n->next); - l = l->next; + if (l) { + /* There was a common prefix, use it. */ + md->len -= l; len -= l; + if (sfx) { + md->str -= l; str -= l; + } else { + md->str += l; str += l; + } + ret += l; + } else if (md->line || md->len != md->olen || !md->astr) + return ret; + else { + /* We still have the line string to try. */ + md->line = 1; + md->len = md->alen; + md->str = md->astr; + } } - return r; + return ret; } -/* This simplifies the Cline to match the given strings. The strings are: - * the common prefix and its length, a string with the suffix at the end - * and the suffix length. */ +/* This is used to build a common prefix or suffix sub-list. If requested + * it returns the unmatched cline lists in orest and nrest. */ static void -merge_cline(Cline lc, char *p, int pl, char *s, int sl, int psl) +join_psfx(Cline ot, Cline nt, Cline *orest, Cline *nrest, int sfx) { - int pll, sll; - Cline l = NULL, *q = &l, n; - - pll = strlen(p); - if (s) { - /* If there is a suffix, get a pointer to the beginning of the - * common suffix. */ - int i = strlen(s); - - if (ainfo->suflen < 10000) - s = s + i - ainfo->suflen; - else { - s = s + i - sl; - p[pll - (sl - psl)] = '\0'; - pll -= sl - psl; - } - sll = strlen(s) - sl; - } else - sll = 0; - - pll -= pl; + Cline p = NULL, o, n; + struct cmdata md, omd; + char **sstr = NULL; + int len, join = 0, line = 0, *slen = NULL; - /* Now build a cline list from the string(s) and join it with the - * cline list we have built while testing possible matches. */ - l = str_cline(p, pl, &n); - q = &(n->next); - if (!sl) - *q = getcline(NULL, 0, p + pl, pll, CLF_END | CLF_VAR); - else { - *q = n = getcline(p + pl, pll, s, sll, CLF_MID); + if (sfx) { + o = ot->suffix; n = nt->suffix; + } else { + o = ot->prefix; n = nt->prefix; + } + if (!o) { + if (orest) + *orest = NULL; + if (nrest) + *nrest = n; - n->next = str_cline(s + sll, sl, NULL); + return; } - join_clines(lc, l); -} + if (!n) { + if (sfx) + ot->suffix = NULL; + else + ot->prefix = NULL; -/* This inserts the Cline built into the command line. The last two - * arguments are the relative positions where the begining and the - * end of the brace expansion strings have to be re-inserted. */ + if (orest) + *orest = o; + else + free_cline(o); + if (nrest) + *nrest = NULL; + return; + } + md.cl = n; + md.len = 0; -static void -inst_cline(Cline l, int pl, int sl) -{ - int m = -1, d = -1, b = -1, hb = 0, i = 0; + /* Walk through the old list. */ + while (o) { + join = 0; + memcpy(&omd, &md, sizeof(struct cmdata)); - /* Adjust the position of the braces. */ - pl += brpl; - sl += brbsl; + /* We first get the length of the prefix equal in both strings. */ + if (o->flags & CLF_LINE) { + if ((len = sub_match(&md, o->line, o->llen, sfx)) != o->llen) { + join = 1; line = 1; slen = &(o->llen); sstr = &(o->line); + } + } else if ((len = sub_match(&md, o->word, o->wlen, sfx)) != o->wlen) { + if (o->line) { + memcpy(&md, &omd, sizeof(struct cmdata)); + o->flags |= CLF_LINE | CLF_DIFF; - i = cs - wb; + continue; + } + join = 1; line = 0; slen = &(o->wlen); sstr = &(o->word); + } + if (join) { + /* There is a rest that is different in the two lists, + * we try to build a new cline matching both strings. */ + Cline joinl; + int jlen; + + if ((joinl = join_sub(&md, *sstr + len, *slen - len, + &jlen, sfx, !(o->flags & CLF_JOIN)))) { + /* We have one, insert it into the list. */ + joinl->flags |= CLF_DIFF; + if (len + jlen != *slen) { + Cline rest; + + rest = get_cline(NULL, 0, *sstr + (sfx ? 0 : len + jlen), + *slen - len - jlen, NULL, 0, 0); + + rest->next = o->next; + joinl->next = rest; + } else + joinl->next = o->next; - /* Insert the brace strings now? */ - if (pl >= 0 && i >= pl && brbeg && *brbeg) { - inststrlen(brbeg, 1, -1); - pl = -1; - hb = 1; - } - if (sl >= 0 && i >= sl && brend && *brend) { - inststrlen(brend, 1, -1); - sl = -1; - hb = 1; - } - /* Walk the list. */ - while (l) { - /* If this cline describes a suffix where something is missing - * for some matches, remember the position. */ - if (m < 0 && (l->flags & (CLF_MISS | CLF_SUF)) == (CLF_MISS | CLF_SUF)) - m = cs; - - if (l->prefix) { - Cline sl = l->prefix, ssl; - int hm; - - if (l->flags & (CLF_END | CLF_MID)) { - /* At the end and in the middle the suffix we have - * separate runs. */ - for (; sl; sl = sl->next) { - hm = 0; - if (sl->prefix) { - for (ssl = sl->prefix; ssl; ssl = ssl->next) { - if (ssl->line) - /* line for a string derived from applying - * the matchers the other way round. */ - inststrlen(ssl->line, 1, ssl->llen); - else - /* and word for substrings equal in all - * matches. */ - inststrlen(ssl->word, 1, ssl->wlen); - /* If the string differs from any of the - * matches, remember the position. */ - if (d < 0 && (ssl->flags & CLF_DIFF)) - d = cs; - } - } else if (sl->wlen) - inststrlen(sl->word, 1, sl->wlen); - - if (m < 0 && (sl->flags & CLF_MISS)) - m = cs; - if (sl->llen) - inststrlen(sl->line, 1, sl->llen); - hm = (sl->flags & CLF_MISS); - } - if ((l->flags & CLF_MID) &&hm && b < 0) { - b = cs; - hb = 1; - } - } else { - /* The cline contains a newly build part of the string - * in a sub-list. */ - for (; sl; sl = sl->next) { - if (sl->line) - /* line for a string derived from applying the - * matchers the other way round. */ - inststrlen(sl->line, 1, sl->llen); + if (len) { + if (sfx) + *sstr += *slen - len; + *slen = len; + o->next = joinl; + } else { + o->next = NULL; + free_cline(o); + if (p) + p->next = joinl; + else if (sfx) + ot->suffix = joinl; else - /* and word for substrings equal in all matches. */ - inststrlen(sl->word, 1, sl->wlen); - /* If the string differs from any of the matches, - * remember the position. */ - if (d < 0 && (sl->flags & CLF_DIFF)) - d = cs; + ot->prefix = joinl; } + o = joinl; + join = 0; } - if (!(l->flags & (CLF_END | CLF_MID))) - i += l->llen; } - if (l->suffix) { - Cline sl = revert_clines(l->suffix); + if (join) { + /* We couldn't build a cline for a common string, so we + * cut the list here. */ + if (len) { + Cline r; - if ((sl->flags & CLF_MISS) && b < 0) { - b = cs; - hb = 1; - } - for (; sl; sl = sl->next) { - if (sl->line) - inststrlen(sl->line, 1, sl->llen); - else - inststrlen(sl->word, 1, sl->wlen); - if (d < 0 && (sl->flags & CLF_DIFF)) - d = cs; - } - } - if (l->flags & CLF_MID) { - /* The cline in the middle, insert the prefix and the - * suffix. */ - if (!l->prefix && l->llen) { - inststrlen(l->line, 1, l->llen); - if (b < 0) { - b = cs; - hb = l->flags & CLF_MISS; + if (orest) { + if (line) + r = get_cline(o->line + len, *slen - len, + NULL, 0, NULL, 0, o->flags); + else + r = get_cline(NULL, 0, o->word + len, *slen - len, + NULL, 0, o->flags); + + r->next = o->next; + *orest = r; + + *slen = len; + o->next = NULL; + } else { + if (sfx) + *sstr += *slen - len; + *slen = len; + free_cline(o->next); + o->next = NULL; } - } - if (!l->suffix && l->wlen > 0) - inststrlen(l->word, 1, l->wlen); - } else if (!l->prefix && !l->suffix) { - if (l->word && - !((pl >= 0 && brbeg && *brbeg && - i < pl && i + l->llen >= pl) || - (sl >= 0 && brend && *brend && - i < sl && i + l->llen >= sl))) { - /* We insert the prefered string stored in word only if we - * don't have to put the brace beginning or end here. */ - inststrlen(l->word, 1, l->wlen); } else { - /* Otherwise just re-insert the original string. */ - inststrlen(l->line, 1, l->llen); + if (p) + p->next = NULL; + else if (sfx) + ot->suffix = NULL; + else + ot->prefix = NULL; + + if (orest) + *orest = o; + else + free_cline(o); } - i += l->llen; - } - /* Remember the position if there is a difference or a missing - * substring. */ - if (d < 0 && (l->flags & CLF_DIFF)) - d = cs; - if (m < 0 && (l->flags & CLF_MISS)) - m = cs; - - /* Probably insert the brace beginning or end. */ - if (pl >= 0 && i >= pl && brbeg && *brbeg) { - cs -= i - pl; - inststrlen(brbeg, 1, -1); - cs += i - pl; - pl = -1; - hb = 1; - } - if (sl >= 0 && i > sl && brend && *brend) { - cs -= i - sl; - inststrlen(brend, 1, -1); - cs += i - sl; - sl = -1; - hb = 1; + if (!orest || !nrest) + ot->flags |= CLF_MISS; + + if (nrest) + *nrest = undo_cmdata(&md, sfx); + + return; } - l = l->next; + p = o; + o = o->next; } - lastend = cs; - /* Now place the cursor. Preferably in a position where something - * is missing, otherwise in a place where the string differs from - * any of the matches, or just leave it at the end. */ - cs = (b >= 0 && hb ? b : (m >= 0 ? m : (d >= 0 ? d : cs))); - if (cs > ll) - cs = ll; + if (md.len || md.cl) + ot->flags |= CLF_MISS; + if (orest) + *orest = NULL; + if (nrest) + *nrest = undo_cmdata(&md, sfx); } -/* Check if the given pattern matches the given string. * - * `in' and `out' are used for {...} classes. In `out' we store the * - * character number that was matched. In the word pattern this is * - * given in `in' so that we can easily test if we found the * - * corresponding character. */ +/* This builds the common prefix and suffix for a mid-cline -- the one + * describing the place where the prefix and the suffix meet. */ -/**/ -static int -pattern_match(Cpattern p, char *s, unsigned char *in, unsigned char *out) +static void +join_mid(Cline o, Cline n) { - unsigned char c; + if (o->flags & CLF_JOIN) { + /* The JOIN flag is set in the old cline struct if it was + * already joined with another one. In this case the suffix + * field contains the suffix from previous calls. */ + Cline nr; - while (p) { - c = *((unsigned char *) s); + join_psfx(o, n, NULL, &nr, 0); - if (out) - *out = 0; + n->suffix = revert_cline(nr); - if (p->equiv) { - if (in) { - c = p->tab[c]; - if ((*in && *in != c) || (!*in && !c)) - return 0; - } else if (out) { - if (!(*out = p->tab[c])) - return 0; - } else if (!p->tab[c]) - return 0; + join_psfx(o, n, NULL, NULL, 1); + } else { + /* This is the first time for both structs, so the prefix field + * contains the whole sub-list. */ + Cline or, nr; - if (in && *in) - in++; - if (out) - out++; - } else if (!p->tab[c]) - return 0; + o->flags |= CLF_JOIN; - s++; - p = p->next; + /* We let us give both rests and use them as the suffixes. */ + join_psfx(o, n, &or, &nr, 0); + + if (or) + or->llen = (o->slen > or->wlen ? or->wlen : o->slen); + o->suffix = revert_cline(or); + n->suffix = revert_cline(nr); + + join_psfx(o, n, NULL, NULL, 1); } - return 1; + n->suffix = NULL; } -/* Do the matching for a prefix. l and w contain the strings on the line and - * for the generated word, respectively. In nlp we return a cline list for this - * match. In lp we return the length of the matched string. rlp is used to - * return a pointer to the last cline struct in the list returned in nlp, and - * in bplp we return the relative position where the brace beginning would - * have to be insrted in the string returned, which is the string to use - * as the completion. */ +/* This simplifies the cline list given as the first argument so that + * it also matches the second list. */ -static char * -match_pfx(char *l, char *w, Cline *nlp, int *lp, Cline *rlp, int *bplp) +static Cline +join_clines(Cline o, Cline n) { - static unsigned char *ea; - static int ealen = 0; - static char *rw; - static int rwlen; - - int ll = strlen(l), lw = strlen(w), oll = ll, olw = lw, mlw; - int il = 0, iw = 0, t, bc = brpl; - char *nw = rw; - Cmlist ms; - Cmatcher mp, lm = NULL; - Cline lr = NULL; - - if (nlp) { - *nlp = NULL; - - if (ll + 1 > 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) { - t = 0; - /* First try the matchers. */ - for (ms = mstack; ms; ms = ms->next) { - for (mp = ms->matcher; mp; mp = mp->next) { - if (lm == mp) - continue; + /* First time called, just return the new list. On further invocations + * we will get it as the first argument. */ + if (!o) + return n; + else { + Cline oo = o, nn = n, po = NULL, pn = NULL; - t = 1; - if ((oll == ll || olw == lw) && !nlp && mp->wlen < 0) - /* If we were called recursively, don't use `*' patterns - * at the beginning (avoiding infinite recursion). */ - t = 0; - else if (mp->flags & CMF_LEFT) { - /* Try to match the left anchor, if any. */ - if (il < mp->lalen || iw < mp->lalen) - t = 0; - else if (mp->left) - t = pattern_match(mp->left, l - mp->lalen, NULL, NULL) && - pattern_match(mp->left, w - mp->lalen, NULL, NULL); - else - t = (!il && !iw); - } - if (t) { - /* Now match the line pattern. */ - if (ll < mp->llen || lw < mp->wlen) - t = 0; - else if (mp->wlen < 0) { - /* This is reached if we have a `*' pattern. */ - if ((t = pattern_match(mp->line, l, NULL, NULL))) { - if (mp->flags & CMF_RIGHT) - /* Check if the anchor matches what's on the - * line. If it also matches the word, we don't - * use the matcher since we don't want one of - * these patterns on the line to match more - * than one such sub-string in the word. */ - t = (mp->right && ll >= mp->llen + mp->ralen && - pattern_match(mp->right, l + mp->llen, - NULL, NULL) && - lw >= mp->ralen && - !pattern_match(mp->right, w, NULL, NULL)); - if (t) { - /* The anchor matched, so find out how many - * characters are matched by the `*' pattern. - * We do this by looping over the string - * and calling this function recursively. */ - int i = 0, j = iw, k = lw, m = 0; - int jj = il + mp->llen, kk = ll - mp->llen; - char *p = l + mp->llen, *q = w; - - for (; k; i++, j++, k--, q++) { - if ((mp->flags & CMF_RIGHT) && - (mp->right && k >= mp->ralen && - pattern_match(mp->right, q, - NULL, NULL))) { - if (m++) { - k = 0; - break; - } - } - if (match_pfx(p, q, NULL, NULL, NULL, NULL)) - break; - } - if (k && i) { - /* We found a position where the rest of - * the line matched again (k != 0) and - * we skipped over at least one character - * (i != 0), so add a cline for this */ - 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) | CLF_VAR); - } - /* ...and adjust the pointers and counters - * to continue after the matched portion. */ - w = q; - iw = j; - lw = k; - l = p; - il = jj; - ll = kk; - bc -= mp->llen; - - /* In bc we count the characters used - * backward starting with the original - * position of the brace beginning. So, - * if it becomes less than or equal to - * zero, we have reached the place where - * the brace string would have to be - * inserted. */ - if (bc <= 0 && bplp) { - *bplp = nw - rw; - bplp = NULL; - } - lm = mp; - break; - } else - t = 0; - } else - t = 0; - } - } else { - /* No `*', just try to match the line and word * - * patterns. */ - t = pattern_match(mp->line, l, NULL, ea) && - pattern_match(mp->word, w, ea, NULL); - mlw = mp->wlen; - } - } - /* Now test the right anchor, if any. */ - if (t && (mp->flags & CMF_RIGHT)) { - if (ll < mp->llen + mp->ralen || lw < mlw + mp->ralen) - t = 0; - else if (mp->right) - t = pattern_match(mp->right, l + mp->llen, NULL, NULL) && - pattern_match(mp->right, w + mlw, NULL, NULL); + /* Walk through the lists. */ + while (o && n) { + /* If one of them describes a new part and the other one does + * not, synchronise them by searching an old part in the + * other list. */ + if ((o->flags & CLF_NEW) && !(n->flags & CLF_NEW)) { + Cline t, tn; + + for (t = o; (tn = t->next) && (tn->flags & CLF_NEW); t = tn); + if (tn && cmp_anchors(tn, n, 0)) { + Cline tmp; + + tmp = o->prefix; + o->prefix = tn->prefix; + tn->prefix = tmp; + + if (po) + po->next = tn; else - t = 0; - } - if (t) { - /* If it matched, build a new chunk on the Cline list * - * and add the string to the built match. */ - if (nlp) { - 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; - lw -= mlw; - il += mp->llen; - iw += mlw; - bc -= mp->llen; - - if (bc <= 0 && bplp) { - *bplp = nw - rw; - bplp = NULL; - } - break; + oo = tn; + t->next = NULL; + free_cline(o); + o = tn; + o->flags |= CLF_MISS; + continue; } } - if (mp) { - if (mp != lm) - lm = NULL; - break; - } - } - 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 (lp) - *lp = iw; - if (lw) { - 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); - - *rlp = lr; - } else { - addtocline(nlp, &lr, l, 0, dupstring(w), lw, NULL, - CLF_VAR | CLF_END); - nw = addtoword(&rw, &rwlen, nw, NULL, NULL, w, lw, 0); - } - } - } else if (rlp) { - if (nlp && lr) { - lr->next = freecl; - freecl = *nlp; - } - return NULL; - } - if (nlp && nw) - *nw = '\0'; + if (!(o->flags & CLF_NEW) && (n->flags & CLF_NEW)) { + Cline t, tn; - if (ll) { - if (nlp && *nlp) { - lr->next = freecl; - freecl = *nlp; - } - return NULL; - } - if (nlp) - /* Finally, return the built match string. */ - return dupstring(rw); - - return ((char *) 1); -} + for (t = n; (tn = t->next) && (tn->flags & CLF_NEW); t = tn); + if (tn && cmp_anchors(o, tn, 0)) { + Cline tmp; -/* Do the matching for a suffix. Almost the same as match_pfx(), only in the -* other direction. */ + tmp = n->prefix; + n->prefix = tn->prefix; + tn->prefix = tmp; -static char * -match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp) -{ - static unsigned char *ea; - static int ealen = 0; - static char *rw; - static int rwlen; - - int ll = strlen(l), lw = strlen(w), mlw; - int il = 0, iw = 0, t, bc = brsl; - char *nw = rw; - Cmlist ms; - Cmatcher mp, lm = NULL; - Cline lr = NULL; - - l += ll; - w += lw; - - if (nlp) { - *nlp = NULL; - - if (ll + 1 > ealen) { - if (ealen) - zfree(ea, ealen); - ea = (unsigned char *) zalloc(ealen = ll + 20); - } - } - while (ll && lw) { - t = 0; - for (ms = mstack; ms; ms = ms->next) { - for (mp = ms->matcher; mp; mp = mp->next) { - if (lm == mp) + n = tn; + o->flags |= CLF_MISS; continue; - - t = 1; - if (mp->flags & CMF_RIGHT) { - if (il < mp->ralen || iw < mp->ralen) - t = 0; - else if (mp->right) - t = pattern_match(mp->right, l, NULL, NULL) && - pattern_match(mp->right, w, NULL, NULL); - else - t = (!il && !iw); } - if (t) { - if (ll < mp->llen || lw < mp->wlen) - t = 0; - else if (mp->wlen < 0) { - if ((t = pattern_match(mp->line, l - mp->llen, - NULL, NULL))) { - if (mp->flags & CMF_LEFT) - t = (mp->left && ll >= mp->llen + mp->lalen && - pattern_match(mp->left, - l - mp->llen - mp->lalen, - NULL, NULL) && - lw >= mp->lalen && - !pattern_match(mp->left, w - mp->lalen, - NULL, NULL)); - if (t) { - int i = 0, j = iw, k = lw, m = 0; - int jj = il + mp->llen, kk = ll - mp->llen; - char *p = l - mp->llen - 1, *q = w - 1; - - for (; k; i++, j++, k--, q--) { - if ((mp->flags & CMF_LEFT) && - (mp->left && k >= mp->lalen && - pattern_match(mp->left, q - mp->lalen, - NULL, NULL))) { - if (m++) { - k = 0; - break; - } - } - if (match_pfx(p, q, NULL, NULL, NULL, NULL)) - break; - } - if (k && i) { - 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) | CLF_VAR); - } - w = q + 1; - iw = j; - lw = k; - l = p + 1; - il = jj; - ll = kk; - bc -= mp->llen; - - if (bc <= 0 && bslp) { - *bslp = nw - rw; - bslp = NULL; - } - lm = mp; - break; - } else - t = 0; - } - } - } else { - t = pattern_match(mp->line, l - mp->llen, NULL, ea) && - pattern_match(mp->word, w - mp->wlen, ea, NULL); - mlw = mp->wlen; - } + } + /* Almost the same as above, but for the case that they + * describe different types of parts (prefix, suffix, or mid). */ + if ((o->flags & (CLF_SUF | CLF_MID)) != + (n->flags & (CLF_SUF | CLF_MID))) { + Cline t, tn; + + for (t = n; + (tn = t->next) && + (tn->flags & (CLF_SUF | CLF_MID)) != + (o->flags & (CLF_SUF | CLF_MID)); + t = tn); + if (tn && cmp_anchors(o, tn, 1)) { + n = tn; + continue; } - if (t && (mp->flags & CMF_LEFT)) { - if (ll < mp->llen + mp->lalen || lw < mlw + mp->lalen) - t = 0; - else if (mp->left) - t = pattern_match(mp->right, l - mp->llen - mp->lalen, - NULL, NULL) && - pattern_match(mp->right, w - mlw - mp->lalen, - NULL, NULL); + for (t = o; + (tn = t->next) && + (tn->flags & (CLF_SUF | CLF_MID)) != + (n->flags & (CLF_SUF | CLF_MID)); + t = tn); + if (tn && cmp_anchors(tn, n, 1)) { + if (po) + po->next = tn; else - t = 0; + oo = tn; + t->next = NULL; + free_cline(o); + o = tn; + continue; } - if (t) { - if (nlp) { - nw = addtoword(&rw, &rwlen, nw, mp, l - mp->llen, - w - mlw, mlw, 1); - addtocline(nlp, &lr, l - mp->llen, mp->llen, - w - mlw, mlw, mp, 0); - } - l -= mp->llen; - w -= mlw; - ll -= mp->llen; - lw -= mlw; - il += mp->llen; - iw += mlw; - bc -= mp->llen; - if (bc <= 0 && bslp) { - *bslp = nw - rw; - bslp = NULL; + if (o->flags & CLF_MID) { + o->flags = (o->flags & ~CLF_MID) | (n->flags & CLF_SUF); + if (n->flags & CLF_SUF) { + free_cline(o->prefix); + o->prefix = NULL; + } else { + free_cline(o->suffix); + o->suffix = NULL; } - break; } - } - if (mp) { - if (mp != lm) - lm = NULL; break; } - } - 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; + /* Now see if they have matching anchors. If not, cut the list. */ + if (!(o->flags & CLF_MID) && !cmp_anchors(o, n, 1)) { + Cline t, tn; + + for (t = n; (tn = t->next) && !cmp_anchors(o, tn, 1); t = tn); + + if (tn) { + n = tn; + continue; + } else { + if (o->flags & CLF_SUF) + break; + + o->word = o->line = o->orig = NULL; + o->wlen = 0; + free_cline(o->next); + o->next = NULL; + } } - return NULL; + /* Ok, they are equal, now join the sub-lists. */ + if (o->flags & CLF_MID) + join_mid(o, n); + else + join_psfx(o, n, NULL, NULL, (o->flags & CLF_SUF)); + + po = o; + o = o->next; + pn = n; + n = n->next; } - } - if (lp) - *lp = iw; - if (nlp && nw) - *nw = '\0'; + /* Free the rest of the old list. */ + if (o) { + if (po) + po->next = NULL; + else + oo = NULL; - if (ll) { - if (nlp && *nlp) { - lr->next = freecl; - freecl = *nlp; + free_cline(o); } - return NULL; - } - if (nlp) - return dupstring(rw); + free_cline(nn); - return ((char *) 1); + return oo; + } } -/* Check if the word `w' is matched by the strings in pfx and sfx (the prefix - * and the suffix from the line. In clp a cline list is returned for w. - * qu is non-zero if the words has to be quoted before processed any further. - * bpl and bsl are used to report the positions where the brace-strings in - * the prefix and the suffix have to be re-inserted if this match is inserted - * in the line. - * The return value is the string to use as a completion or NULL if the prefix - * and the suffix don't match the word w. */ +/* This adds all the data we have for a match. */ -static char * -comp_match(char *pfx, char *sfx, char *w, Cline *clp, int qu, int *bpl, int *bsl) +static Cmatch +add_match_data(int alt, char *str, Cline line, + char *ipre, char *ripre, char *isuf, + char *pre, char *prpre, char *ppre, char *psuf, char *suf, + int bpl, int bsl, int flags, int exact) { - char *r = NULL; - Cline pli; - int pl; - - if (qu) - w = quotename(w, NULL, NULL, NULL); - - if (*sfx) { - /* We have a suffix, so this gets a bit more complicated. */ - char *p, *s; - int sl; - Cline sli, last; - - /* First see if the prefix matches. In pl we get the length of - * the string matched by it. */ - if ((p = match_pfx(pfx, w, &pli, &pl, &last, bpl))) { - /* Then try to match the rest of the string with the suffix. */ - if ((s = match_sfx(sfx, w + pl, &sli, &sl, bsl))) { - int pml, sml; - - /* Now append the cline list for the suffix to the one - * for the prefix. */ - last->llen -= sl; - last->next = revert_clines(sli); - - /* And store the correct parts of the prefix and the suffix - * in the cline struct in the middle. */ - pml = strlen(p); - sml = strlen(s); - r = (char *) zhalloc(pml + sml + last->llen + 1); - strcpy(r, p); - strncpy(r + pml, last->line, last->llen); - strcpy(r + pml + last->llen, s); - } else { - /* Suffix didn't match, so free the cline list for the - * prefix. */ - last->next = freecl; - freecl = pli; - - return NULL; - } - } else - return NULL; - } else if (!(r = match_pfx(pfx, w, &pli, &pl, NULL, bpl))) - /* We had only the prefix to match and that didn't match. */ - return NULL; + Cmatch cm; + Aminfo ai = (alt ? fainfo : ainfo); + int palen = 0, salen = 0, ipl = 0, pl = 0, ppl = 0, isl = 0, psl = 0; - /* If there are path prefixes or suffixes, pre- and append them to - * the cline list built. */ - if (lppre && *lppre) { - Cline l, t = str_cline(lppre, -1, &l); + DPUTS(!line, "BUG: add_match_data() without cline"); - l->next = pli; - pli = t; - } - if (lpsuf && *lpsuf) { - Cline n, t = str_cline(lpsuf, -1, NULL); + /* If there is a path suffix, we build a cline list for it and + * append it to the list for the match itself. */ + if (psuf) + salen = (psl = strlen(psuf)); + if (isuf) + salen += (isl = strlen(isuf)); - if ((n = pli)) { - while (n->next) n = n->next; + if (salen) { + char *asuf = (char *) zhalloc(salen); + Cline pp, p, s; - n->next = t; - } else - pli = t; - } - *clp = pli; + if (psl) + memcpy(asuf, psuf, psl); + if (isl) + memcpy(asuf + psl, isuf, isl); - return r; -} + s = bld_parts(asuf, salen, salen, NULL); -/* Insert the given string into the command line. If move is non-zero, * - * the cursor position is changed and len is the length of the string * - * to insert (if it is -1, the length is calculated here). */ + for (pp = NULL, p = line; p->next; pp = p, p = p->next); -/**/ -static void -inststrlen(char *str, int move, int len) -{ - if (!len || !str) - return; - if (len == -1) - len = strlen(str); - spaceinline(len); - strncpy((char *)(line + cs), str, len); - if (move) - cs += len; -} + if (!(p->flags & (CLF_SUF | CLF_MID)) && + !p->llen && !p->wlen && !p->olen) { + if (p->prefix) { + Cline q; -/* Insert the given match. This returns the number of characters inserted.*/ + for (q = p->prefix; q->next; q = q->next); + q->next = s->prefix; + s->prefix = p->prefix; + p->prefix = NULL; + } + free_cline(p); + if (pp) + pp->next = s; + else + line = s; + } else + p->next = s; + } + /* And the same for the prefix. */ + if (ipre) + palen = (ipl = strlen(ipre)); + if (pre) + palen += (pl = strlen(pre)); + if (ppre) + palen += (ppl = strlen(ppre)); + + if (palen) { + char *apre = (char *) zhalloc(palen); + Cline p, lp; + + if (ipl) + memcpy(apre, ipre, ipl); + if (pl) + memcpy(apre + ipl, pre, pl); + if (ppl) + memcpy(apre + ipl + pl, ppre, ppl); + + p = bld_parts(apre, palen, palen, &lp); + if (lp->prefix && !(line->flags & (CLF_SUF | CLF_MID))) { + lp->prefix->next = line->prefix; + line->prefix = lp->prefix; + lp->prefix = NULL; + + free_cline(lp); + + if (p != lp) { + Cline q; + + for (q = p; q->next != lp; q = q->next); + + q->next = line; + line = p; + } + } else { + lp->next = line; + line = p; + } + } + /* Then build the unambiguous cline list. */ + ai->line = join_clines(ai->line, line); -/**/ -static int -instmatch(Cmatch m) -{ - int l, r = 0, ocs, a = cs; + mnum++; + ai->count++; + + /* Allocate and fill the match structure. */ + cm = (Cmatch) zhalloc(sizeof(struct cmatch)); + cm->str = str; + cm->ppre = (ppre && *ppre ? ppre : NULL); + cm->psuf = (psuf && *psuf ? psuf : NULL); + cm->prpre = ((flags & CMF_FILE) && prpre && *prpre ? prpre : NULL); + cm->ipre = (ipre && *ipre ? ipre : NULL); + cm->ripre = (ripre && *ripre ? ripre : NULL); + cm->isuf = (isuf && *isuf ? isuf : NULL); + cm->pre = pre; + cm->suf = suf; + cm->flags = flags; + cm->brpl = bpl; + cm->brsl = bsl; + cm->rems = cm->remf = NULL; + addlinknode((alt ? fmatches : matches), cm); - /* Ignored prefix. */ - if (m->ipre) { - inststrlen(m->ipre, 1, (l = strlen(m->ipre))); - r += l; - } - /* -P prefix. */ - if (m->pre) { - inststrlen(m->pre, 1, (l = strlen(m->pre))); - r += l; - } - /* Path prefix. */ - if (m->ppre) { - inststrlen(m->ppre, 1, (l = strlen(m->ppre))); - r += l; - } - /* The string itself. */ - inststrlen(m->str, 1, (l = strlen(m->str))); - r += l; - ocs = cs; - /* Re-insert the brace beginning, if any. */ - 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; - cs = ocs; - } - /* Path suffix. */ - if (m->psuf) { - inststrlen(m->psuf, 1, (l = strlen(m->psuf))); - r += l; + /* One more match for this explanation. */ + if (expl) { + if (alt) + expl->fcount++; + else + expl->count++; } - /* Re-insert the brace end. */ - if (brend && *brend) { - a = cs; - cs -= m->brsl; - ocs = brscs = cs; - l = strlen(brend); - inststrlen(brend, 1, l); - r += l; - cs = a + l; - } else - brscs = -1; - /* -S suffix */ - if (m->suf) { - inststrlen(m->suf, 1, (l = strlen(m->suf))); - r += l; + if (!ai->firstm) + ai->firstm = cm; + + /* Do we have an exact match? More than one? */ + if (exact) { + if (!ai->exact) { + ai->exact = 1; + if (incompfunc) { + /* If a completion widget is active, we make the exact + * string available in `compstate'. */ + + int sl = strlen(str); + int lpl = (cm->ppre ? strlen(cm->ppre) : 0); + int lsl = (cm->psuf ? strlen(cm->psuf) : 0); + char *e; + + zsfree(compexactstr); + compexactstr = e = (char *) zalloc(lpl + sl + lsl + 1); + if (cm->ppre) { + strcpy(e, cm->ppre); + e += lpl; + } + strcpy(e, str); + e += sl; + if (cm->psuf) + strcpy(e, cm->psuf); + comp_setunsetptr(CP_EXACTSTR, 0); + } + ai->exactm = cm; + } else { + ai->exact = 2; + ai->exactm = NULL; + if (incompfunc) + comp_setunsetptr(0, CP_EXACTSTR); + } } - lastend = cs; - cs = ocs; - return r; + return cm; } /* This is used by compadd to add a couple of matches. The arguments are @@ -4032,16 +3404,16 @@ instmatch(Cmatch m) /**/ int -addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, +addmatches(char *ipre, char *isuf, + char *ppre, char *psuf, char *prpre, char *pre, char *suf, char *group, char *rems, char *remf, char *ign, int flags, int aflags, Cmatcher match, char *exp, char **argv) { - char *s, *t, *e, *me, *ms, *lipre = NULL, *lpre = NULL, *lsuf = NULL; + char *s, *ms, *lipre = NULL, *lisuf = NULL, *lpre = NULL, *lsuf = NULL; char **aign = NULL; - int lpl, lsl, i, pl, sl, test, bpl, bsl, llpl = 0, llsl = 0, nm = mnum; - Aminfo ai = NULL; + int lpl, lsl, pl, sl, bpl, bsl, llpl = 0, llsl = 0, nm = mnum; + int oisalt = 0, isalt, isexact; Cline lc = NULL; - LinkList l = NULL; Cmatch cm; struct cmlist mst; Cmlist oms = mstack; @@ -4080,6 +3452,7 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, * to perform matching. */ if (aflags & CAF_MATCH) { lipre = dupstring(compiprefix); + lisuf = dupstring(compisuffix); lpre = dupstring(compprefix); lsuf = dupstring(compsuffix); llpl = strlen(lpre); @@ -4091,16 +3464,18 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, lpre += pl; } if (comppatmatch && *comppatmatch) { + int is = (*comppatmatch == '*'); char *tmp = (char *) zhalloc(2 + llpl + llsl); strcpy(tmp, lpre); tmp[llpl] = 'x'; - strcpy(tmp + llpl + 1, lsuf); + strcpy(tmp + llpl + is, lsuf); tokenize(tmp); remnulargs(tmp); if (haswilds(tmp)) { - tmp[llpl] = Star; + if (is) + tmp[llpl] = Star; if ((cp = parsereg(tmp))) haspattern = 1; } @@ -4111,6 +3486,10 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, ipre = (lipre ? dyncat(lipre, ipre) : dupstring(ipre)); else if (lipre) ipre = lipre; + if (isuf) + isuf = (lisuf ? dyncat(lisuf, isuf) : dupstring(isuf)); + else if (lisuf) + isuf = lisuf; if (ppre) { ppre = dupstring(ppre); lpl = strlen(ppre); @@ -4162,237 +3541,45 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, begcmgroup("default", 0); } /* Select the set of matches. */ - if (aflags & CAF_ALT) { - l = fmatches; - ai = fainfo; - } else { - l = matches; - ai = ainfo; - } + oisalt = (aflags & CAF_ALT); + if (remf) { remf = dupstring(remf); rems = NULL; } else if (rems) rems = dupstring(rems); - /* Build the common -P prefix. */ - if (ai->pprefix) { - if (pre) - ai->pprefix[pfxlen(ai->pprefix, pre)] = '\0'; - else - ai->pprefix[0] = '\0'; - } else - ai->pprefix = dupstring(pre ? pre : ""); } /* Walk through the matches given. */ for (; (s = dupstring(*argv)); argv++) { - sl = pl = strlen(s); - lc = NULL; - ms = NULL; + sl = strlen(s); bpl = brpl; bsl = brsl; + isalt = oisalt; if ((!psuf || !*psuf) && aign) { /* Do the suffix-test. If the match has one of the * suffixes from ign, we put it in the alternate set. */ char **pt = aign; int filell; - for (test = 1; test && *pt; pt++) + for (isalt = 0; !isalt && *pt; pt++) if ((filell = strlen(*pt)) < sl && !strcmp(*pt, s + sl - filell)) - test = 0; - - if (!test) { - l = fmatches; - ai = fainfo; - } else { - l = matches; - ai = ainfo; - } - } - if (aflags & CAF_MATCH) { - /* Do the matching. */ - if (cp) { - if ((test = domatch(s, cp, 0))) - e = me = s + sl; - else - continue; - } else { - test = (sl >= llpl + llsl && - strpfx(lpre, s) && strsfx(lsuf, s)); - if (!test && mstack && - (ms = comp_match(lpre, lsuf, s, - &lc, (aflags & CAF_QUOTE), - &bpl, &bsl))) - test = 1; - - if (!test) - continue; - pl = sl - llsl; - me = s + sl - llsl; - e = s + llpl; - } - } else { - e = s; - me = s + sl; - pl = sl; - } - /* Quoting? */ - if (!(aflags & CAF_QUOTE)) { - int tmp = me - s; - - s = quotename(s, &e, me, &tmp); - me = s + tmp; - sl = strlen(s); - } - /* The rest is almost the same as in addmatch(). */ - if (!ms) { - if (sl < ai->minlen) - ai->minlen = sl; - if (!cp && !mstack && ai->firstm && - (i = sfxlen(ai->firstm->str, s)) < ai->suflen) - ai->suflen = i; - } - t = s; - if (ppre) - t = dyncat(ppre, t); - if (!cp && !ms && (mstack || psuf)) { - int bl = ((aflags & CAF_MATCH) ? llpl : 0); - Cline *clp = &lc, tlc; - char *ss = dupstring(s), *ee = me + (ss - s); - - DPUTS(me < s || me > s + sl, - "BUG: invalid end-pointer (me)"); - - if (ppre && *ppre) { - *clp = tlc = getcline(NULL, 0, ppre, lpl, CLF_VAR); - clp = &(tlc->next); - } - if (bl) { - *clp = str_cline(ss, bl, &tlc); - clp = &(tlc->next); - } - if (ee != ss + sl) { - *clp = tlc = getcline(ss + bl, ee - ss - bl, - NULL, 0, CLF_MID); - clp = &(tlc->next); - *clp = str_cline(ee, (ss + sl) - ee, &tlc); - clp = &(tlc->next); - } else { - *clp = tlc = getcline(NULL, 0, ss + bl, sl - bl, - CLF_END | CLF_VAR); - clp = &(tlc->next); - } - if (psuf && *psuf) { - *clp = tlc = getcline(NULL, 0, psuf, lsl, - CLF_END | CLF_VAR); - clp = &(tlc->next); - } - *clp = NULL; - } else if (!cp && mstack) { - Cline tlc; - - if (ppre && *ppre) { - tlc = getcline(NULL, 0, ppre, lpl, CLF_VAR); - tlc->next = lc; - lc = tlc; - } - if (psuf && *psuf) { - if (lc) { - for (tlc = lc; tlc->next; tlc = tlc->next); - tlc->next = getcline(NULL, 0, psuf, lsl, - CLF_END | CLF_VAR); - } else - lc = getcline(NULL, 0, psuf, lsl, - CLF_END | CLF_VAR); - } + isalt = 1; } - if (ipre && *ipre) { - Cline tlc = prepend_cline(ipre, lc); - - ai->noipre = 0; - if (!ms && !mstack) { - if ((aflags & CAF_MATCH) || ai->icpl > pl) - ai->icpl = pl; - if ((aflags & CAF_MATCH) || ai->icsl > lsl) - ai->icsl = lsl; - if (ai->iaprefix) - ai->iaprefix[pfxlen(ai->iaprefix, t)] = '\0'; - else - ai->iaprefix = dupstring(t); - } else - ai->ilinecl = join_clines(ai->ilinecl, lc); - if (ai->iprefix) { - if (strcmp(ipre, ai->iprefix)) - ai->iprefix = ""; - } else - ai->iprefix = dupstring(ipre); + if (!(aflags & CAF_MATCH)) { + ms = s; + lc = bld_parts(s, sl, -1, NULL); + isexact = 0; + } else if (!(ms = comp_match(lpre, lsuf, s, cp, &lc, + (aflags & CAF_QUOTE), + &bpl, &bsl, &isexact))) + continue; - t = dyncat(ipre, t); - lc = tlc; - } else - ai->iprefix = ""; - if (!ms && !mstack && !lc) { - if ((aflags & CAF_MATCH) || ai->cpl > pl) - ai->cpl = pl; - if ((aflags & CAF_MATCH) || ai->csl > lsl) - ai->csl = lsl; - if (ai->aprefix) - ai->aprefix[pfxlen(ai->aprefix, t)] = '\0'; - else - ai->aprefix = dupstring(t); - } else - ai->linecl = join_clines(ai->linecl, lc); - - mnum++; - ai->count++; - - /* Finally add the match. */ - cm = (Cmatch) zhalloc(sizeof(struct cmatch)); - cm->ppre = ppre; - cm->psuf = psuf; - cm->prpre = prpre; - cm->str = (ms ? ms : dupstring(s)); - cm->ipre = cm->ripre = (ipre && *ipre ? ipre : NULL); - cm->pre = pre; - cm->suf = suf; - cm->flags = flags; - cm->brpl = bpl; - cm->brsl = bsl; - cm->remf = remf; + cm = add_match_data(isalt, ms, lc, ipre, ipre, isuf, pre, prpre, + ppre, psuf, suf, bpl, bsl, + flags, isexact); cm->rems = rems; - addlinknode(l, cm); - - if (exp) { - if (l == matches) - expl->count++; - else - expl->fcount++; - } - if (!ms) { - if (!ai->firstm) - ai->firstm = cm; - if (!cp && (aflags & CAF_MATCH) && !(e - (s + pl))) { - if (!ai->exact) { - ai->exact = 1; - zsfree(compexactstr); - compexactstr = e = (char *) zalloc(lpl + sl + lsl + 1); - if (ppre) { - strcpy(e, ppre); - e += lpl; - } - strcpy(e, s); - e += sl; - if (psuf) - strcpy(e, psuf); - comp_setunsetptr(CP_EXACTSTR, 0); - } else { - ai->exact = 2; - cm = NULL; - comp_setunsetptr(0, CP_EXACTSTR); - } - ai->exactm = cm; - } - } + cm->remf = remf; } compnmatches = mnum; if (exp) @@ -4419,16 +3606,11 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, static void addmatch(char *s, char *t) { - int test = 0, sl = strlen(s), pl = rpl, cc = 0, isf = 0; - int mpl = 0, msl = 0, bpl = brpl, bsl = brsl; - char *e = NULL, *tt, *te, *ms = NULL; - Comp cp = patcomp; + int isfile = 0, isalt = 0, isexact, bpl = brpl, bsl = brsl; + char *ms = NULL, *tt; HashNode hn; Param pm; - LinkList l = matches; - Cmatch cm; Cline lc = NULL; - Aminfo ai = ainfo; /* * addwhat: -5 is for files, @@ -4440,7 +3622,7 @@ addmatch(char *s, char *t) * -3 is for executable command names. * -2 is for anything unquoted * -1 is for other file specifications - * (things with `~' of `=' at the beginning, ...). + * (things with `~' or `=' at the beginning, ...). */ /* Just to make the code cleaner */ @@ -4449,90 +3631,34 @@ addmatch(char *s, char *t) if (incompfunc) s = dupstring(s); - e = s + sl; - if (!addwhat) { - test = 1; - } else if (addwhat == -1 || addwhat == -5 || addwhat == -6 || - addwhat == CC_FILES || addwhat == -7 || addwhat == -8) { - if (sl < fpl + fsl) - return; + if (addwhat == -1 || addwhat == -5 || addwhat == -6 || + addwhat == CC_FILES || addwhat == -7 || addwhat == -8) { if ((addwhat == CC_FILES || addwhat == -5) && !*psuf) { /* If this is a filename, do the fignore check. */ char **pt = fignore; - int filell; + int filell, sl = strlen(s); - for (test = 1; test && *pt; pt++) - if ((filell = strlen(*pt)) < sl - && !strcmp(*pt, s + sl - filell)) - test = 0; - - if (!test) { - l = fmatches; - ai = fainfo; - } - } - pl = fpl; - if (addwhat == -5 || addwhat == -8) { - test = 1; - cp = filecomp; - cc = cp || ispattern; - e = s + sl - fsl; - mpl = fpl; msl = fsl; - } else { - if ((cp = filecomp)) { - if ((test = domatch(s, filecomp, 0))) { - e = s + sl; - cc = 1; - } - } else { - e = s + sl - fsl; - if ((test = !strncmp(s, fpre, fpl))) - if ((test = !strcmp(e, fsuf))) { - mpl = fpl; msl = fsl; - } - if (!test && mstack && - (ms = comp_match(fpre, fsuf, s, &lc, - (addwhat == CC_FILES || - addwhat == -6), &bpl, &bsl))) - test = 1; - if (ispattern) - cc = 1; - } + for (isalt = 0; !isalt && *pt; pt++) + if ((filell = strlen(*pt)) < sl && + !strcmp(*pt, s + sl - filell)) + isalt = 1; } - if (test) { - if (addwhat == -7 && !findcmd(s, 0)) - return; - isf = CMF_FILE; + if (!(ms = comp_match(fpre, fsuf, s, filecomp, &lc, + (addwhat == CC_FILES || addwhat == -6 || + addwhat == -5 || addwhat == -8), + &bpl, &bsl, &isexact))) + return; - if (addwhat == CC_FILES || addwhat == -6 || - addwhat == -5 || addwhat == -8) { - te = s + pl; - s = quotename(s, &e, te, &pl); - sl = strlen(s); - } else if (!cc) { - s = dupstring(t = s); - e += s - t; - } - if (cc) { - tt = (char *)zhalloc(lppl + lpsl + sl + 1); - tt[0] = '\0'; - if (lppre) - strcpy(tt, lppre); - strcat(tt, s); - if (lpsuf) - strcat(tt, lpsuf); - e += (tt - s); - untokenize(s = tt); - sl = strlen(s); - } - } + if (addwhat == -7 && !findcmd(s, 0)) + return; + isfile = CMF_FILE; } else if (addwhat == CC_QUOTEFLAG || addwhat == -2 || (addwhat == -3 && !(hn->flags & DISABLED)) || (addwhat == -4 && (PM_TYPE(pm->flags) == PM_SCALAR) && - (tt = pm->gets.cfn(pm)) && *tt == '/') || - (addwhat == -9 && !(hn->flags & PM_UNSET)) || + !pm->level && (tt = pm->gets.cfn(pm)) && *tt == '/') || + (addwhat == -9 && !(hn->flags & PM_UNSET) && !pm->level) || (addwhat > 0 && ((!(hn->flags & PM_UNSET) && (((addwhat & CC_ARRAYS) && (hn->flags & PM_ARRAY)) || @@ -4541,7 +3667,8 @@ addmatch(char *s, char *t) ((addwhat & CC_SCALARS) && (hn->flags & PM_SCALAR)) || ((addwhat & CC_READONLYS) && (hn->flags & PM_READONLY)) || ((addwhat & CC_SPECIALS) && (hn->flags & PM_SPECIAL)) || - ((addwhat & CC_PARAMS) && !(hn->flags & PM_EXPORTED)))) || + ((addwhat & CC_PARAMS) && !(hn->flags & PM_EXPORTED))) && + !pm->level) || ((( addwhat & CC_SHFUNCS) || ( addwhat & CC_BUILTINS) || ( addwhat & CC_EXTCMDS) || @@ -4551,211 +3678,23 @@ addmatch(char *s, char *t) (((addwhat & CC_DISCMDS) && (hn->flags & DISABLED)) || ((addwhat & CC_EXCMDS) && !(hn->flags & DISABLED)))) || ((addwhat & CC_BINDINGS) && !(hn->flags & DISABLED))))) { - if (sl >= rpl + rsl || mstack || cp) { - if (cp) { - test = domatch(s, patcomp, 0); - e = s + sl; - } else { - e = s + sl - rsl; - if ((test = !strncmp(s, rpre, rpl))) - if ((test = !strcmp(e, rsuf))) { - mpl = rpl; msl = rsl; - } - if (!test && mstack && - (ms = comp_match(rpre, rsuf, s, &lc, - (addwhat == CC_QUOTEFLAG), &bpl, &bsl))) - test = 1; - } - } - if (!test && sl < lpl + lsl && !mstack) + if (!(ms = comp_match(rpre, rsuf, s, patcomp, &lc, + (addwhat == CC_QUOTEFLAG), + &bpl, &bsl, &isexact)) && + !(ms = comp_match(lpre, lsuf, s, NULL, &lc, + (addwhat == CC_QUOTEFLAG), + &bpl, &bsl, &isexact))) return; - if (!test && lpre && lsuf) { - e = s + sl - lsl; - if ((test = !strncmp(s, lpre, lpl))) - if ((test = !strcmp(e, lsuf))) { - mpl = lpl; msl = lsl; - } - if (!test && mstack && - (ms = comp_match(lpre, lsuf, s, &lc, - (addwhat == CC_QUOTEFLAG), &bpl, &bsl))) - test = 1; - pl = lpl; - } - if (addwhat == CC_QUOTEFLAG) { - te = s + pl; - s = quotename(s, &e, te, &pl); - sl = strlen(s); - } } - if (!test) + if (!ms) return; - if (!ms) { - if (sl < ai->minlen) - ai->minlen = sl; - if (!mstack && !ispattern && ai->firstm && - (test = sfxlen(ai->firstm->str, s)) < ai->suflen) - ai->suflen = test; - } - - /* Generate the common -P prefix. */ - - if (ai->pprefix) { - if (curcc->prefix) - ai->pprefix[pfxlen(ai->pprefix, curcc->prefix)] = '\0'; - else - ai->pprefix[0] = '\0'; - } else - ai->pprefix = dupstring(curcc->prefix ? curcc->prefix : ""); - - /* Generate the prefix to insert for ambiguous completions. */ - t = s; - if (lppre) - t = dyncat(lppre, t); - if (!ispattern && !ms && mstack) { - Cline *clp = &lc, tlc; - char *ss = dupstring(s), *ee = e + (ss - s); - - DPUTS(e < s || e > s + sl, "BUG: invalid end-pointer (e)"); - - if (lppre && *lppre) { - *clp = str_cline(lppre, strlen(lppre), &tlc); - clp = &(tlc->next); - } - if (pl) { - *clp = str_cline(ss, pl, &tlc); - clp = &(tlc->next); - } - if (ee != ss + sl || (lpsuf && *lpsuf)) { - *clp = tlc = getcline(ss + pl, (ee - ss) - pl, NULL, 0, CLF_MID); - clp = &(tlc->next); - if (ee != ss + sl) { - *clp = str_cline(ee, (ss + sl) - ee, &tlc); - clp = &(tlc->next); - } - if (lpsuf && *lpsuf) { - *clp = str_cline(lpsuf, strlen(lpsuf), &tlc); - clp = &(tlc->next); - } - } else { - *clp = tlc = getcline(NULL, 0, ss + pl, sl - pl, - CLF_END | CLF_VAR); - clp = &(tlc->next); - } - *clp = NULL; - } - if (ipre && *ipre) { - Cline tlc = prepend_cline(ipre, lc); - - ai->noipre = 0; - if (!ms && !mstack) { - ai->icpl = lppl + mpl; - ai->icsl = lpsl + msl; - if (ai->iaprefix) - ai->iaprefix[pfxlen(ai->iaprefix, t)] = '\0'; - else - ai->iaprefix = dupstring(t); - } else - ai->ilinecl = join_clines(ai->ilinecl, lc); - if (ai->iprefix) { - if (strcmp(ipre, ai->iprefix)) - ai->iprefix = ""; - } else - ai->iprefix = dupstring(ipre); - - t = dyncat(ipre, t); - lc = tlc; - } else - ai->iprefix = ""; - - if (!ms && !mstack) { - ai->cpl = lppl + mpl; - ai->csl = lpsl + msl; - if (ai->aprefix) - ai->aprefix[pfxlen(ai->aprefix, t)] = '\0'; - else - ai->aprefix = dupstring(t); - } else - ai->linecl = join_clines(ai->linecl, lc); - - mnum++; - ai->count++; - - /* Allocate and fill the match structure. */ - cm = (Cmatch) zhalloc(sizeof(struct cmatch)); - if (ispattern) { - if (lpsuf && *lpsuf && strsfx(lpsuf, s)) { - s[sl - lpsl] = '\0'; - cm->psuf = lpsuf; - } else - cm->psuf = NULL; - - if (lppre && *lppre && strpfx(lppre, s)) { - s += lppl; - cm->ppre = lppre; - cm->prpre = (isf && prpre && *prpre ? prpre : NULL); - } else - cm->ppre = cm->prpre = NULL; - } else { - cm->ppre = (lppre && *lppre ? lppre : NULL); - cm->psuf = (lpsuf && *lpsuf ? lpsuf : NULL); - cm->prpre = (isf && prpre && *prpre ? prpre : NULL); - } - cm->str = (ms ? ms : s); - cm->ipre = (ipre && *ipre ? ipre : NULL); - cm->ripre = (ripre && *ripre ? ripre : NULL); - if (incompfunc) { - cm->pre = dupstring(curcc->prefix); - cm->suf = dupstring(curcc->suffix); - } else { - cm->pre = curcc->prefix; - cm->suf = curcc->suffix; - } - cm->flags = mflags | isf; - cm->brpl = bpl; - cm->brsl = bsl; - cm->rems = cm->remf = NULL; - addlinknode(l, cm); - - /* One more match for this explanation. */ - if (expl) { - if (l == matches) - expl->count++; - else - expl->fcount++; - } - if (!ms) { - if (!ai->firstm) - ai->firstm = cm; - - /* Do we have an exact match? More than one? */ - if (!ispattern && !(e - (s + pl))) { - if (!ai->exact) { - ai->exact = 1; - if (incompfunc) { - int lpl = (cm->ppre ? strlen(cm->ppre) : 0); - int lsl = (cm->psuf ? strlen(cm->psuf) : 0); - - zsfree(compexactstr); - compexactstr = e = (char *) zalloc(lpl + sl + lsl + 1); - if (cm->ppre) { - strcpy(e, cm->ppre); - e += lpl; - } - strcpy(e, s); - e += sl; - if (cm->psuf) - strcpy(e, cm->psuf); - comp_setunsetptr(CP_EXACTSTR, 0); - } - } else { - ai->exact = 2; - cm = NULL; - if (incompfunc) - comp_setunsetptr(0, CP_EXACTSTR); - } - ai->exactm = cm; - } - } + add_match_data(isalt, ms, lc, ipre, ripre, isuf, + (incompfunc ? dupstring(curcc->prefix) : curcc->prefix), + prpre, + (isfile ? lppre : NULL), + (isfile ? lpsuf : NULL), + (incompfunc ? dupstring(curcc->suffix) : curcc->suffix), + bpl, bsl, (mflags | isfile), isexact); } #ifdef HAVE_NIS_PLUS @@ -5011,9 +3950,10 @@ gen_matches_files(int dirs, int execs, int all) strcpy(p + o, psuf); /* Do we have to use globbing? */ - if (ispattern || (ns && comppatmatch && *comppatmatch)) { + if (ispattern || + (ns && comppatmatch && *comppatmatch)) { /* Yes, so append a `*' if needed. */ - if (ns) { + if (ns && comppatmatch && *comppatmatch == '*') { int tl = strlen(p); p[tl] = Star; @@ -5068,7 +4008,9 @@ docompletion(char *s, int lst, int incmd) ((isset(AUTOLIST) && !isset(BASHAUTOLIST)) ? (isset(LISTAMBIGUOUS) ? 3 : 2) : 0) : 1); zsfree(comppatmatch); - opm = comppatmatch = ztrdup(useglob ? "yes" : ""); + opm = comppatmatch = ztrdup(useglob ? "*" : ""); + zsfree(comppatinsert); + comppatinsert = ztrdup("menu"); zsfree(compforcelist); compforcelist = ztrdup(""); haspattern = 0; @@ -5173,7 +4115,7 @@ callcompfunc(char *s, char *fn) compparameter = compredirect = ""; if (ispar) compcontext = (ispar == 2 ? "brace_parameter" : "parameter"); - else if (inwhat == IN_MATH) { + else if (linwhat == IN_MATH) { if (insubscr) { compcontext = "subscript"; if (varname) { @@ -5195,7 +4137,7 @@ callcompfunc(char *s, char *fn) compredirect = rdstr; set |= CP_REDIRECT; } else - switch (inwhat) { + switch (linwhat) { case IN_ENV: compcontext = "array_value"; compparameter = varname; @@ -5263,20 +4205,20 @@ callcompfunc(char *s, char *fn) zsfree(compprefix); zsfree(compsuffix); if (unset(COMPLETEINWORD)) { - if (inwhat == IN_MATH) + if (linwhat == IN_MATH) tmp = s; else - tmp = quotename(s, NULL, NULL, NULL); + tmp = quotename(s, NULL); untokenize(tmp); compprefix = ztrdup(tmp); compsuffix = ztrdup(""); } else { char *ss = s + offs, sav; - if (inwhat == IN_MATH) + if (linwhat == IN_MATH) tmp = s; else - tmp = quotename(s, &ss, NULL, NULL); + tmp = quotename(s, &ss); sav = *ss; *ss = '\0'; untokenize(tmp); @@ -5287,6 +4229,8 @@ callcompfunc(char *s, char *fn) } zsfree(compiprefix); compiprefix = ztrdup(""); + zsfree(compisuffix); + compisuffix = ztrdup(""); compcurrent = (usea ? (clwpos + 1 - aadd) : 0); compnmatches = mnum; @@ -5411,6 +4355,8 @@ makecomplist(char *s, int incmd, int lst) } else compmatcher = 0; + linwhat = inwhat; + /* Walk through the global matchers. */ for (;;) { bmatchers = NULL; @@ -5432,16 +4378,14 @@ makecomplist(char *s, int incmd, int lst) ainfo = (Aminfo) hcalloc(sizeof(struct aminfo)); fainfo = (Aminfo) hcalloc(sizeof(struct aminfo)); - ainfo->minlen = ainfo->suflen = - fainfo->minlen = fainfo->suflen = 10000; - ainfo->noipre = fainfo->noipre= 1; - freecl = NULL; if (!validlist) lastambig = 0; amatches = 0; mnum = 0; + unambig_mnum = -1; + isuf = NULL; begcmgroup("default", 0); ccused = newlinklist(); @@ -5529,9 +4473,9 @@ comp_str(int *ipl, int *pl, int untok) ctokenize(ip); remnulargs(ip); } + lp = strlen(p); ls = strlen(s); lip = strlen(ip); - lp = strlen(p); str = zhalloc(lip + lp + ls + 1); strcpy(str, ip); strcat(str, p); @@ -5555,12 +4499,17 @@ makecomplistcall(Compctl cc) HEAPALLOC { int ooffs = offs, lip, lp; char *str = comp_str(&lip, &lp, 0); + char *oisuf = isuf; + isuf = dupstring(compisuffix); + ctokenize(isuf); + remnulargs(isuf); offs = lip + lp; cc->refc++; ccont = 0; makecomplistor(cc, str, lincmd, lip, 0); offs = ooffs; + isuf = oisuf; compnmatches = mnum; } LASTALLOC; } SWITCHBACKHEAPS; @@ -5591,7 +4540,11 @@ makecomplistctl(int flags) char *str = comp_str(&lip, &lp, 0), *t; char *os = cmdstr, **ow = clwords, **p, **q; int on = clwnum, op = clwpos; + char *oisuf = isuf; + isuf = dupstring(compisuffix); + ctokenize(isuf); + remnulargs(isuf); clwnum = arrlen(compwords); clwpos = compcurrent - 1; cmdstr = ztrdup(compwords[0]); @@ -5607,6 +4560,7 @@ makecomplistctl(int flags) incompfunc = 2; ret = makecomplistglobal(str, !clwpos, COMP_COMPLETE, flags); incompfunc = 1; + isuf = oisuf; offs = ooffs; compnmatches = mnum; zsfree(cmdstr); @@ -5634,15 +4588,15 @@ makecomplistglobal(char *os, int incmd, int lst, int flags) ccont = CC_CCCONT; - if (inwhat == IN_ENV) { + if (linwhat == IN_ENV) { /* Default completion for parameter values. */ cc = &cc_default; - } else if (inwhat == IN_MATH) { + } else if (linwhat == IN_MATH) { /* Parameter names inside mathematical expression. */ cc_dummy.mask = CC_PARAMS; cc = &cc_dummy; cc_dummy.refc = 10000; - } else if (inwhat == IN_COND) { + } else if (linwhat == IN_COND) { /* We try to be clever here: in conditions we complete option * * names after a `-o', file names after `-nt', `-ot', and `-ef' * * and file names and parameter names elsewhere. */ @@ -6206,9 +5160,10 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) if (ispattern) { /* The word should be treated as a pattern, so compute the matcher. */ - p = (char *)ncalloc(rpl + rsl + 2); + p = (char *) zhalloc(rpl + rsl + 2); strcpy(p, rpre); - if (rpl && p[rpl - 1] != Star) { + if (rpl && p[rpl - 1] != Star && + (!comppatmatch || *comppatmatch == '*')) { p[rpl] = Star; strcpy(p + rpl + 1, rsuf); } else @@ -6294,9 +5249,10 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) /* We have to use globbing, so compute the pattern from * * the file prefix and suffix with a `*' between them. */ - p = (char *)ncalloc((t2 = strlen(fpre)) + strlen(fsuf) + 2); + p = (char *) zhalloc((t2 = strlen(fpre)) + strlen(fsuf) + 2); strcpy(p, fpre); - if ((!t2 || p[t2 - 1] != Star) && *fsuf != Star) + if ((!t2 || p[t2 - 1] != Star) && *fsuf != Star && + (!comppatmatch || *comppatmatch == '*')) p[t2++] = Star; strcpy(p + t2, fsuf); filecomp = parsereg(p); @@ -6340,7 +5296,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) opts[NULLGLOB] = 1; addwhat = 0; - p = (char *)zhalloc(lpl + lsl + 3); + p = (char *) zhalloc(lpl + lsl + 3); strcpy(p, lpre); if (*lsuf != '*' && *lpre && lpre[lpl - 1] != '*') strcat(p, "*"); @@ -6888,9 +5844,9 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) void invalidatelist(void) { - if(showinglist == -2) + if (showinglist == -2) listmatches(); - if(validlist) + if (validlist) freematches(); lastambig = menucmp = validlist = showinglist = fromcomp = 0; menucur = NULL; @@ -6930,7 +5886,7 @@ get_user_var(char *nam) notempty = 0; } else { notempty = 1; - if(*ptr == Meta) + if (*ptr == Meta) ptr++; } if (brk) @@ -6939,7 +5895,7 @@ get_user_var(char *nam) if (!brk || !count) return NULL; *ptr = '\0'; - aptr = uarr = (char **)ncalloc(sizeof(char *) * (count + 1)); + aptr = uarr = (char **) zhalloc(sizeof(char *) * (count + 1)); while ((*aptr++ = (char *)ugetnode(arrlist))); uarr[count] = NULL; @@ -6952,7 +5908,7 @@ get_user_var(char *nam) return (incompfunc ? arrdup(arr) : arr); if ((val = getsparam(nam))) { - arr = (char **)ncalloc(2*sizeof(char *)); + arr = (char **) zhalloc(2*sizeof(char *)); arr[0] = (incompfunc ? dupstring(val) : val); arr[1] = NULL; } @@ -7021,8 +5977,8 @@ makearray(LinkList l, int s, int *np, int *nlp) int n, nl = 0; /* Build an array for the matches. */ - rp = ap = (Cmatch *)ncalloc(((n = countlinknodes(l)) + 1) * - sizeof(Cmatch)); + rp = ap = (Cmatch *) ncalloc(((n = countlinknodes(l)) + 1) * + sizeof(Cmatch)); /* And copy them into it. */ for (nod = firstnode(l); nod; incnode(nod)) @@ -7156,6 +6112,7 @@ dupmatch(Cmatch m) r->str = ztrdup(m->str); r->ipre = ztrdup(m->ipre); r->ripre = ztrdup(m->ripre); + r->isuf = ztrdup(m->isuf); r->ppre = ztrdup(m->ppre); r->psuf = ztrdup(m->psuf); r->prpre = ztrdup(m->prpre); @@ -7272,6 +6229,7 @@ freematch(Cmatch m) zsfree(m->str); zsfree(m->ipre); zsfree(m->ripre); + zsfree(m->isuf); zsfree(m->ppre); zsfree(m->psuf); zsfree(m->pre); @@ -7325,14 +6283,323 @@ freematches(void) } } +/* Insert the given string into the command line. If move is non-zero, * + * the cursor position is changed and len is the length of the string * + * to insert (if it is -1, the length is calculated here). */ + +/**/ +static void +inststrlen(char *str, int move, int len) +{ + if (!len || !str) + return; + if (len == -1) + len = strlen(str); + spaceinline(len); + strncpy((char *)(line + cs), str, len); + if (move) + cs += len; +} + +/* This builds the unambiguous string. If ins is non-zero, it is + * immediatly inserted in the line. Otherwise csp is used to return + * the relative cursor position in the string returned. */ + +static char * +cline_str(Cline l, int ins, int *csp) +{ + Cline s; + int ocs = cs, ncs, pcs, pm, sm, d, b, i, j, li = 0; + int pl, sl, hasp, hass, ppos, spos, plen, slen; + + ppos = spos = plen = slen = hasp = hass = 0; + pm = sm = d = b = pl = sl = -1; + + /* Get the information about the brace beginning and end we have + * to re-insert. */ + if (ins) { + if ((hasp = (brbeg && *brbeg))) { + plen = strlen(brbeg); pl = brpl; + } + if ((hass = (brend && *brend))) { + slen = strlen(brend); sl = we - wb - brsl - plen - slen + 1; + } + if (!pl) { + inststrlen(brbeg, 1, -1); + pl = -1; hasp = 0; + } + if (!sl) { + inststrlen(brend, 1, -1); + sl = -1; hass = 0; + } + } + /* Walk through the top-level cline list. */ + while (l) { + if (pl >= 0) + ppos = -1; + if (sl >= 0) + spos = -1; + /* Insert the original string if no prefix. */ + if (l->olen && !(l->flags & CLF_SUF) && !l->prefix) { + inststrlen(l->orig, 1, l->olen); + if (ins) { + li += l->olen; + if (pl >= 0 && li >= pl) { + ppos = cs - (li - pl); pl = -1; + } + if (sl >= 0 && li >= sl) { + spos = cs - (li - sl) - 1; sl = -1; + } + } + } else { + /* Otherwise insert the prefix. */ + for (s = l->prefix; s; s = s->next) { + pcs = cs; + if (s->flags & CLF_LINE) + inststrlen(s->line, 1, s->llen); + else + inststrlen(s->word, 1, s->wlen); + if (d < 0 && (s->flags & CLF_DIFF)) + d = cs; + if (ins) { + li += s->llen; + if (pl >= 0 && li >= pl) { + ppos = pcs + s->llen - (li - pl); pl = -1; + } + if (sl >= 0 && li >= sl) { + spos = pcs + s->llen - (li - sl) - 1; sl = -1; + } + } + } + } + /* Remember the position if this is the first prefix with + * missing characters. */ + if (pm < 0 && (l->flags & CLF_MISS) && !(l->flags & CLF_SUF)) + pm = cs; + pcs = cs; + /* Insert the anchor. */ + if (l->flags & CLF_LINE) + inststrlen(l->line, 1, l->llen); + else + inststrlen(l->word, 1, l->wlen); + if (ins) { + li += l->llen; + if (pl >= 0 && li >= pl) { + ppos = pcs + l->llen - (li - pl); pl = -1; + } + if (sl >= 0 && li >= sl) { + spos = pcs + l->llen - (li - sl) - 1; sl = -1; + } + } + /* Remember the cursor position for suffixes and mids. */ + if (l->flags & CLF_MISS) { + if (l->flags & CLF_MID) + b = cs; + else if (sm < 0 && (l->flags & CLF_SUF)) + sm = cs; + } + /* And now insert the suffix or the original string. */ + if (l->olen && (l->flags & CLF_SUF) && !l->suffix) { + pcs = cs; + inststrlen(l->orig, 1, l->olen); + if (ins) { + li += l->olen; + if (pl >= 0 && li >= pl) { + ppos = pcs + l->olen - (li - pl); pl = -1; + } + if (sl >= 0 && li >= sl) { + spos = pcs + l->olen - (li - sl) - 1; sl = -1; + } + } + } else { + int hp = 0, hs = 0; + + for (j = -1, i = 0, s = l->suffix; s; s = s->next) { + if (j < 0 && (s->flags & CLF_DIFF)) + j = i; + if (s->flags & CLF_LINE) { + inststrlen(s->line, 0, s->llen); + i += s->llen; pcs = cs + s->llen; + } else { + inststrlen(s->word, 0, s->wlen); + i += s->wlen; pcs = cs + s->wlen; + } + if (ins) { + li += s->llen; + if (pl >= 0 && li >= pl) { + hp = 1; ppos = pcs - (li - pl) - i; pl = -1; + } + if (sl >= 0 && li >= sl) { + hs = 1; spos = pcs - (li - sl) - i; sl = -1; + } + } + } + if (hp) + ppos += i; + if (hs) + spos += i; + cs += i; + if (d < 0 && j >= 0) + d = cs - j; + } + /* If we reached the right positions, re-insert the braces. */ + if (ins) { + if (hasp && ppos >= 0) { + i = cs; + cs = ppos; + inststrlen(brbeg, 1, plen); + cs = i + plen; + hasp = 0; + } + if (hass && spos >= 0) { + i = cs; + cs = spos; + inststrlen(brend, 1, slen); + cs = i + slen; + hass = 0; + } + } + l = l->next; + } + if (pl >= 0) + inststrlen(brbeg, 1, plen); + if (sl >= 0) + inststrlen(brend, 1, slen); + + /* This calculates the new cursor position. If we had a mid cline + * with missing characters, we take this, otherwise if we have a + * prefix with missing characters, we take that, the same for a + * suffix, and finally a place where the matches differ. */ + ncs = (b >= 0 ? b : (pm >= 0 ? pm : (sm >= 0 ? sm : (d >= 0 ? d : cs)))); + + if (!ins) { + /* We always inserted the string in the line. If that was not + * requested, we copy it and remove from the line. */ + char *r = zalloc((i = cs - ocs) + 1); + + memcpy(r, (char *) (line + ocs), i); + r[i] = '\0'; + cs = ocs; + foredel(i); + + *csp = ncs - ocs; + + return r; + } + if (ncs >= ppos) + ncs += plen; + if (ncs > spos) + ncs += slen; + + lastend = cs; + cs = ncs; + + return NULL; +} + +/* This is a utility function using the function above to allow access + * to the unambiguous string and cursor position via compstate. */ + +/**/ +char * +unambig_data(int *cp) +{ + static char *scache = NULL; + static int ccache; + + if (mnum && ainfo) { + if (mnum != unambig_mnum) { + zsfree(scache); + scache = cline_str((ainfo->count ? ainfo->line : fainfo->line), + 0, &ccache); + } + } else { + zsfree(scache); + scache = ztrdup(""); + ccache = 0; + } + unambig_mnum = mnum; + if (cp) + *cp = ccache + 1; + + return scache; +} + +/* Insert the given match. This returns the number of characters inserted.*/ + +/**/ +static int +instmatch(Cmatch m) +{ + int l, r = 0, ocs, a = cs; + + /* Ignored prefix. */ + if (m->ipre) { + inststrlen(m->ipre, 1, (l = strlen(m->ipre))); + r += l; + } + /* -P prefix. */ + if (m->pre) { + inststrlen(m->pre, 1, (l = strlen(m->pre))); + r += l; + } + /* Path prefix. */ + if (m->ppre) { + inststrlen(m->ppre, 1, (l = strlen(m->ppre))); + r += l; + } + /* The string itself. */ + inststrlen(m->str, 1, (l = strlen(m->str))); + r += l; + ocs = cs; + /* Re-insert the brace beginning, if any. */ + 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; + cs = ocs; + } + /* Path suffix. */ + if (m->psuf) { + inststrlen(m->psuf, 1, (l = strlen(m->psuf))); + r += l; + } + /* Re-insert the brace end. */ + if (brend && *brend) { + a = cs; + cs -= m->brsl; + ocs = brscs = cs; + l = strlen(brend); + inststrlen(brend, 1, l); + r += l; + cs = a + l; + } else + brscs = -1; + /* -S suffix */ + if (m->suf) { + inststrlen(m->suf, 1, (l = strlen(m->suf))); + r += l; + } + /* ignored suffix */ + if (m->isuf) { + inststrlen(m->isuf, 1, (l = strlen(m->isuf))); + r += l; + } + lastend = cs; + cs = ocs; + + return r; +} + /* Handle the case were we found more than one match. */ /**/ static void do_ambiguous(void) { - int p = (usemenu || haspattern), atend = (cs == we); - menucmp = 0; /* If we have to insert the first match, call do_single(). This is * @@ -7349,22 +6616,17 @@ do_ambiguous(void) * unambiguous prefix. */ lastambig = 1; - if (p) { - /* p is set if we are in a position to start using menu completion * - * due to one of the menu completion options, or due to the * - * menu-complete-word command, or due to using GLOB_COMPLETE which * - * does menu-style completion regardless of the setting of the * - * normal menu completion options. */ + if (usemenu || (haspattern && comppatinsert && + !strcmp(comppatinsert, "menu"))) { + /* We are in a position to start using menu completion due to one * + * of the menu completion options, or due to the menu-complete- * + * word command, or due to using GLOB_COMPLETE which does menu- * + * style completion regardless of the setting of the normal menu * + * completion options. */ do_ambig_menu(); - } else { + } else if (ainfo) { + int atend = (cs == we), oll = ll, la; VARARR(char, oline, ll); - int sl = 0, oll = ll; - int ocs, pl = 0, l, lp, ls, la = 0; - char *ps; - Cline lc; - - if (!ainfo) - return; /* Copy the line buffer to be able to easily test if it changed. */ memcpy(oline, line, ll); @@ -7375,69 +6637,9 @@ do_ambiguous(void) cs = wb; foredel(we - wb); - /* Sort-of general case: we have an ambiguous completion, and aren't * - * starting menu completion or doing anything really weird. We need * - * to insert any unambiguous prefix and suffix, if possible. */ - - if (ainfo->iprefix && *ainfo->iprefix) { - inststrlen(ainfo->iprefix, 1, -1); - inststrlen(ainfo->pprefix, 1, -1); - ps = ainfo->iaprefix; - lc = ainfo->ilinecl; - lp = ainfo->icpl; - ls = ainfo->icsl; - } else { - if (ainfo->noipre && ainfo->pprefix) { - pl = strlen(ainfo->pprefix); - inststrlen(ainfo->pprefix, 1, pl); - } - ps = ainfo->aprefix; - lc = ainfo->linecl; - lp = ainfo->cpl; - ls = ainfo->csl; - } - if (lc) { - if (!ps) - ps = ""; - if (lp) { - if (ls) { - DPUTS(!ainfo->firstm, "BUG: merge without firtsm"); - if (ainfo->firstm->psuf) - merge_cline(lc, ps, lp, - dyncat(ainfo->firstm->str, - ainfo->firstm->psuf), - ls, (sl = strlen(ainfo->firstm->psuf))); - else - merge_cline(lc, ps, lp, ainfo->firstm->str, ls, 0); - } else - merge_cline(lc, ps, lp, NULL, 0, 0); - } - inst_cline(lc, pl, sl); - } else { - inststrlen(ps, 1, -1); - ocs = cs; - if (brbeg && *brbeg) { - cs = wb + brpl + pl; - l = strlen(brbeg); - inststrlen(brbeg, 1, l); - ocs += l; - cs = ocs; - } - if(ainfo->suflen && !atend) { - DPUTS(!ainfo->firstm, "BUG: suffix without firstm"); - inststrlen(ainfo->firstm->str + - strlen(ainfo->firstm->str) - ainfo->suflen, 1, - ainfo->suflen); - } - if (ainfo->firstm && ainfo->firstm->psuf) - inststrlen(ainfo->firstm->psuf, 0, -1); - if (brend && *brend) { - cs -= brsl; - inststrlen(brend, 1, -1); - } - lastend = cs; - cs = ocs; - } + /* Now get the unambiguous string and insert it into the line. */ + cline_str(ainfo->line, 1, NULL); + /* la is non-zero if listambiguous may be used. Copying and * comparing the line looks like BFI but it is the easiest * solution. Really. */ @@ -7451,8 +6653,7 @@ do_ambiguous(void) fromcomp = ((isset(AUTOMENU) ? FC_LINE : 0) | ((atend && cs != lastend) ? FC_INWORD : 0)); - /* - * If the LIST_AMBIGUOUS option (meaning roughly `show a list only * + /* If the LIST_AMBIGUOUS option (meaning roughly `show a list only * * if the completion is completely ambiguous') is set, and some * * prefix was inserted, return now, bypassing the list-displaying * * code. On the way, invalidate the list and note that we don't * @@ -7463,9 +6664,12 @@ do_ambiguous(void) invalidatelist(); fromcomp = fc; lastambig = 0; + clearlist = 1; return; } - } + } else + return; + /* At this point, we might want a completion listing. Show the listing * * if it is needed. */ if (isset(LISTBEEP)) @@ -7503,9 +6707,8 @@ ztat(char *nam, struct stat *buf, int ls) static void do_single(Cmatch m) { - int l; + int l, sr = 0; int havesuff = 0; - char *str = m->str, *ppre = m->ppre, *psuf = m->psuf, *prpre = m->prpre; if (!prpre) prpre = ""; @@ -7553,7 +6756,7 @@ do_single(Cmatch m) } else { /* There is no user-specified suffix, * * so generate one automagically. */ - if(m->ripre && (m->flags & CMF_PARBR)) { + if (m->ripre && (m->flags & CMF_PARBR)) { /*{{*/ /* Completing a parameter in braces. Add a removable `}' suffix. */ inststrlen("}", 1, 1); @@ -7561,48 +6764,20 @@ do_single(Cmatch m) if (menuwe) menuend++; } - if((m->flags & CMF_FILE) || (m->ripre && isset(AUTOPARAMSLASH))) { + if ((m->flags & CMF_FILE) || (m->ripre && isset(AUTOPARAMSLASH))) { /* If we have a filename or we completed a parameter name * * and AUTO_PARAM_SLASH is set, lets see if it is a directory. * * If it is, we append a slash. */ - char *p; struct stat buf; + char *p; /* Build the path name. */ - if (haspattern || ic || m->ripre) { - int ne = noerrs; - - noerrs = 1; - - if (m->ripre) { - int pl = strlen(m->ripre); - - p = (char *) ncalloc(pl + strlen(str) + strlen(psuf) + 1); - sprintf(p, "%s%s%s", m->ripre, str, psuf); - if (pl && p[pl-1] == Inbrace) - strcpy(p+pl-1, p+pl); - } else if (ic) { - p = (char *) ncalloc(strlen(ppre) + strlen(str) + - strlen(psuf) + 2); - sprintf(p, "%c%s%s%s", ic, ppre, str, psuf); - } else { - p = (char *) ncalloc(strlen(ppre) + strlen(str) + - strlen(psuf) + 1); - sprintf(p, "%s%s%s", ppre, str, psuf); - } - parsestr(p); - if (ic) - *p = ic; - singsub(&p); + p = (char *) zhalloc(strlen(prpre) + strlen(str) + + strlen(psuf) + 3); + sprintf(p, "%s%s%s", (prpre && *prpre) ? prpre : "./", str, psuf); - noerrs = ne; - } else { - p = (char *) ncalloc(strlen(prpre) + strlen(str) + - strlen(psuf) + 3); - sprintf(p, "%s%s%s", (prpre && *prpre) ? prpre : "./", str, psuf); - } /* And do the stat. */ - if (!ztat(p, &buf, 0) && S_ISDIR(buf.st_mode)) { + if (!(sr = ztat(p, &buf, 0)) && S_ISDIR(buf.st_mode)) { /* It is a directory, so add the slash. */ havesuff = 1; inststrlen("/", 1, 1); @@ -7632,12 +6807,13 @@ do_single(Cmatch m) inststrlen(",", 1, 1); menuinsc++; makesuffix(1); - if (menuwe && isset(AUTOPARAMKEYS)) + if ((!menucmp || menuwe) && isset(AUTOPARAMKEYS)) suffixlen[','] = suffixlen['}'] = 1; } - } else if (!menucmp && !havesuff) { + } else if (!menucmp && !havesuff && (!(m->flags & CMF_FILE) || !sr)) { /* If we didn't add a suffix, add a space, unless we are * - * doing menu completion. */ + * doing menu completion or we are completing files and * + * the string doesn't name an existing file. */ inststrlen(" ", 1, 1); menuinsc++; if (menuwe) @@ -7680,7 +6856,7 @@ pfxlen(char *s, char *t) /* Return the length of the common suffix of s and t. */ -/**/ +#if 0 static int sfxlen(char *s, char *t) { @@ -7695,6 +6871,7 @@ sfxlen(char *s, char *t) } else return 0; } +#endif /* This is used to print the explanation string. * * It returns the number of lines printed. */ @@ -7798,7 +6975,7 @@ listmatches(void) #ifdef DEBUG /* Sanity check */ - if(!validlist) { + if (!validlist) { showmsg("BUG: listmatches called with bogus list"); return; } @@ -8199,7 +7376,7 @@ processcmd(void) inststr(" "); untokenize(s); HEAPALLOC { - inststr(quotename(s, NULL, NULL, NULL)); + inststr(quotename(s, NULL)); } LASTALLOC; zsfree(s); done = 1; diff --git a/Src/glob.c b/Src/glob.c index 56e0ac133..f8fd2aa4a 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -583,7 +583,7 @@ compalloc(void) /**/ static int -getglobflags() +getglobflags(void) { char *nptr; /* (#X): assumes we are still positioned on the initial '(' */ diff --git a/Src/init.c b/Src/init.c index f3576aadd..9fc4a81fb 100644 --- a/Src/init.c +++ b/Src/init.c @@ -757,25 +757,43 @@ run_init_scripts(void) source(GLOBAL_ZSHENV); #endif if (isset(RCS)) { + int globalfirst = isset(GLOBALRCSFIRST); + if (globalfirst) { +#ifdef GLOBAL_ZPROFILE + if (islogin) + source(GLOBAL_ZPROFILE); +#endif +#ifdef GLOBAL_ZSHRC + if (interact) + source(GLOBAL_ZSHRC); +#endif +#ifdef GLOBAL_ZLOGIN + if (islogin) + source(GLOBAL_ZLOGIN); +#endif + } if (unset(PRIVILEGED)) sourcehome(".zshenv"); if (islogin) { #ifdef GLOBAL_ZPROFILE - source(GLOBAL_ZPROFILE); + if (!globalfirst) + source(GLOBAL_ZPROFILE); #endif if (unset(PRIVILEGED)) sourcehome(".zprofile"); } if (interact) { #ifdef GLOBAL_ZSHRC - source(GLOBAL_ZSHRC); + if (!globalfirst) + source(GLOBAL_ZSHRC); #endif if (unset(PRIVILEGED)) sourcehome(".zshrc"); } if (islogin) { #ifdef GLOBAL_ZLOGIN - source(GLOBAL_ZLOGIN); + if (!globalfirst) + source(GLOBAL_ZLOGIN); #endif if (unset(PRIVILEGED)) sourcehome(".zlogin"); diff --git a/Src/options.c b/Src/options.c index bfe146e1e..9010831c0 100644 --- a/Src/options.c +++ b/Src/options.c @@ -114,6 +114,7 @@ static struct optname optns[] = { {NULL, "flowcontrol", OPT_ALL, FLOWCONTROL}, {NULL, "functionargzero", OPT_EMULATE|OPT_NONBOURNE, FUNCTIONARGZERO}, {NULL, "glob", OPT_ALL, GLOBOPT}, +{NULL, "globalrcsfirst", 0, GLOBALRCSFIRST}, {NULL, "globassign", OPT_EMULATE|OPT_CSH, GLOBASSIGN}, {NULL, "globcomplete", 0, GLOBCOMPLETE}, {NULL, "globdots", 0, GLOBDOTS}, @@ -228,7 +229,7 @@ static short zshletters[LAST_OPT - FIRST_OPT + 1] = { /* > */ 0, /* ? */ 0, /* @ */ 0, - /* A */ 0, + /* A */ 0, /* use with set for arrays */ /* B */ -BEEP, /* C */ -CLOBBER, /* D */ PUSHDTOHOME, @@ -261,9 +262,9 @@ static short zshletters[LAST_OPT - FIRST_OPT + 1] = { /* _ */ 0, /* ` */ 0, /* a */ ALLEXPORT, - /* b */ 0, - /* c */ 0, - /* d */ 0, + /* b */ 0, /* in non-Bourne shells, end of options */ + /* c */ 0, /* command follows */ + /* d */ GLOBALRCSFIRST, /* e */ ERREXIT, /* f */ -RCS, /* g */ HISTIGNORESPACE, @@ -274,7 +275,7 @@ static short zshletters[LAST_OPT - FIRST_OPT + 1] = { /* l */ LOGINSHELL, /* m */ MONITOR, /* n */ -EXECOPT, - /* o */ 0, + /* o */ 0, /* long option name follows */ /* p */ PRIVILEGED, /* q */ 0, /* r */ RESTRICTED, diff --git a/Src/params.c b/Src/params.c index 7ae6a75ec..dbc6ce8d8 100644 --- a/Src/params.c +++ b/Src/params.c @@ -2709,6 +2709,8 @@ printparamnode(HashNode hn, int printflags) printf("array "); else if (p->flags & PM_HASHED) printf("association "); + if (p->level) + printf("local "); if (p->flags & PM_LEFT) printf("left justified %d ", p->ct); if (p->flags & PM_RIGHT_B) diff --git a/Src/subst.c b/Src/subst.c index 651179b72..c62fcce6b 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -702,7 +702,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) int spbreak = isset(SHWORDSPLIT) && !ssub && !qt; char *val = NULL, **aval = NULL; unsigned int fwidth = 0; - Value v; + Value v = NULL; int flags = 0; int flnum = 0; int sortit = 0, casind = 0; @@ -1828,7 +1828,7 @@ modify(char **str, char **ptr) subst(©, hsubl, hsubr, gbal); break; case 'q': - copy = bslashquote(copy, NULL, NULL, NULL, 0); + copy = bslashquote(copy, NULL, 0); break; } tc = *tt; @@ -1882,7 +1882,7 @@ modify(char **str, char **ptr) } break; case 'q': - *str = bslashquote(*str, NULL, NULL, NULL, 0); + *str = bslashquote(*str, NULL, 0); break; } } diff --git a/Src/utils.c b/Src/utils.c index 3f8177271..12b7fc7eb 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -3140,7 +3140,7 @@ hasspecial(char const *s) /**/ char * -bslashquote(const char *s, char **e, char *te, int *pl, int instring) +bslashquote(const char *s, char **e, int instring) { const char *u, *tt; char *v, buf[PATH_MAX * 2]; @@ -3151,8 +3151,6 @@ bslashquote(const char *s, char **e, char *te, int *pl, int instring) for (; *u; u++) { if (e && *e == u) *e = v, sf |= 1; - if (te == u) - *pl = v - tt, sf |= 2; if (ispecial(*u) && (!instring || (isset(BANGHIST) && *u == (char)bangchar) || @@ -3189,8 +3187,6 @@ bslashquote(const char *s, char **e, char *te, int *pl, int instring) if (e && *e == u) *e = v; - if (te == u) - *pl = v - tt; return (char *) tt; } diff --git a/Src/zsh.h b/Src/zsh.h index d0b566e3f..c3c853dfd 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1085,6 +1085,7 @@ enum { EXTENDEDHISTORY, FLOWCONTROL, FUNCTIONARGZERO, + GLOBALRCSFIRST, GLOBOPT, GLOBASSIGN, GLOBCOMPLETE, |