diff options
Diffstat (limited to 'Src/Zle/compctl.c')
-rw-r--r-- | Src/Zle/compctl.c | 1085 |
1 files changed, 1085 insertions, 0 deletions
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c new file mode 100644 index 000000000..658cf4161 --- /dev/null +++ b/Src/Zle/compctl.c @@ -0,0 +1,1085 @@ +/* + * compctl.c - the compctl builtin + * + * This file is part of zsh, the Z shell. + * + * Copyright (c) 1992-1997 Paul Falstad + * All rights reserved. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and to distribute modified versions of this software for any + * purpose, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * In no event shall Paul Falstad or the Zsh Development Group be liable + * to any party for direct, indirect, special, incidental, or consequential + * damages arising out of the use of this software and its documentation, + * even if Paul Falstad and the Zsh Development Group have been advised of + * the possibility of such damage. + * + * Paul Falstad and the Zsh Development Group specifically disclaim any + * warranties, including, but not limited to, the implied warranties of + * merchantability and fitness for a particular purpose. The software + * provided hereunder is on an "as is" basis, and Paul Falstad and the + * Zsh Development Group have no obligation to provide maintenance, + * support, updates, enhancements, or modifications. + * + */ + +#include "compctl.mdh" +#include "compctl.pro" + +#define COMP_LIST (1<<0) /* -L */ +#define COMP_COMMAND (1<<1) /* -C */ +#define COMP_DEFAULT (1<<2) /* -D */ +#define COMP_FIRST (1<<3) /* -T */ +#define COMP_REMOVE (1<<4) + +#define COMP_SPECIAL (COMP_COMMAND|COMP_DEFAULT|COMP_FIRST) + +/* Flag for listing, command, default, or first completion */ +static int cclist; + +/* Mask for determining what to print */ +static unsigned long showmask = 0; + +/* Parse the basic flags for `compctl' */ + +/**/ +static int +get_compctl(char *name, char ***av, Compctl cc, int first, int isdef) +{ + /* Parse the basic flags for completion: + * first is a flag that we are not in extended completion, + * while hx indicates or (+) completion (need to know for + * default and command completion as the initial compctl is special). + * cct is a temporary just to hold flags; it never needs freeing. + */ + struct compctl cct; + char **argv = *av; + int ready = 0, hx = 0; + + /* Handle `compctl + foo ...' specially: turn it into + * a default compctl by removing it from the hash table. + */ + if (first && argv[0][0] == '+' && !argv[0][1] && + !(argv[1] && argv[1][0] == '-' && argv[1][1])) { + argv++; + if(argv[0] && argv[0][0] == '-') + argv++; + *av = argv; + freecompctl(cc); + cclist = COMP_REMOVE; + return 0; + } + + memset((void *)&cct, 0, sizeof(cct)); + + /* Loop through the flags until we have no more: * + * those with arguments are not properly allocated yet, * + * we just hang on to the argument that was passed. */ + for (; !ready && argv[0] && argv[0][0] == '-' && (argv[0][1] || !first);) { + if (!argv[0][1]) + *argv = "-+"; + while (!ready && *++(*argv)) { + if(**argv == Meta) + *++*argv ^= 32; + switch (**argv) { + case 'f': + cct.mask |= CC_FILES; + break; + case 'c': + cct.mask |= CC_COMMPATH; + break; + case 'm': + cct.mask |= CC_EXTCMDS; + break; + case 'w': + cct.mask |= CC_RESWDS; + break; + case 'o': + cct.mask |= CC_OPTIONS; + break; + case 'v': + cct.mask |= CC_VARS; + break; + case 'b': + cct.mask |= CC_BINDINGS; + break; + case 'A': + cct.mask |= CC_ARRAYS; + break; + case 'I': + cct.mask |= CC_INTVARS; + break; + case 'F': + cct.mask |= CC_SHFUNCS; + break; + case 'p': + cct.mask |= CC_PARAMS; + break; + case 'E': + cct.mask |= CC_ENVVARS; + break; + case 'j': + cct.mask |= CC_JOBS; + break; + case 'r': + cct.mask |= CC_RUNNING; + break; + case 'z': + cct.mask |= CC_STOPPED; + break; + case 'B': + cct.mask |= CC_BUILTINS; + break; + case 'a': + cct.mask |= CC_ALREG | CC_ALGLOB; + break; + case 'R': + cct.mask |= CC_ALREG; + break; + case 'G': + cct.mask |= CC_ALGLOB; + break; + case 'u': + cct.mask |= CC_USERS; + break; + case 'd': + cct.mask |= CC_DISCMDS; + break; + case 'e': + cct.mask |= CC_EXCMDS; + break; + case 'N': + cct.mask |= CC_SCALARS; + break; + case 'O': + cct.mask |= CC_READONLYS; + break; + case 'Z': + cct.mask |= CC_SPECIALS; + break; + case 'q': + cct.mask |= CC_REMOVE; + break; + case 'U': + cct.mask |= CC_DELETE; + break; + case 'n': + cct.mask |= CC_NAMED; + break; + case 'Q': + cct.mask |= CC_QUOTEFLAG; + break; + case '/': + cct.mask |= CC_DIRS; + break; + case 'k': + if ((*argv)[1]) { + cct.keyvar = (*argv) + 1; + *argv = "" - 1; + } else if (!argv[1]) { + zwarnnam(name, "variable name expected after -%c", NULL, + **argv); + return 1; + } else { + cct.keyvar = *++argv; + *argv = "" - 1; + } + break; + case 'K': + if ((*argv)[1]) { + cct.func = (*argv) + 1; + *argv = "" - 1; + } else if (!argv[1]) { + zwarnnam(name, "function name expected after -%c", NULL, + **argv); + return 1; + } else { + cct.func = *++argv; + *argv = "" - 1; + } + break; + case 'Y': + cct.mask |= CC_EXPANDEXPL; + goto expl; + case 'X': + cct.mask &= ~CC_EXPANDEXPL; + expl: + if ((*argv)[1]) { + cct.explain = (*argv) + 1; + *argv = "" - 1; + } else if (!argv[1]) { + zwarnnam(name, "string expected after -%c", NULL, **argv); + return 1; + } else { + cct.explain = *++argv; + *argv = "" - 1; + } + break; + case 'y': + if ((*argv)[1]) { + cct.ylist = (*argv) + 1; + *argv = "" - 1; + } else if (!argv[1]) { + zwarnnam(name, "function/variable expected after -%c", + NULL, **argv); + } else { + cct.ylist = *++argv; + *argv = "" - 1; + } + break; + case 'P': + if ((*argv)[1]) { + cct.prefix = (*argv) + 1; + *argv = "" - 1; + } else if (!argv[1]) { + zwarnnam(name, "string expected after -%c", NULL, **argv); + return 1; + } else { + cct.prefix = *++argv; + *argv = "" - 1; + } + break; + case 'S': + if ((*argv)[1]) { + cct.suffix = (*argv) + 1; + *argv = "" - 1; + } else if (!argv[1]) { + zwarnnam(name, "string expected after -%c", NULL, **argv); + return 1; + } else { + cct.suffix = *++argv; + *argv = "" - 1; + } + break; + case 'g': + if ((*argv)[1]) { + cct.glob = (*argv) + 1; + *argv = "" - 1; + } else if (!argv[1]) { + zwarnnam(name, "glob pattern expected after -%c", NULL, + **argv); + return 1; + } else { + cct.glob = *++argv; + *argv = "" - 1; + } + break; + case 's': + if ((*argv)[1]) { + cct.str = (*argv) + 1; + *argv = "" - 1; + } else if (!argv[1]) { + zwarnnam(name, "command string expected after -%c", NULL, + **argv); + return 1; + } else { + cct.str = *++argv; + *argv = "" - 1; + } + break; + case 'l': + if ((*argv)[1]) { + cct.subcmd = (*argv) + 1; + *argv = "" - 1; + } else if (!argv[1]) { + zwarnnam(name, "command name expected after -%c", NULL, + **argv); + return 1; + } else { + cct.subcmd = *++argv; + *argv = "" - 1; + } + break; + case 'W': + if ((*argv)[1]) { + cct.withd = (*argv) + 1; + *argv = "" - 1; + } else if (!argv[1]) { + zwarnnam(name, "path expected after -%c", NULL, + **argv); + return 1; + } else { + cct.withd = *++argv; + *argv = "" - 1; + } + break; + case 'H': + if ((*argv)[1]) + cct.hnum = atoi((*argv) + 1); + else if (argv[1]) + cct.hnum = atoi(*++argv); + else { + zwarnnam(name, "number expected after -%c", NULL, + **argv); + return 1; + } + if (!argv[1]) { + zwarnnam(name, "missing pattern after -%c", NULL, + **argv); + return 1; + } + cct.hpat = *++argv; + if (cct.hnum < 1) + cct.hnum = 0; + if (*cct.hpat == '*' && !cct.hpat[1]) + cct.hpat = ""; + *argv = "" - 1; + break; + case 'C': + if (first && !hx) { + cclist |= COMP_COMMAND; + } else { + zwarnnam(name, "misplaced command completion (-C) flag", + NULL, 0); + return 1; + } + break; + case 'D': + if (first && !hx) { + isdef = 1; + cclist |= COMP_DEFAULT; + } else { + zwarnnam(name, "misplaced default completion (-D) flag", + NULL, 0); + return 1; + } + break; + case 'T': + if (first && !hx) { + cclist |= COMP_FIRST; + } else { + zwarnnam(name, "misplaced first completion (-T) flag", + NULL, 0); + return 1; + } + break; + case 'L': + if (!first || hx) { + zwarnnam(name, "illegal use of -L flag", NULL, 0); + return 1; + } + cclist |= COMP_LIST; + break; + case 'x': + if (!argv[1]) { + zwarnnam(name, "condition expected after -%c", NULL, + **argv); + return 1; + } + if (first) { + argv++; + if (get_xcompctl(name, &argv, &cct, isdef)) { + if (cct.ext) + freecompctl(cct.ext); + return 1; + } + ready = 2; + } else { + zwarnnam(name, "recursive extended completion not allowed", + NULL, 0); + return 1; + } + break; + default: + if (!first && (**argv == '-' || **argv == '+')) + (*argv)--, argv--, ready = 1; + else { + zwarnnam(name, "bad option: -%c", NULL, **argv); + return 1; + } + } + } + + if (*++argv && (!ready || ready == 2) && + **argv == '+' && !argv[0][1]) { + /* There's an alternative (+) completion: assign + * what we have so far before moving on to that. + */ + if (cc_assign(name, &cc, &cct, first && !hx)) + return 1; + + hx = 1; + ready = 0; + + if (!*++argv || **argv != '-' || + (**argv == '-' && (!argv[0][1] || + (argv[0][1] == '-' && !argv[0][2])))) { + /* No argument to +, which means do default completion */ + if (isdef) + zwarnnam(name, + "recursive xor'd default completions not allowed", + NULL, 0); + else + cc->xor = &cc_default; + } else { + /* more flags follow: prepare to loop again */ + cc->xor = (Compctl) zcalloc(sizeof(*cc)); + cc = cc->xor; + memset((void *)&cct, 0, sizeof(cct)); + } + } + } + if (!ready && *argv && **argv == '-') + argv++; + + if (! (cct.mask & (CC_EXCMDS | CC_DISCMDS))) + cct.mask |= CC_EXCMDS; + + /* assign the last set of flags we parsed */ + if (cc_assign(name, &cc, &cct, first && !hx)) + return 1; + + *av = argv; + + return 0; +} + +/* Handle the -x ... -- part of compctl. */ + +/**/ +static int +get_xcompctl(char *name, char ***av, Compctl cc, int isdef) +{ + char **argv = *av, *t, *tt, sav; + int n, l = 0, ready = 0; + Compcond m, c, o; + Compctl *next = &(cc->ext); + + while (!ready) { + /* o keeps track of or's, m remembers the starting condition, + * c is the current condition being parsed + */ + o = m = c = (Compcond) zcalloc(sizeof(*c)); + /* Loop over each condition: something like 's[...][...], p[...]' */ + for (t = *argv; *t;) { + while (*t == ' ') + t++; + /* First get the condition code */ + switch (*t) { + case 's': + c->type = CCT_CURSUF; + break; + case 'S': + c->type = CCT_CURPRE; + break; + case 'p': + c->type = CCT_POS; + break; + case 'c': + c->type = CCT_CURSTR; + break; + case 'C': + c->type = CCT_CURPAT; + break; + case 'w': + c->type = CCT_WORDSTR; + break; + case 'W': + c->type = CCT_WORDPAT; + break; + case 'n': + c->type = CCT_CURSUB; + break; + case 'N': + c->type = CCT_CURSUBC; + break; + case 'm': + c->type = CCT_NUMWORDS; + break; + case 'r': + c->type = CCT_RANGESTR; + break; + case 'R': + c->type = CCT_RANGEPAT; + break; + default: + t[1] = '\0'; + zwarnnam(name, "unknown condition code: %s", t, 0); + zfree(m, sizeof(struct compcond)); + + return 1; + } + /* Now get the arguments in square brackets */ + if (t[1] != '[') { + t[1] = '\0'; + zwarnnam(name, "expected condition after condition code: %s", t, 0); + zfree(m, sizeof(struct compcond)); + + return 1; + } + t++; + /* First count how many or'd arguments there are, + * marking the active ]'s and ,'s with unprintable characters. + */ + for (n = 0, tt = t; *tt == '['; n++) { + for (l = 1, tt++; *tt && l; tt++) + if (*tt == '\\' && tt[1]) + tt++; + else if (*tt == '[') + l++; + else if (*tt == ']') + l--; + else if (l == 1 && *tt == ',') + *tt = '\201'; + if (tt[-1] == ']') + tt[-1] = '\200'; + } + + if (l) { + t[1] = '\0'; + zwarnnam(name, "error after condition code: %s", t, 0); + zfree(m, sizeof(struct compcond)); + + return 1; + } + c->n = n; + + /* Allocate space for all the arguments of the conditions */ + if (c->type == CCT_POS || + c->type == CCT_NUMWORDS) { + c->u.r.a = (int *)zcalloc(n * sizeof(int)); + c->u.r.b = (int *)zcalloc(n * sizeof(int)); + } else if (c->type == CCT_CURSUF || + c->type == CCT_CURPRE) + c->u.s.s = (char **)zcalloc(n * sizeof(char *)); + + else if (c->type == CCT_RANGESTR || + c->type == CCT_RANGEPAT) { + c->u.l.a = (char **)zcalloc(n * sizeof(char *)); + c->u.l.b = (char **)zcalloc(n * sizeof(char *)); + } else { + c->u.s.p = (int *)zcalloc(n * sizeof(int)); + c->u.s.s = (char **)zcalloc(n * sizeof(char *)); + } + /* Now loop over the actual arguments */ + for (l = 0; *t == '['; l++, t++) { + for (t++; *t && *t == ' '; t++); + tt = t; + if (c->type == CCT_POS || + c->type == CCT_NUMWORDS) { + /* p[...] or m[...]: one or two numbers expected */ + for (; *t && *t != '\201' && *t != '\200'; t++); + if (!(sav = *t)) { + zwarnnam(name, "error in condition", NULL, 0); + freecompcond(m); + return 1; + } + *t = '\0'; + c->u.r.a[l] = atoi(tt); + /* Second argument is optional: see if it's there */ + if (sav == '\200') + /* no: copy first argument */ + c->u.r.b[l] = c->u.r.a[l]; + else { + tt = ++t; + for (; *t && *t != '\200'; t++); + if (!*t) { + zwarnnam(name, "error in condition", NULL, 0); + freecompcond(m); + return 1; + } + *t = '\0'; + c->u.r.b[l] = atoi(tt); + } + } else if (c->type == CCT_CURSUF || + c->type == CCT_CURPRE) { + /* -s[..] or -S[..]: single string expected */ + for (; *t && *t != '\200'; t++) + if (*t == '\201') + *t = ','; + if (!*t) { + zwarnnam(name, "error in condition", NULL, 0); + freecompcond(m); + return 1; + } + *t = '\0'; + c->u.s.s[l] = ztrdup(tt); + } else if (c->type == CCT_RANGESTR || + c->type == CCT_RANGEPAT) { + /* -r[..,..] or -R[..,..]: two strings expected */ + for (; *t && *t != '\201'; t++); + if (!*t) { + zwarnnam(name, "error in condition", NULL, 0); + freecompcond(m); + return 1; + } + *t = '\0'; + c->u.l.a[l] = ztrdup(tt); + tt = ++t; + /* any more commas are text, not active */ + for (; *t && *t != '\200'; t++) + if (*t == '\201') + *t = ','; + if (!*t) { + zwarnnam(name, "error in condition", NULL, 0); + freecompcond(m); + return 1; + } + *t = '\0'; + c->u.l.b[l] = ztrdup(tt); + } else { + /* remaining patterns are number followed by string */ + for (; *t && *t != '\200' && *t != '\201'; t++); + if (!*t || *t == '\200') { + zwarnnam(name, "error in condition", NULL, 0); + freecompcond(m); + return 1; + } + *t = '\0'; + c->u.s.p[l] = atoi(tt); + tt = ++t; + for (; *t && *t != '\200'; t++) + if (*t == '\201') + *t = ','; + if (!*t) { + zwarnnam(name, "error in condition", NULL, 0); + freecompcond(m); + return 1; + } + *t = '\0'; + c->u.s.s[l] = ztrdup(tt); + } + } + while (*t == ' ') + t++; + if (*t == ',') { + /* Another condition to `or' */ + o->or = c = (Compcond) zcalloc(sizeof(*c)); + o = c; + t++; + } else if (*t) { + /* Another condition to `and' */ + c->and = (Compcond) zcalloc(sizeof(*c)); + c = c->and; + } + } + /* Assign condition to current compctl */ + *next = (Compctl) zcalloc(sizeof(*cc)); + (*next)->cond = m; + argv++; + /* End of the condition; get the flags that go with it. */ + if (get_compctl(name, &argv, *next, 0, isdef)) + return 1; + if ((!argv || !*argv) && (cclist & COMP_SPECIAL)) + /* default, first, or command completion finished */ + ready = 1; + else { + /* see if we are looking for more conditions or are + * ready to return (ready = 1) + */ + if (!argv || !*argv || **argv != '-' || + ((!argv[0][1] || argv[0][1] == '+') && !argv[1])) { + zwarnnam(name, "missing command names", NULL, 0); + return 1; + } + if (!strcmp(*argv, "--")) + ready = 1; + else if (!strcmp(*argv, "-+") && argv[1] && + !strcmp(argv[1], "--")) { + ready = 1; + argv++; + } + argv++; + /* prepare to put the next lot of conditions on the end */ + next = &((*next)->next); + } + } + /* save position at end of parsing */ + *av = argv - 1; + return 0; +} + +/**/ +static int +cc_assign(char *name, Compctl *ccptr, Compctl cct, int reass) +{ + /* Copy over the details from the values in cct to those in *ccptr */ + Compctl cc; + + if (cct->subcmd && (cct->keyvar || cct->glob || cct->str || + cct->func || cct->explain || cct->ylist || + cct->prefix)) { + zwarnnam(name, "illegal combination of options", NULL, 0); + return 1; + } + + /* Handle assignment of new default or command completion */ + if (reass && !(cclist & COMP_LIST)) { + /* if not listing */ + if (cclist == (COMP_COMMAND|COMP_DEFAULT) + || cclist == (COMP_COMMAND|COMP_FIRST) + || cclist == (COMP_DEFAULT|COMP_FIRST) + || cclist == COMP_SPECIAL) { + zwarnnam(name, "can't set -D, -T, and -C simultaneously", NULL, 0); + /* ... because the following code wouldn't work. */ + return 1; + } + if (cclist & COMP_COMMAND) { + /* command */ + *ccptr = &cc_compos; + cc_reassign(*ccptr); + } else if (cclist & COMP_DEFAULT) { + /* default */ + *ccptr = &cc_default; + cc_reassign(*ccptr); + } else if (cclist & COMP_FIRST) { + /* first */ + *ccptr = &cc_first; + cc_reassign(*ccptr); + } + } + + /* Free the old compctl */ + cc = *ccptr; + zsfree(cc->keyvar); + zsfree(cc->glob); + zsfree(cc->str); + zsfree(cc->func); + zsfree(cc->explain); + zsfree(cc->ylist); + zsfree(cc->prefix); + zsfree(cc->suffix); + zsfree(cc->subcmd); + zsfree(cc->withd); + zsfree(cc->hpat); + + /* and copy over the new stuff, (permanently) allocating + * space for strings. + */ + cc->mask = cct->mask; + cc->keyvar = ztrdup(cct->keyvar); + cc->glob = ztrdup(cct->glob); + cc->str = ztrdup(cct->str); + cc->func = ztrdup(cct->func); + cc->explain = ztrdup(cct->explain); + cc->ylist = ztrdup(cct->ylist); + cc->prefix = ztrdup(cct->prefix); + cc->suffix = ztrdup(cct->suffix); + cc->subcmd = ztrdup(cct->subcmd); + cc->withd = ztrdup(cct->withd); + cc->hpat = ztrdup(cct->hpat); + cc->hnum = cct->hnum; + + /* careful with extended completion: it's already allocated */ + cc->ext = cct->ext; + + return 0; +} + +/**/ +static void +cc_reassign(Compctl cc) +{ + /* Free up a new default or command completion: + * this is a hack to free up the parts which should be deleted, + * without removing the basic variable which is statically allocated + */ + Compctl c2; + + c2 = (Compctl) zcalloc(sizeof *cc); + c2->xor = cc->xor; + c2->ext = cc->ext; + c2->refc = 1; + + freecompctl(c2); + + cc->ext = cc->xor = NULL; +} + +/**/ +static void +compctl_process_cc(char **s, Compctl cc) +{ + Compctlp ccp; + + if (cclist & COMP_REMOVE) { + /* Delete entries for the commands listed */ + for (; *s; s++) { + if ((ccp = (Compctlp) compctltab->removenode(compctltab, *s))) + compctltab->freenode((HashNode) ccp); + } + } else { + /* Add the compctl just read to the hash table */ + + cc->refc = 0; + for (; *s; s++) { + cc->refc++; + ccp = (Compctlp) zalloc(sizeof *ccp); + ccp->cc = cc; + compctltab->addnode(compctltab, ztrdup(*s), ccp); + } + } +} + +/* Print a `compctl' */ + +/**/ +static void +printcompctl(char *s, Compctl cc, int printflags) +{ + Compctl cc2; + char *css = "fcqovbAIFpEjrzBRGudeNOZUnQmw/"; + char *mss = " pcCwWsSnNmrR"; + unsigned long t = 0x7fffffff; + unsigned long flags = cc->mask; + unsigned long oldshowmask; + + if ((flags & CC_EXCMDS) && !(flags & CC_DISCMDS)) + flags &= ~CC_EXCMDS; + + /* If showmask is non-zero, then print only those * + * commands with that flag set. */ + if (showmask && !(flags & showmask)) + return; + + /* Temporarily clear showmask in case we make * + * recursive calls to printcompctl. */ + oldshowmask = showmask; + showmask = 0; + + /* print either command name or start of compctl command itself */ + if (s) { + if (cclist & COMP_LIST) { + printf("compctl"); + if (cc == &cc_compos) + printf(" -C"); + if (cc == &cc_default) + printf(" -D"); + if (cc == &cc_first) + printf(" -T"); + } else + quotedzputs(s, stdout); + } + + /* loop through flags w/o args that are set, printing them if so */ + if (flags & t) { + printf(" -"); + if ((flags & (CC_ALREG | CC_ALGLOB)) == (CC_ALREG | CC_ALGLOB)) + putchar('a'), flags &= ~(CC_ALREG | CC_ALGLOB); + while (*css) { + if (flags & t & 1) + putchar(*css); + css++; + flags >>= 1; + t >>= 1; + } + } + + /* now flags with arguments */ + flags = cc->mask; + printif(cc->keyvar, 'k'); + printif(cc->func, 'K'); + printif(cc->explain, (cc->mask & CC_EXPANDEXPL) ? 'Y' : 'X'); + printif(cc->ylist, 'y'); + printif(cc->prefix, 'P'); + printif(cc->suffix, 'S'); + printif(cc->glob, 'g'); + printif(cc->str, 's'); + printif(cc->subcmd, 'l'); + printif(cc->withd, 'W'); + if (cc->hpat) { + printf(" -H %d ", cc->hnum); + quotedzputs(cc->hpat, stdout); + } + + /* now the -x ... -- extended completion part */ + if (cc->ext) { + Compcond c, o; + int i; + + cc2 = cc->ext; + printf(" -x"); + + while (cc2) { + /* loop over conditions */ + c = cc2->cond; + + printf(" '"); + for (c = cc2->cond; c;) { + /* loop over or's */ + o = c->or; + while (c) { + /* loop over and's */ + putchar(mss[c->type]); + + for (i = 0; i < c->n; i++) { + /* for all [...]'s of a given condition */ + putchar('['); + switch (c->type) { + case CCT_POS: + case CCT_NUMWORDS: + printf("%d,%d", c->u.r.a[i], c->u.r.b[i]); + break; + case CCT_CURSUF: + case CCT_CURPRE: + printqt(c->u.s.s[i]); + break; + case CCT_RANGESTR: + case CCT_RANGEPAT: + printqt(c->u.l.a[i]); + putchar(','); + printqt(c->u.l.b[i]); + break; + default: + printf("%d,", c->u.s.p[i]); + printqt(c->u.s.s[i]); + } + putchar(']'); + } + if ((c = c->and)) + putchar(' '); + } + if ((c = o)) + printf(" , "); + } + putchar('\''); + c = cc2->cond; + cc2->cond = NULL; + /* now print the flags for the current condition */ + printcompctl(NULL, cc2, 0); + cc2->cond = c; + if ((cc2 = (Compctl) (cc2->next))) + printf(" -"); + } + if (cclist & COMP_LIST) + printf(" --"); + } + if (cc && cc->xor) { + /* print xor'd (+) completions */ + printf(" +"); + if (cc->xor != &cc_default) + printcompctl(NULL, cc->xor, 0); + } + if (s) { + if ((cclist & COMP_LIST) && (cc != &cc_compos) + && (cc != &cc_default) && (cc != &cc_first)) { + if(s[0] == '-' || s[0] == '+') + printf(" -"); + putchar(' '); + quotedzputs(s, stdout); + } + putchar('\n'); + } + + showmask = oldshowmask; +} + +/**/ +static void +printcompctlp(HashNode hn, int printflags) +{ + Compctlp ccp = (Compctlp) hn; + + /* Function needed for use by scanhashtable() */ + printcompctl(ccp->nam, ccp->cc, printflags); +} + +/* Main entry point for the `compctl' builtin */ + +/**/ +static int +bin_compctl(char *name, char **argv, char *ops, int func) +{ + Compctl cc = NULL; + int ret = 0; + + /* clear static flags */ + cclist = 0; + showmask = 0; + + /* Parse all the arguments */ + if (*argv) { + cc = (Compctl) zcalloc(sizeof(*cc)); + if (get_compctl(name, &argv, cc, 1, 0)) { + freecompctl(cc); + return 1; + } + + /* remember flags for printing */ + showmask = cc->mask; + if ((showmask & CC_EXCMDS) && !(showmask & CC_DISCMDS)) + showmask &= ~CC_EXCMDS; + + /* if no command arguments or just listing, we don't want cc */ + if (!*argv || (cclist & COMP_LIST)) + freecompctl(cc); + } + + /* If no commands and no -C, -T, or -D, print all the compctl's * + * If some flags (other than -C, -T, or -D) were given, then * + * only print compctl containing those flags. */ + if (!*argv && !(cclist & COMP_SPECIAL)) { + scanhashtable(compctltab, 1, 0, 0, compctltab->printnode, 0); + printcompctl((cclist & COMP_LIST) ? "" : "COMMAND", &cc_compos, 0); + printcompctl((cclist & COMP_LIST) ? "" : "DEFAULT", &cc_default, 0); + printcompctl((cclist & COMP_LIST) ? "" : "FIRST", &cc_first, 0); + return ret; + } + + /* If we're listing and we've made it to here, then there are arguments * + * or a COMP_SPECIAL flag (-D, -C, -T), so print only those. */ + if (cclist & COMP_LIST) { + HashNode hn; + char **ptr; + + showmask = 0; + for (ptr = argv; *ptr; ptr++) { + if ((hn = compctltab->getnode(compctltab, *ptr))) { + compctltab->printnode(hn, 0); + } else { + zwarnnam(name, "no compctl defined for %s", *ptr, 0); + ret = 1; + } + } + if (cclist & COMP_COMMAND) + printcompctl("", &cc_compos, 0); + if (cclist & COMP_DEFAULT) + printcompctl("", &cc_default, 0); + if (cclist & COMP_FIRST) + printcompctl("", &cc_first, 0); + return ret; + } + + /* Assign the compctl to the commands given */ + if (*argv) { + if(cclist & COMP_SPECIAL) + /* Ideally we'd handle this properly, setting both the * + * special and normal completions. For the moment, * + * this is better than silently failing. */ + zwarnnam(name, "extraneous commands ignored", NULL, 0); + else + compctl_process_cc(argv, cc); + } + + return ret; +} + +static struct builtin bintab[] = { + BUILTIN("compctl", 0, bin_compctl, 0, -1, 0, NULL, NULL), +}; + +/**/ +int +boot_compctl(Module m) +{ + if(!addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab))) + return 1; + compctltab->printnode = printcompctlp; + return 0; +} + +#ifdef MODULE + +/**/ +int +cleanup_compctl(Module m) +{ + compctltab->printnode = NULL; + deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + return 0; +} +#endif |