diff options
Diffstat (limited to 'Src/Zle/computil.c')
-rw-r--r-- | Src/Zle/computil.c | 651 |
1 files changed, 621 insertions, 30 deletions
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c index b5b09e732..42de5c65c 100644 --- a/Src/Zle/computil.c +++ b/Src/Zle/computil.c @@ -127,7 +127,7 @@ static struct cdstate cd_state; static int cd_parsed = 0; static void -free_cdsets(Cdset p) +freecdsets(Cdset p) { Cdset n; @@ -151,7 +151,7 @@ cd_init(char *nam, char *sep, char **args, int disp) if (cd_parsed) { zsfree(cd_state.sep); - free_cdsets(cd_state.sets); + freecdsets(cd_state.sets); } setp = &(cd_state.sets); cd_state.sep = ztrdup(sep); @@ -270,7 +270,7 @@ cd_get(char **params) cd_state.sets = set->next; set->next = NULL; - free_cdsets(set); + freecdsets(set); return 0; } @@ -387,7 +387,7 @@ arrcmp(char **a, char **b) } static void -free_caargs(Caarg a) +freecaargs(Caarg a) { Caarg n; @@ -402,7 +402,7 @@ free_caargs(Caarg a) } static void -free_cadef(Cadef d) +freecadef(Cadef d) { if (d) { Caopt p, n; @@ -415,11 +415,11 @@ free_cadef(Cadef d) zsfree(p->name); zsfree(p->descr); freearray(p->xor); - free_caargs(p->args); + freecaargs(p->args); zfree(p, sizeof(*p)); } - free_caargs(d->args); - free_caargs(d->rest); + freecaargs(d->args); + freecaargs(d->rest); if (d->single) zfree(d->single, 256 * sizeof(Caopt)); zfree(d, sizeof(*d)); @@ -561,7 +561,7 @@ parse_cadef(char *nam, char **args) *p = sav; } if (*p != ')') { - free_cadef(ret); + freecadef(ret); zerrnam(nam, "invalid argument: %s", *args, 0); return NULL; } @@ -599,7 +599,7 @@ parse_cadef(char *nam, char **args) p++; } if (!p[1]) { - free_cadef(ret); + freecadef(ret); zerrnam(nam, "invalid argument: %s", *args, 0); return NULL; } @@ -627,7 +627,7 @@ parse_cadef(char *nam, char **args) p++; if (!*p) { - free_cadef(ret); + freecadef(ret); zerrnam(nam, "invalid option definition: %s", *args, 0); return NULL; } @@ -637,7 +637,7 @@ parse_cadef(char *nam, char **args) descr = NULL; if (c && c != ':') { - free_cadef(ret); + freecadef(ret); zerrnam(nam, "invalid option definition: %s", *args, 0); return NULL; } @@ -667,8 +667,8 @@ parse_cadef(char *nam, char **args) p++; } if (*p != ':') { - free_cadef(ret); - free_caargs(oargs); + freecadef(ret); + freecaargs(oargs); zerrnam(nam, "invalid option definition: %s", *args, 0); return NULL; @@ -726,12 +726,12 @@ parse_cadef(char *nam, char **args) int type = CAA_REST; if (*++p != ':') { - free_cadef(ret); + freecadef(ret); zerrnam(nam, "invalid rest argument definition: %s", *args, 0); return NULL; } if (ret->rest) { - free_cadef(ret); + freecadef(ret); zerrnam(nam, "doubled rest argument definition: %s", *args, 0); return NULL; } @@ -758,7 +758,7 @@ parse_cadef(char *nam, char **args) anum++; if (*p != ':') { - free_cadef(ret); + freecadef(ret); zerrnam(nam, "invalid argument: %s", *args, 0); return NULL; } @@ -773,8 +773,8 @@ parse_cadef(char *nam, char **args) pre = tmp, tmp = tmp->next); if (tmp && tmp->num == anum - 1) { - free_cadef(ret); - free_caargs(arg); + freecadef(ret); + freecaargs(arg); zerrnam(nam, "doubled argument definition: %s", *args, 0); return NULL; } @@ -808,7 +808,7 @@ get_cadef(char *nam, char **args) if (i) min = p; if ((new = parse_cadef(nam, args))) { - free_cadef(*min); + freecadef(*min); *min = new; } return new; @@ -1412,7 +1412,7 @@ struct cvval { static Cvdef cvdef_cache[MAX_CVCACHE]; static void -free_cvdef(Cvdef d) +freecvdef(Cvdef d) { if (d) { Cvval p, n; @@ -1425,7 +1425,7 @@ free_cvdef(Cvdef d) zsfree(p->name); zsfree(p->descr); freearray(p->xor); - free_caargs(p->arg); + freecaargs(p->arg); zfree(p, sizeof(*p)); } zfree(d, sizeof(*d)); @@ -1493,7 +1493,7 @@ parse_cvdef(char *nam, char **args) *p = sav; } if (*p != ')') { - free_cvdef(ret); + freecvdef(ret); zerrnam(nam, "invalid argument: %s", *args, 0); return NULL; } @@ -1514,7 +1514,7 @@ parse_cvdef(char *nam, char **args) p++; if (hassep && !sep && name + 1 != p) { - free_cvdef(ret); + freecvdef(ret); zerrnam(nam, "no multi-letter values with empty separator allowed", NULL, 0); return NULL; } @@ -1525,7 +1525,7 @@ parse_cvdef(char *nam, char **args) p++; if (!*p) { - free_cvdef(ret); + freecvdef(ret); zerrnam(nam, "invalid value definition: %s", *args, 0); return NULL; } @@ -1536,7 +1536,7 @@ parse_cvdef(char *nam, char **args) descr = NULL; } if (c && c != ':') { - free_cvdef(ret); + freecvdef(ret); zerrnam(nam, "invalid value definition: %s", *args, 0); return NULL; } @@ -1549,7 +1549,7 @@ parse_cvdef(char *nam, char **args) } if (c == ':') { if (hassep && !sep) { - free_cvdef(ret); + freecvdef(ret); zerrnam(nam, "no value with argument with empty separator allowed", NULL, 0); return NULL; } @@ -1594,7 +1594,7 @@ get_cvdef(char *nam, char **args) if (i) min = p; if ((new = parse_cvdef(nam, args))) { - free_cvdef(*min); + freecvdef(*min); *min = new; } return new; @@ -1977,12 +1977,592 @@ bin_compquote(char *nam, char **args, char *ops, int func) return 0; } +typedef struct cspat *Cspat; +typedef struct cstyle *Cstyle; + +struct cspat { + Cspat next; + char *pat; + Patprog prog; + int weight; + Cstyle styles, lstyles; +}; + +struct cstyle { + Cstyle next; + char *name; + char **vals; +}; + +/* List of styles. */ + +static Cspat compstyles, lcompstyles; + +static void +freecstyle(Cstyle s) +{ + Cstyle n; + + while (s) { + n = s->next; + + zsfree(s->name); + freearray(s->vals); + zfree(s, sizeof(*s)); + + s = n; + } +} + +static void +freecspat(Cspat p) +{ + Cspat n; + + while (p) { + n = p->next; + + zsfree(p->pat); + freepatprog(p->prog); + zfree(p, sizeof(*p)); + + p = n; + } +} + +static Cspat +getcspat(char *pat) +{ + Cspat p; + + for (p = compstyles; p; p = p->next) + if (!strcmp(pat, p->pat)) + return p; + + return NULL; +} + +static Cstyle +getcstyle(Cspat p, char *name) +{ + Cstyle s; + + for (s = p->styles; s; s= s->next) + if (!strcmp(name, s->name)) + return s; + + return NULL; +} + +static void +setcstyle(Cspat p, char *name, char **vals) +{ + Cstyle s; + + for (s = p->styles; s; s = s->next) + if (!strcmp(name, s->name)) { + freearray(s->vals); + PERMALLOC { + s->vals = arrdup(vals); + } LASTALLOC; + + return; + } + s = (Cstyle) zalloc(sizeof(*s)); + + s->name = ztrdup(name); + PERMALLOC { + s->vals = arrdup(vals); + } LASTALLOC; + s->next = NULL; + + if (p->lstyles) + p->lstyles->next = s; + else + p->styles = s; + p->lstyles = s; +} + +static Cspat +addcspat(char *pat, Patprog prog) +{ + Cspat p, q, qq; + int weight, tmp, first; + char *s; + + for (weight = 0, tmp = 2, first = 1, s = pat; *s; s++) { + if (first && *s == '*' && (!s[1] || s[1] == ':')) { + tmp = 0; + continue; + } + first = 0; + + if (*s == '(' || *s == '|' || *s == '*' || *s == '[' || *s == '<' || + *s == '?' || *s == '#' || *s == '^') + tmp = 1; + + if (*s == ':') { + first = 1; + weight += tmp; + tmp = 2; + } + } + weight += tmp; + + p = (Cspat) zalloc(sizeof(*p)); + + p->pat = ztrdup(pat); + p->weight = weight; + p->prog = prog; + p->styles = p->lstyles = NULL; + + for (qq = NULL, q = compstyles; q && q->weight >= weight; + qq = q, q = q->next); + + p->next = q; + if (qq) + qq->next = p; + else + compstyles = p; + if (!q) + lcompstyles = p; + + return p; +} + +static void +deletecstyle(Cspat p, char *name) +{ + Cstyle ps, s; + + for (ps = NULL, s = p->styles; s; ps = s, s = s->next) + if (!strcmp(name, s->name)) { + if (ps) + ps->next = s->next; + else + p->styles = s->next; + if (s == p->lstyles) + p->lstyles = ps; + + s->next = NULL; + freecstyle(s); + + return; + } +} + +static void +deletecspat(Cspat pat) +{ + Cspat pp, p; + + for (pp = NULL, p = compstyles; p; pp = p, p = p->next) + if (p == pat) { + if (pp) + pp->next = p->next; + else + compstyles = p->next; + if (p == lcompstyles) + lcompstyles = pp; + + p->next = NULL; + zsfree(p->pat); + freepatprog(p->prog); + freecstyle(p->styles); + zfree(p, sizeof(*p)); + + return; + } +} + +static Cstyle +lookupcstyle(char *ctxt, char *style) +{ + Cspat p; + Cstyle s; + + for (p = compstyles; p; p = p->next) + if (pattry(p->prog, ctxt)) + for (s = p->styles; s; s = s->next) + if (!strcmp(style, s->name)) + return s; + + return NULL; +} + +static int +bin_compstyles(char *nam, char **args, char *ops, int func) +{ + int min, max, n; + + if (args[0][0] != '-' || !args[0][1] || args[0][2]) { + zerrnam(nam, "invalid argument: %s", args[0], 0); + return 1; + } + switch (args[0][1]) { + case 'a': min = 3; max = -1; break; + case 'd': min = 0; max = 2; break; + case 'S': min = 3; max = 3; break; + case 'A': min = 3; max = 3; break; + case 'H': min = 3; max = 3; break; + case 'T': min = 2; max = 2; break; + case 'G': min = 1; max = 3; break; + default: + zerrnam(nam, "invalid option: %s", args[0], 0); + return 1; + } + n = arrlen(args) - 1; + if (n < min) { + zerrnam(nam, "not enough arguments", NULL, 0); + return 1; + } else if (max >= 0 && n > max) { + zerrnam(nam, "too many arguments", NULL, 0); + return 1; + } + switch (args[0][1]) { + case 'a': + { + Cspat p; + + if (!(p = getcspat(args[1]))) { + Patprog prog; + char *pat = dupstring(args[1]); + + tokenize(pat); + + if (!(prog = patcompile(pat, PAT_ZDUP, NULL))) { + zerrnam(nam, "invalid pattern: %s", args[1], 0); + return 1; + } + p = addcspat(args[1], prog); + } + setcstyle(p, args[2], args + 3); + } + break; + case 'd': + { + Cspat p; + + if (args[1]) { + if ((p = getcspat(args[1]))) { + if (args[2]) { + deletecstyle(p, args[2]); + if (!p->styles) + deletecspat(p); + } else + deletecspat(p); + } + } else { + freecspat(compstyles); + compstyles = lcompstyles = NULL; + } + } + break; + case 'S': + { + Cstyle s; + char *ret; + int val; + + if ((s = lookupcstyle(args[1], args[2])) && s->vals[0]) { + PERMALLOC { + ret = sepjoin(s->vals, NULL); + } LASTALLOC; + val = 0; + } else { + ret = ztrdup(""); + val = 1; + } + setsparam(args[3], ret); + + return val; + } + break; + case 'A': + case 'H': + { + Cstyle s; + char **ret; + int val; + + if ((s = lookupcstyle(args[1], args[2]))) { + PERMALLOC { + ret = arrdup(s->vals); + } LASTALLOC; + val = 0; + } else { + char *dummy = NULL; + + PERMALLOC { + ret = arrdup(&dummy); + } LASTALLOC; + val = 1; + } + if (args[0][1] == 'A') + setaparam(args[3], ret); + else + sethparam(args[3], ret); + + return val; + } + break; + case 'T': + return !lookupcstyle(args[1], args[2]); + case 'G': + { + LinkList l = newlinklist(); + int ret = 1; + Cspat p; + + if (args[2]) { + if ((p = getcspat(args[2]))) { + Cstyle s; + + if (args[3]) { + if ((s = getcstyle(p, args[3]))) { + char **v = s->vals; + + while (*v) + addlinknode(l, *v++); + + ret = 0; + } + } else { + for (s = p->styles; s; s = s->next) + addlinknode(l, s->name); + + ret = 0; + } + } + } else { + for (p = compstyles; p; p = p->next) + addlinknode(l, p->pat); + + ret = 0; + } + set_list_array(args[1], l); + + return ret; + } + } + return 0; +} + +typedef struct ctags *Ctags; +typedef struct ctset *Ctset; + +struct ctags { + char **all; + char *context; + int init; + Ctset sets; +}; + +struct ctset { + Ctset next; + char **tags; +}; + +/* Array of tag-set infos. Index is the locallevel. */ + +#define MAX_TAGS 256 +static Ctags comptags[MAX_TAGS]; + +/* locallevel at last comptags -i */ + +static int lasttaglevel; + +static void +freectset(Ctset s) +{ + Ctset n; + + while (s) { + n = s->next; + + freearray(s->tags); + zfree(s, sizeof(*s)); + + s = n; + } +} + +static void +freectags(Ctags t) +{ + if (t) { + freearray(t->all); + zsfree(t->context); + freectset(t->sets); + zfree(t, sizeof(*t)); + } +} + +static void +settags(char **tags) +{ + Ctags t; + + if (comptags[locallevel]) + freectags(comptags[locallevel]); + + comptags[locallevel] = t = (Ctags) zalloc(sizeof(*t)); + + PERMALLOC { + t->all = arrdup(tags + 1); + } LASTALLOC; + t->context = ztrdup(*tags); + t->sets = NULL; + t->init = 1; +} + +static int +arrcontains(char **a, char *s) +{ + while (*a) + if (!strcmp(s, *a++)) + return 1; + + return 0; +} + +static int +bin_comptags(char *nam, char **args, char *ops, int func) +{ + int min, max, n; + + if (incompfunc != 1) { + zerrnam(nam, "can only be called from completion function", NULL, 0); + return 1; + } + if (args[0][0] != '-' || !args[0][1] || args[0][2]) { + zerrnam(nam, "invalid argument: %s", args[0], 0); + return 1; + } + if (locallevel >= MAX_TAGS) { + zerrnam(nam, "nesting level too deep", NULL, 0); + return 1; + } + if (args[0][1] != 'i' && !comptags[locallevel]) { + zerrnam(nam, "no tags registered", NULL, 0); + return 1; + } + switch (args[0][1]) { + case 'i': min = 2; max = -1; break; + case 'C': min = 1; max = 1; break; + case 'T': min = 0; max = 0; break; + case 'N': min = 0; max = 0; break; + case 'R': min = 1; max = 1; break; + case 'S': min = 1; max = 1; break; + default: + zerrnam(nam, "invalid option: %s", args[0], 0); + return 1; + } + n = arrlen(args) - 1; + if (n < min) { + zerrnam(nam, "not enough arguments", NULL, 0); + return 1; + } else if (max >= 0 && n > max) { + zerrnam(nam, "too many arguments", NULL, 0); + return 1; + } + switch (args[0][1]) { + case 'i': + settags(args + 1); + lasttaglevel = locallevel; + break; + case 'C': + setsparam(args[1], ztrdup(comptags[locallevel]->context)); + break; + case 'T': + return !comptags[locallevel]->sets; + case 'N': + { + Ctset s; + + if (comptags[locallevel]->init) + comptags[locallevel]->init = 0; + else if ((s = comptags[locallevel]->sets)) { + comptags[locallevel]->sets = s->next; + s->next = NULL; + freectset(s); + } + return !comptags[locallevel]->sets; + } + case 'R': + { + Ctset s; + + return !((s = comptags[locallevel]->sets) && + arrcontains(s->tags, args[1])); + } + case 'S': + if (comptags[locallevel]->sets) { + char **ret; + + PERMALLOC { + ret = arrdup(comptags[locallevel]->sets->tags); + } LASTALLOC; + + setaparam(args[1], ret); + } else + return 1; + + break; + } + return 0; +} + +static int +bin_comptry(char *nam, char **args, char *ops, int func) +{ + if (incompfunc != 1) { + zerrnam(nam, "can only be called from completion function", NULL, 0); + return 1; + } + if (!lasttaglevel || !comptags[lasttaglevel]) { + zerrnam(nam, "no tags registered", NULL, 0); + return 1; + } + if (*args) { + char **p, **q, **all; + + args = arrdup(args); + + for (p = q = args, all = comptags[lasttaglevel]->all; *p; p++) + if (arrcontains(all, *p)) + *q++ = *p; + *q = NULL; + + if (*args) { + Ctset s = (Ctset) zalloc(sizeof(*s)), l; + + PERMALLOC { + s->tags = arrdup(args); + } LASTALLOC; + s->next = NULL; + + if ((l = comptags[lasttaglevel]->sets)) { + while (l->next) + l = l->next; + + l->next = s; + } else + comptags[lasttaglevel]->sets = s; + } + } + return 0; +} + static struct builtin bintab[] = { BUILTIN("compdisplay", 0, bin_compdisplay, 2, -1, 0, NULL, NULL), BUILTIN("compdescribe", 0, bin_compdescribe, 3, -1, 0, NULL, NULL), BUILTIN("comparguments", 0, bin_comparguments, 1, -1, 0, NULL, NULL), BUILTIN("compvalues", 0, bin_compvalues, 1, -1, 0, NULL, NULL), BUILTIN("compquote", 0, bin_compquote, 1, -1, 0, NULL, NULL), + BUILTIN("compstyles", 0, bin_compstyles, 1, -1, 0, NULL, NULL), + BUILTIN("comptags", 0, bin_comptags, 1, -1, 0, NULL, NULL), + BUILTIN("comptry", 0, bin_comptry, 0, -1, 0, NULL, NULL), }; @@ -1993,6 +2573,12 @@ setup_computil(Module m) memset(cadef_cache, 0, sizeof(cadef_cache)); memset(cvdef_cache, 0, sizeof(cvdef_cache)); + compstyles = NULL; + + memset(comptags, 0, sizeof(comptags)); + + lasttaglevel = 0; + return 0; } @@ -2020,9 +2606,14 @@ finish_computil(Module m) int i; for (i = 0; i < MAX_CACACHE; i++) - free_cadef(cadef_cache[i]); + freecadef(cadef_cache[i]); for (i = 0; i < MAX_CVCACHE; i++) - free_cvdef(cvdef_cache[i]); + freecvdef(cvdef_cache[i]); + + freecspat(compstyles); + + for (i = 0; i < MAX_TAGS; i++) + freectags(comptags[i]); return 0; } |