diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/Makefile.in | 2 | ||||
-rw-r--r-- | Src/Makemod.in.in | 5 | ||||
-rw-r--r-- | Src/Zle/zle_tricky.c | 16 | ||||
-rw-r--r-- | Src/builtin.c | 44 | ||||
-rw-r--r-- | Src/exec.c | 22 | ||||
-rw-r--r-- | Src/glob.c | 19 | ||||
-rw-r--r-- | Src/hashtable.c | 87 | ||||
-rw-r--r-- | Src/input.c | 2 | ||||
-rw-r--r-- | Src/params.c | 471 | ||||
-rw-r--r-- | Src/prompt.c | 256 | ||||
-rw-r--r-- | Src/subst.c | 30 | ||||
-rw-r--r-- | Src/text.c | 2 | ||||
-rw-r--r-- | Src/utils.c | 4 | ||||
-rw-r--r-- | Src/zsh.export | 1 | ||||
-rw-r--r-- | Src/zsh.h | 7 |
15 files changed, 671 insertions, 297 deletions
diff --git a/Src/Makefile.in b/Src/Makefile.in index 269ed7c1b..27891e92a 100644 --- a/Src/Makefile.in +++ b/Src/Makefile.in @@ -149,7 +149,7 @@ uninstall.bin: uninstall.bin-here # install binary, creating install directory if necessary install.bin-here: zsh install.bin-@L@ $(sdir_top)/mkinstalldirs $(bindir) - $(INSTALL_PROGRAM) zsh $(bindir)/zsh-$(VERSION) + $(INSTALL_PROGRAM) $(STRIPFLAGS) zsh $(bindir)/zsh-$(VERSION) if test -f $(bindir)/zsh; then \ rm -f $(bindir)/zsh.old; \ ln $(bindir)/zsh $(bindir)/zsh.old; \ diff --git a/Src/Makemod.in.in b/Src/Makemod.in.in index f27a6bd57..a5c760eb4 100644 --- a/Src/Makemod.in.in +++ b/Src/Makemod.in.in @@ -119,8 +119,9 @@ uninstall.modules: uninstall.modules-here install.bin-here uninstall.bin-here: install.modules-here: - $(sdir_top)/mkinstalldirs $(MODDIR) - modules='$(MODULES)'; for mod in $$modules; do \ + modules='$(MODULES)'; \ + if test -n "$$modules"; then $(sdir_top)/mkinstalldirs $(MODDIR); fi; \ + for mod in $$modules; do \ $(INSTALL_PROGRAM) $$mod $(MODDIR)/$$mod; \ done diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index 9ffef3b80..a8998739c 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -2945,7 +2945,7 @@ docompletion(char *s, int lst, int incmd) ainfo = fainfo = NULL; /* Make sure we have the completion list and compctl. */ - if (makecomplist(s, incmd)) { + if (makecomplist(s, incmd, lst)) { /* Error condition: feeeeeeeeeeeeep(). */ feep(); goto compend; @@ -3029,7 +3029,7 @@ static unsigned long ccont; /**/ static int -makecomplist(char *s, int incmd) +makecomplist(char *s, int incmd, int lst) { struct cmlist ms; Cmlist m = cmatcher; @@ -3062,7 +3062,7 @@ makecomplist(char *s, int incmd) ccused = newlinklist(); ccstack = newlinklist(); - makecomplistglobal(s, incmd); + makecomplistglobal(s, incmd, lst); endcmgroup(NULL); @@ -3098,12 +3098,14 @@ makecomplist(char *s, int incmd) /**/ static void -makecomplistglobal(char *os, int incmd) +makecomplistglobal(char *os, int incmd, int lst) { Compctl cc; char *s; - if (inwhat == IN_ENV) + if (lst == COMP_WIDGET) { + cc = compwidget->u.cc; + } else if (inwhat == IN_ENV) /* Default completion for parameter values. */ cc = &cc_default; else if (inwhat == IN_MATH) { @@ -4413,7 +4415,8 @@ get_user_var(char *nam) } else { /* Otherwise it should be a parameter name. */ char **arr = NULL, *val; - if (!(arr = getaparam(nam)) && (val = getsparam(nam))) { + if (!(arr = getaparam(nam)) && !(arr = gethparam(nam)) && + (val = getsparam(nam))) { arr = (char **)ncalloc(2*sizeof(char *)); arr[0] = val; arr[1] = NULL; @@ -5026,6 +5029,7 @@ do_single(Cmatch m) else { p = (char *) ncalloc(strlen(ppre) + strlen(str) + strlen(psuf) + 1); + sprintf(p, "%s%s%s", ppre, str, psuf); } parsestr(p); if (ic) diff --git a/Src/builtin.c b/Src/builtin.c index 3aae0f769..dbe91a5b1 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -50,7 +50,7 @@ static struct builtin builtins[] = BUILTIN("cd", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL), BUILTIN("chdir", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL), BUILTIN("continue", BINF_PSPECIAL, bin_break, 0, 1, BIN_CONTINUE, NULL, NULL), - BUILTIN("declare", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "LRUZfilrtux", NULL), + BUILTIN("declare", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZafilrtux", NULL), BUILTIN("dirs", 0, bin_dirs, 0, -1, 0, "v", NULL), BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmr", NULL), BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL), @@ -60,7 +60,7 @@ static struct builtin builtins[] = BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmr", NULL), BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL), BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL), - BUILTIN("export", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "LRUZfilrtu", "x"), + BUILTIN("export", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "LRUZafilrtu", "x"), BUILTIN("false", 0, bin_false, 0, -1, 0, NULL, NULL), BUILTIN("fc", BINF_FCOPTS, bin_fc, 0, -1, BIN_FC, "nlreIRWAdDfEim", NULL), BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL), @@ -78,7 +78,7 @@ static struct builtin builtins[] = BUILTIN("jobs", 0, bin_fg, 0, -1, BIN_JOBS, "dlpZrs", NULL), BUILTIN("kill", 0, bin_kill, 0, -1, 0, NULL, NULL), BUILTIN("let", 0, bin_let, 1, -1, 0, NULL, NULL), - BUILTIN("local", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "LRUZilrtu", NULL), + BUILTIN("local", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZailrtu", NULL), BUILTIN("log", 0, bin_log, 0, 0, 0, NULL, NULL), BUILTIN("logout", 0, bin_break, 0, 1, BIN_LOGOUT, NULL, NULL), @@ -93,7 +93,7 @@ static struct builtin builtins[] = BUILTIN("pwd", 0, bin_pwd, 0, 0, 0, "rLP", NULL), BUILTIN("r", BINF_R, bin_fc, 0, -1, BIN_FC, "nrl", NULL), BUILTIN("read", 0, bin_read, 0, -1, 0, "rzu0123456789pkqecnAlE", NULL), - BUILTIN("readonly", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "LRUZfiltux", "r"), + BUILTIN("readonly", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZafiltux", "r"), BUILTIN("rehash", 0, bin_hash, 0, 0, 0, "dfv", "r"), BUILTIN("return", BINF_PSPECIAL, bin_break, 0, 1, BIN_RETURN, NULL, NULL), BUILTIN("set", BINF_PSPECIAL, bin_set, 0, -1, 0, NULL, NULL), @@ -107,7 +107,7 @@ static struct builtin builtins[] = BUILTIN("trap", BINF_PSPECIAL, bin_trap, 0, -1, 0, NULL, NULL), BUILTIN("true", 0, bin_true, 0, -1, 0, NULL, NULL), BUILTIN("type", 0, bin_whence, 0, -1, 0, "ampfsw", "v"), - BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "LRUZfilrtuxm", NULL), + BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZafilrtuxm", NULL), BUILTIN("umask", 0, bin_umask, 0, 1, 0, "S", NULL), BUILTIN("unalias", 0, bin_unhash, 1, -1, 0, "m", "a"), BUILTIN("unfunction", 0, bin_unhash, 1, -1, 0, "m", "f"), @@ -618,6 +618,8 @@ set_pwd_env(void) { Param pm; + /* update the PWD and OLDPWD shell parameters */ + pm = (Param) paramtab->getnode(paramtab, "PWD"); if (pm && PM_TYPE(pm->flags) != PM_SCALAR) { pm->flags &= ~PM_READONLY; @@ -704,7 +706,6 @@ bin_cd(char *nam, char **argv, char *ops, int func) chdir(unmeta(pwd)); } } - set_pwd_env(); return 0; } @@ -946,7 +947,6 @@ cd_try_chdir(char *pfix, char *dest, int hard) static void cd_new_pwd(int func, LinkNode dir, int chaselinks) { - Param pm; List l; char *new_pwd, *s; int dirstacksize; @@ -981,13 +981,8 @@ cd_new_pwd(int func, LinkNode dir, int chaselinks) zsfree(oldpwd); oldpwd = pwd; pwd = new_pwd; - /* update the PWD and OLDPWD shell parameters */ - if ((pm = (Param) paramtab->getnode(paramtab, "PWD")) && - (pm->flags & PM_EXPORTED) && pm->env) - pm->env = replenv(pm->env, pwd); - if ((pm = (Param) paramtab->getnode(paramtab, "OLDPWD")) && - (pm->flags & PM_EXPORTED) && pm->env) - pm->env = replenv(pm->env, oldpwd); + set_pwd_env(); + if (unset(PUSHDSILENT) && func != BIN_CD && isset(INTERACTIVE)) printdirstack(); else if (doprintdir) { @@ -1474,8 +1469,8 @@ bin_typeset(char *name, char **argv, char *ops, int func) Param pm; Asgment asg; Comp com; - char *optstr = "iLRZlurtxU"; - int on = 0, off = 0, roff, bit = PM_INTEGER; + char *optstr = "aiLRZlurtxU----A"; + int on = 0, off = 0, roff, bit = PM_ARRAY; int initon, initoff, of, i; int returnval = 0, printflags = 0; @@ -1506,6 +1501,8 @@ bin_typeset(char *name, char **argv, char *ops, int func) off |= PM_LOWER; if (on & PM_LOWER) off |= PM_UPPER; + if (on & PM_HASHED) + off |= PM_ARRAY; on &= ~off; /* Given no arguments, list whatever the options specify. */ @@ -1548,8 +1545,15 @@ bin_typeset(char *name, char **argv, char *ops, int func) if (PM_TYPE(pm->flags) == PM_ARRAY && (on & PM_UNIQUE) && !(pm->flags & PM_READONLY & ~off)) uniqarray((*pm->gets.afn) (pm)); + if ((on & ~pm->flags) & PM_HASHED) { + char *nam = ztrdup(pm->nam); + unsetparam(nam); + pm = createparam(nam, on & ~PM_READONLY); + DPUTS(!pm, "BUG: parameter not created"); + } pm->flags = (pm->flags | on) & ~off; - if (PM_TYPE(pm->flags) != PM_ARRAY) { + if (PM_TYPE(pm->flags) != PM_ARRAY && + PM_TYPE(pm->flags) != PM_HASHED) { if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) && auxlen) pm->ct = auxlen; /* did we just export this? */ @@ -1598,7 +1602,8 @@ bin_typeset(char *name, char **argv, char *ops, int func) (((pm->flags & PM_SPECIAL) && pm->level == locallevel) || (!(pm->flags & PM_UNSET) && ((locallevel == pm->level) || func == BIN_EXPORT) && - !(bit = ((off & pm->flags) | (on & ~pm->flags)) & PM_INTEGER)))) { + !(bit = (((off & pm->flags) | (on & ~pm->flags)) & + (PM_INTEGER|PM_HASHED)))))) { /* if no flags or values are given, just print this parameter */ if (!on && !roff && !asg->value) { paramtab->printnode((HashNode) pm, 0); @@ -1623,7 +1628,8 @@ bin_typeset(char *name, char **argv, char *ops, int func) if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) && auxlen) pm->ct = auxlen; - if (PM_TYPE(pm->flags) != PM_ARRAY) { + if (PM_TYPE(pm->flags) != PM_ARRAY && + PM_TYPE(pm->flags) != PM_HASHED) { if (pm->flags & PM_EXPORTED) { if (!(pm->flags & PM_UNSET) && !pm->env && !asg->value) pm->env = addenv(asg->name, getsparam(asg->name)); diff --git a/Src/exec.c b/Src/exec.c index 22fa526ec..bb70e59c8 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1004,11 +1004,12 @@ void untokenize(char *s) { for (; *s; s++) - if (itok(*s)) + if (itok(*s)) { if (*s == Nularg) chuck(s--); else *s = ztokens[*s - Pound]; + } } /* Open a file for writing redicection */ @@ -1923,22 +1924,8 @@ save_params(Cmd cmd, LinkList *restore_p, LinkList *remove_p) } else if (!(pm->flags & PM_READONLY) && (unset(RESTRICTED) || !(pm->flags & PM_RESTRICTED))) { Param tpm = (Param) alloc(sizeof *tpm); - tpm->nam = s; - tpm->flags = pm->flags; - switch (PM_TYPE(pm->flags)) { - case PM_SCALAR: - tpm->u.str = ztrdup(pm->gets.cfn(pm)); - break; - case PM_INTEGER: - tpm->u.val = pm->gets.ifn(pm); - break; - case PM_ARRAY: - PERMALLOC { - tpm->u.arr = arrdup(pm->gets.afn(pm)); - } LASTALLOC; - break; - } + copyparam(tpm, pm, 1); pm = tpm; } addlinknode(*remove_p, s); @@ -1989,6 +1976,9 @@ restore_params(LinkList restorelist, LinkList removelist) case PM_ARRAY: tpm->sets.afn(tpm, pm->u.arr); break; + case PM_HASHED: + tpm->sets.hfn(tpm, pm->u.hash); + break; } } else paramtab->addnode(paramtab, pm->nam, pm); diff --git a/Src/glob.c b/Src/glob.c index 0c66adec8..ea5d0133c 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -355,21 +355,12 @@ scanner(Complist q) insert(c->str, 0); } else { /* Do pattern matching on current path section. */ - char *fn; + char *fn = pathbuf[pathbufcwd] ? unmeta(pathbuf + pathbufcwd) : "."; int dirs = !!q->next; - DIR *lock; + DIR *lock = opendir(fn); char *subdirs = NULL; int subdirlen = 0; - fn = pathbuf[pathbufcwd] ? unmeta(pathbuf + pathbufcwd) : "."; - if (dirs) { - struct stat st; - stat(fn, &st); - /* a directory with subdirectories has link count greater than 2 */ - if (!S_ISDIR(st.st_mode) || st.st_nlink == 2) - return; - } - lock = opendir(fn); if (lock == NULL) return; while ((fn = zreaddir(lock, 1)) && !errflag) { @@ -594,7 +585,8 @@ parsecomp(int gflag) pptr[1] && pptr[1] != Outpar && pptr[1] != Bar) || *pptr == Outpar) { if (*pptr == '/' || !*pptr || - (isset(EXTENDEDGLOB) && *pptr == Tilde && + ((*pptr == Bar || + (isset(EXTENDEDGLOB) && *pptr == Tilde)) && (gflag & GF_TOPLEV))) c->stat |= C_LAST; return c; @@ -746,7 +738,8 @@ parsecomp(int gflag) } /* mark if last pattern component in path component or pattern */ if (*pptr == '/' || !*pptr || - (isset(EXTENDEDGLOB) && *pptr == Tilde && (gflag & GF_TOPLEV))) + ((*pptr == Bar || + (isset(EXTENDEDGLOB) && *pptr == Tilde)) && (gflag & GF_TOPLEV))) c->stat |= C_LAST; c->str = dupstrpfx(cstr, pptr - cstr); return c; diff --git a/Src/hashtable.c b/Src/hashtable.c index 4adf3904d..5bcfec231 100644 --- a/Src/hashtable.c +++ b/Src/hashtable.c @@ -1061,93 +1061,6 @@ printaliasnode(HashNode hn, int printflags) putchar('\n'); } -/**********************************/ -/* Parameter Hash Table Functions */ -/**********************************/ - -/**/ -void -freeparamnode(HashNode hn) -{ - Param pm = (Param) hn; - - zsfree(pm->nam); - zfree(pm, sizeof(struct param)); -} - -/* Print a parameter */ - -/**/ -void -printparamnode(HashNode hn, int printflags) -{ - Param p = (Param) hn; - char *t, **u; - - if (p->flags & PM_UNSET) - return; - - /* Print the attributes of the parameter */ - if (printflags & PRINT_TYPE) { - if (p->flags & PM_INTEGER) - printf("integer "); - if (p->flags & PM_ARRAY) - printf("array "); - if (p->flags & PM_LEFT) - printf("left justified %d ", p->ct); - if (p->flags & PM_RIGHT_B) - printf("right justified %d ", p->ct); - if (p->flags & PM_RIGHT_Z) - printf("zero filled %d ", p->ct); - if (p->flags & PM_LOWER) - printf("lowercase "); - if (p->flags & PM_UPPER) - printf("uppercase "); - if (p->flags & PM_READONLY) - printf("readonly "); - if (p->flags & PM_TAGGED) - printf("tagged "); - if (p->flags & PM_EXPORTED) - printf("exported "); - } - - if (printflags & PRINT_NAMEONLY) { - zputs(p->nam, stdout); - putchar('\n'); - return; - } - - /* How the value is displayed depends * - * on the type of the parameter */ - quotedzputs(p->nam, stdout); - putchar('='); - switch (PM_TYPE(p->flags)) { - case PM_SCALAR: - /* string: simple output */ - if (p->gets.cfn && (t = p->gets.cfn(p))) - quotedzputs(t, stdout); - putchar('\n'); - break; - case PM_INTEGER: - /* integer */ - printf("%ld\n", p->gets.ifn(p)); - break; - case PM_ARRAY: - /* array */ - putchar('('); - u = p->gets.afn(p); - if(*u) { - quotedzputs(*u++, stdout); - while (*u) { - putchar(' '); - quotedzputs(*u++, stdout); - } - } - printf(")\n"); - break; - } -} - /****************************************/ /* Named Directory Hash Table Functions */ /****************************************/ diff --git a/Src/input.c b/Src/input.c index 576341a7c..45c65b2bf 100644 --- a/Src/input.c +++ b/Src/input.c @@ -176,7 +176,7 @@ shingetline(void) int ingetc(void) { - char lastc; + int lastc; if (lexstop) return ' '; diff --git a/Src/params.c b/Src/params.c index 4f7846820..69fd8a904 100644 --- a/Src/params.c +++ b/Src/params.c @@ -232,6 +232,11 @@ IPDEF9("manpath", &manpath, "MANPATH"), IPDEF9("psvar", &psvar, "PSVAR"), IPDEF9("watch", &watch, "WATCH"), +/*TEST BEGIN*/ +#define IPDEF10(A) {NULL,A,PM_HASHED|PM_SPECIAL|PM_DONTIMPORT,BR((void *)0),SFN(hashsetfn),GFN(hashgetfn),stdunsetfn,0,NULL,NULL,NULL,0} +IPDEF10("testhash"), +/*TEST END*/ + #ifdef DYNAMIC IPDEF9F("module_path", &module_path, "MODULE_PATH", PM_RESTRICTED), #endif @@ -247,7 +252,137 @@ static Param argvparam; /**/ HashTable paramtab; - + +/**/ +HashTable +newparamtable(int size, char const *name) +{ + HashTable ht = newhashtable(size, name, NULL); + + ht->hash = hasher; + ht->emptytable = emptyhashtable; + ht->filltable = NULL; + ht->addnode = addhashnode; + ht->getnode = gethashnode2; + ht->getnode2 = gethashnode2; + ht->removenode = removehashnode; + ht->disablenode = NULL; + ht->enablenode = NULL; + ht->freenode = freeparamnode; + ht->printnode = printparamnode; + + return ht; +} + +/* Copy a parameter hash table */ + +static HashTable outtable; + +/**/ +static void +scancopyparams(HashNode hn, int flags) +{ + /* Going into a real parameter, so always use permanent storage */ + Param pm = (Param)hn; + Param tpm = (Param) zcalloc(sizeof *tpm); + tpm->nam = ztrdup(pm->nam); + copyparam(tpm, pm, 0); + addhashnode(outtable, tpm->nam, tpm); +} + +/**/ +HashTable +copyparamtable(HashTable ht, char *name) +{ + HashTable nht = newparamtable(ht->hsize, name); + outtable = nht; + scanhashtable(ht, 0, 0, 0, scancopyparams, 0); + outtable = NULL; + return nht; +} + +#define SCANPM_WANTVALS (1<<0) +#define SCANPM_WANTKEYS (1<<1) +#define SCANPM_WANTINDEX (1<<2) + +static unsigned numparamvals; + +/**/ +static void +scancountparams(HashNode hn, int flags) +{ + if (!(((Param)hn)->flags & PM_UNSET)) { + ++numparamvals; + if ((flags & SCANPM_WANTKEYS) && (flags & SCANPM_WANTVALS)) + ++numparamvals; + } +} + +static char **paramvals; + +/**/ +static void +scanparamvals(HashNode hn, int flags) +{ + struct value v; + v.pm = (Param)hn; + if (!(v.pm->flags & PM_UNSET)) { + if (flags & SCANPM_WANTKEYS) { + paramvals[numparamvals++] = v.pm->nam; + if (!(flags & SCANPM_WANTVALS)) + return; + } + v.isarr = (PM_TYPE(v.pm->flags) & (PM_ARRAY|PM_HASHED)); + v.inv = (flags & SCANPM_WANTINDEX); + v.a = 0; + v.b = -1; + paramvals[numparamvals++] = getstrvalue(&v); + } +} + +/**/ +char ** +paramvalarr(HashTable ht, unsigned flags) +{ + MUSTUSEHEAP("paramvalarr"); + numparamvals = 0; + if (ht) + scanhashtable(ht, 0, 0, 0, scancountparams, flags); + paramvals = (char **) alloc((numparamvals + 1) * sizeof(char *)); + if (ht) { + numparamvals = 0; + scanhashtable(ht, 0, 0, 0, scanparamvals, flags); + } + paramvals[numparamvals] = 0; + return paramvals; +} + +/* Return the full array (no indexing) referred to by a Value. * + * The array value is cached for the lifetime of the Value. */ + +/**/ +static char ** +getvaluearr(Value v) +{ + if (v->arr) + return v->arr; + else if (PM_TYPE(v->pm->flags) == PM_ARRAY) + return v->arr = v->pm->gets.afn(v->pm); + else if (PM_TYPE(v->pm->flags) == PM_HASHED) { + unsigned flags = 0; + if (v->a) + flags |= SCANPM_WANTKEYS; + if (v->b > v->a) + flags |= SCANPM_WANTVALS; + v->arr = paramvalarr(v->pm->gets.hfn(v->pm), flags); + /* Can't take numeric slices of associative arrays */ + v->a = 0; + v->b = -1; + return v->arr; + } else + return NULL; +} + /* Set up parameter hash table. This will add predefined * * parameter entries as well as setting up parameter table * * entries for environment variables we inherit. */ @@ -261,19 +396,7 @@ createparamtable(void) char buf[50], *str, *iname; int num_env; - paramtab = newhashtable(151, "paramtab", NULL); - - paramtab->hash = hasher; - paramtab->emptytable = NULL; - paramtab->filltable = NULL; - paramtab->addnode = addhashnode; - paramtab->getnode = gethashnode2; - paramtab->getnode2 = gethashnode2; - paramtab->removenode = removehashnode; - paramtab->disablenode = NULL; - paramtab->enablenode = NULL; - paramtab->freenode = freeparamnode; - paramtab->printnode = printparamnode; + paramtab = newparamtable(151, "paramtab"); /* Add the special parameters to the hash table */ for (ip = special_params; ip->nam; ip++) @@ -368,6 +491,36 @@ createparamtable(void) noerrs = 0; } +/* assign various functions used for non-special parameters */ + +/**/ +static void +assigngetset(Param pm) +{ + switch (PM_TYPE(pm->flags)) { + case PM_SCALAR: + pm->sets.cfn = strsetfn; + pm->gets.cfn = strgetfn; + break; + case PM_INTEGER: + pm->sets.ifn = intsetfn; + pm->gets.ifn = intgetfn; + break; + case PM_ARRAY: + pm->sets.afn = arrsetfn; + pm->gets.afn = arrgetfn; + break; + case PM_HASHED: + pm->sets.hfn = hashsetfn; + pm->gets.hfn = hashgetfn; + break; + default: + DPUTS(1, "BUG: tried to create param node without valid flag"); + break; + } + pm->unsetfn = stdunsetfn; +} + /* Create a parameter, so that it can be assigned to. Returns NULL if the * * parameter already exists or can't be created, otherwise returns the * * parameter node. If a parameter of the same name exists in an outer * @@ -413,27 +566,51 @@ createparam(char *name, int flags) pm = (Param) alloc(sizeof *pm); pm->flags = flags; - if(!(pm->flags & PM_SPECIAL)) { - switch (PM_TYPE(flags)) { + if(!(pm->flags & PM_SPECIAL)) + assigngetset(pm); + return pm; +} + +/* Copy a parameter */ + +/**/ +void +copyparam(Param tpm, Param pm, int toplevel) +{ + /* + * Note that tpm, into which we're copying, may not be in permanent + * storage. However, the values themselves are later used directly + * to set the parameter, so must be permanently allocated (in accordance + * with sets.?fn() usage). + */ + PERMALLOC { + tpm->flags = pm->flags; + if (!toplevel) + tpm->flags &= ~PM_SPECIAL; + switch (PM_TYPE(pm->flags)) { case PM_SCALAR: - pm->sets.cfn = strsetfn; - pm->gets.cfn = strgetfn; + tpm->u.str = ztrdup(pm->gets.cfn(pm)); break; case PM_INTEGER: - pm->sets.ifn = intsetfn; - pm->gets.ifn = intgetfn; + tpm->u.val = pm->gets.ifn(pm); break; case PM_ARRAY: - pm->sets.afn = arrsetfn; - pm->gets.afn = arrgetfn; + tpm->u.arr = arrdup(pm->gets.afn(pm)); break; - default: - DPUTS(1, "BUG: tried to create param node without valid flag"); + case PM_HASHED: + tpm->u.hash = copyparamtable(pm->gets.hfn(pm), pm->nam); break; } - pm->unsetfn = stdunsetfn; - } - return pm; + } LASTALLOC; + /* + * If called from inside an associative array, that array is later going + * to be passed as a real parameter, so we need the gets and sets + * functions to be useful. However, the saved associated array is + * not itself special, so we just use the standard ones. + * This is also why we switch off PM_SPECIAL. + */ + if (!toplevel) + assigngetset(tpm); } /* Return 1 if the string s is a valid identifier, else return 0. */ @@ -577,6 +754,23 @@ getarg(char **str, int *inv, Value v, int a2, long *w) singsub(&s); if (!rev) { + if (PM_TYPE(v->pm->flags) == PM_HASHED) { + HashTable ht = v->pm->gets.hfn(v->pm); + if (!ht) { + ht = newparamtable(17, v->pm->nam); + v->pm->sets.hfn(v->pm, ht); + } + if (!(v->pm = (Param) ht->getnode(ht, s))) { + HashTable tht = paramtab; + paramtab = ht; + v->pm = createparam(s, PM_SCALAR|PM_UNSET); + paramtab = tht; + } + v->isarr = 0; + v->a = 0; + *w = v->b = -1; + r = isset(KSHARRAYS) ? 1 : 0; + } else if (!(r = mathevalarg(s, &s)) || (isset(KSHARRAYS) && r >= 0)) r++; if (word && !v->isarr) { @@ -799,11 +993,12 @@ getvalue(char **pptr, int bracks) s = t = *pptr; garr = NULL; - if (idigit(*s)) + if (idigit(*s)) { if (bracks >= 0) ppar = zstrtol(s, &s, 10); else ppar = *s++ - '0'; + } else if (iident(*s)) while (iident(*s)) s++; @@ -844,7 +1039,7 @@ getvalue(char **pptr, int bracks) if (!pm || (pm->flags & PM_UNSET)) return NULL; v = (Value) hcalloc(sizeof *v); - if (PM_TYPE(pm->flags) == PM_ARRAY) + if (PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED)) v->isarr = isvarat ? -1 : 1; v->pm = pm; v->inv = 0; @@ -863,12 +1058,12 @@ getvalue(char **pptr, int bracks) *pptr = s; if (v->a > MAX_ARRLEN || v->a < -MAX_ARRLEN) { - zerr("subscript to %s: %d", (v->a < 0) ? "small" : "big", v->a); + zerr("subscript too %s: %d", (v->a < 0) ? "small" : "big", v->a); return NULL; } if (v->b > MAX_ARRLEN || v->b < -MAX_ARRLEN) { - zerr("subscript to %s: %d", (v->b < 0) ? "small" : "big", v->b); + zerr("subscript too %s: %d", (v->b < 0) ? "small" : "big", v->b); return NULL; } return v; @@ -891,11 +1086,12 @@ getstrvalue(Value v) } switch(PM_TYPE(v->pm->flags)) { + case PM_HASHED: case PM_ARRAY: + ss = getvaluearr(v); if (v->isarr) - s = sepjoin(v->pm->gets.afn(v->pm), NULL); + s = sepjoin(ss, NULL); else { - ss = v->pm->gets.afn(v->pm); if (v->a < 0) v->a += arrlen(ss); s = (v->a >= arrlen(ss) || v->a < 0) ? (char *) hcalloc(1) : ss[v->a]; @@ -913,8 +1109,9 @@ getstrvalue(Value v) break; } - if (v->a == 0 && v->b == -1) + if (v->a == 0 && v->b == -1) { LASTALLOC_RETURN s; + } if (v->a < 0) v->a += strlen(s); if (v->b < 0) @@ -946,7 +1143,7 @@ getarrvalue(Value v) s[0] = dupstring(buf); return s; } - s = v->pm->gets.afn(v->pm); + s = getvaluearr(v); if (v->a == 0 && v->b == -1) return s; if (v->a < 0) @@ -993,6 +1190,7 @@ setstrvalue(Value v, char *val) zsfree(val); return; } + v->pm->flags &= ~PM_UNSET; switch (PM_TYPE(v->pm->flags)) { case PM_SCALAR: MUSTUSEHEAP("setstrvalue"); @@ -1103,17 +1301,25 @@ setarrvalue(Value v, char **val) freearray(val); return; } - if (PM_TYPE(v->pm->flags) != PM_ARRAY) { + if (PM_TYPE(v->pm->flags) & ~(PM_ARRAY|PM_HASHED)) { freearray(val); zerr("attempt to assign array value to non-array", NULL, 0); return; } - if (v->a == 0 && v->b == -1) - (v->pm->sets.afn) (v->pm, val); - else { + if (v->a == 0 && v->b == -1) { + if (PM_TYPE(v->pm->flags) == PM_HASHED) + arrhashsetfn(v->pm, val); + else + (v->pm->sets.afn) (v->pm, val); + } else { char **old, **new, **p, **q, **r; int n, ll, i; + if ((PM_TYPE(v->pm->flags) == PM_HASHED)) { + freearray(val); + zerr("attempt to set slice of associative array", NULL, 0); + return; + } if (v->inv && unset(KSHARRAYS)) v->a--, v->b--; q = old = v->pm->gets.afn(v->pm); @@ -1187,6 +1393,20 @@ getaparam(char *s) return NULL; } +/* Retrieve an assoc array parameter as an array */ + +/**/ +char ** +gethparam(char *s) +{ + Value v; + + if (!idigit(*s) && (v = getvalue(&s, 0)) && + PM_TYPE(v->pm->flags) == PM_HASHED) + return paramvalarr(v->pm->gets.hfn(v->pm), SCANPM_WANTVALS); + return NULL; +} + /**/ Param setsparam(char *s, char *val) @@ -1248,7 +1468,7 @@ setaparam(char *s, char **val) } else { if (!(v = getvalue(&s, 1))) createparam(t, PM_ARRAY); - else if (PM_TYPE(v->pm->flags) != PM_ARRAY && + else if (!(PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) && !(v->pm->flags & PM_SPECIAL)) { int uniq = v->pm->flags & PM_UNIQUE; unsetparam(t); @@ -1338,7 +1558,7 @@ unsetparam_pm(Param pm, int altflag, int exp) * is called. Beyond that, there is an ambiguity: should * * foo() { local bar; unset bar; } make the global bar * * available or not? The following makes the answer "no". */ - if (locallevel >= pm->level) + if ((locallevel && locallevel >= pm->level) || (pm->flags & PM_SPECIAL)) return; paramtab->removenode(paramtab, pm->nam); /* remove parameter node from table */ @@ -1363,6 +1583,7 @@ stdunsetfn(Param pm, int exp) switch (PM_TYPE(pm->flags)) { case PM_SCALAR: pm->sets.cfn(pm, NULL); break; case PM_ARRAY: pm->sets.afn(pm, NULL); break; + case PM_HASHED: pm->sets.hfn(pm, NULL); break; } pm->flags |= PM_UNSET; } @@ -1429,6 +1650,70 @@ arrsetfn(Param pm, char **x) pm->u.arr = x; } +/* Function to get value of an association parameter */ + +/**/ +static HashTable +hashgetfn(Param pm) +{ + return pm->u.hash; +} + +/* Flag to freeparamnode to unset the struct */ + +static int delunset; + +/* Function to set value of an association parameter */ + +/**/ +static void +hashsetfn(Param pm, HashTable x) +{ + if (pm->u.hash && pm->u.hash != x) { + /* The parameters in the hash table need to be unset * + * before being deleted. */ + int odelunset = delunset; + delunset = 1; + deletehashtable(pm->u.hash); + delunset = odelunset; + } + pm->u.hash = x; +} + +/* Function to set value of an association parameter using key/value pairs */ + +/**/ +static void +arrhashsetfn(Param pm, char **val) +{ + /* Best not to shortcut this by using the existing hash table, * + * since that could cause trouble for special hashes. This way, * + * it's up to pm->sets.hfn() what to do. */ + int alen = arrlen(val); + HashTable opmtab = paramtab, ht; + char **aptr = val; + Value v = (Value) hcalloc(sizeof *v); + v->b = -1; + + if (alen % 2) { + freearray(val); + zerr("bad set of key/value pairs for associative array\n", + NULL, 0); + return; + } + ht = paramtab = newparamtable(17, pm->nam); + while (*aptr) { + /* The parameter name is ztrdup'd... */ + v->pm = createparam(*aptr, PM_SCALAR|PM_UNSET); + zsfree(*aptr++); + /* ...but we can use the value without copying. */ + setstrvalue(v, *aptr++); + } + paramtab = opmtab; + pm->sets.hfn(pm, ht); + free(val); /* not freearray() */ +} + /* This function is used as the set function for * * special parameters that cannot be set by the user. */ @@ -2189,3 +2474,107 @@ scanendscope(HashNode hn, int flags) if(pm->level > locallevel) unsetparam_pm(pm, 0, 0); } + + +/**********************************/ +/* Parameter Hash Table Functions */ +/**********************************/ + +/**/ +void +freeparamnode(HashNode hn) +{ + Param pm = (Param) hn; + + /* Since the second flag to unsetfn isn't used, I don't * + * know what its value should be. */ + if (delunset) + pm->unsetfn(pm, 1); + zsfree(pm->nam); + zfree(pm, sizeof(struct param)); +} + +/* Print a parameter */ + +/**/ +void +printparamnode(HashNode hn, int printflags) +{ + Param p = (Param) hn; + char *t, **u; + + if (p->flags & PM_UNSET) + return; + + /* Print the attributes of the parameter */ + if (printflags & PRINT_TYPE) { + if (p->flags & PM_INTEGER) + printf("integer "); + else if (p->flags & PM_ARRAY) + printf("array "); + else if (p->flags & PM_HASHED) + printf("association "); + if (p->flags & PM_LEFT) + printf("left justified %d ", p->ct); + if (p->flags & PM_RIGHT_B) + printf("right justified %d ", p->ct); + if (p->flags & PM_RIGHT_Z) + printf("zero filled %d ", p->ct); + if (p->flags & PM_LOWER) + printf("lowercase "); + if (p->flags & PM_UPPER) + printf("uppercase "); + if (p->flags & PM_READONLY) + printf("readonly "); + if (p->flags & PM_TAGGED) + printf("tagged "); + if (p->flags & PM_EXPORTED) + printf("exported "); + } + + if (printflags & PRINT_NAMEONLY) { + zputs(p->nam, stdout); + putchar('\n'); + return; + } + + /* How the value is displayed depends * + * on the type of the parameter */ + quotedzputs(p->nam, stdout); + putchar('='); + switch (PM_TYPE(p->flags)) { + case PM_SCALAR: + /* string: simple output */ + if (p->gets.cfn && (t = p->gets.cfn(p))) + quotedzputs(t, stdout); + putchar('\n'); + break; + case PM_INTEGER: + /* integer */ + printf("%ld\n", p->gets.ifn(p)); + break; + case PM_ARRAY: + /* array */ + putchar('('); + u = p->gets.afn(p); + if(*u) { + quotedzputs(*u++, stdout); + while (*u) { + putchar(' '); + quotedzputs(*u++, stdout); + } + } + printf(")\n"); + break; + case PM_HASHED: + /* association */ + putchar('('); + { + HashTable ht = p->gets.hfn(p); + if (ht) + scanhashtable(ht, 0, 0, 0, ht->printnode, 0); + } + printf(")\n"); + break; + } +} diff --git a/Src/prompt.c b/Src/prompt.c index 8c9216f95..69823a5e3 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -71,6 +71,10 @@ static int bufspc; static char *bp; +/* Position of the start of the current line in the buffer */ + +static char *bufline; + /* bp1 is an auxilliary pointer into the buffer, which when non-NULL is * * moved whenever the buffer is reallocated. It is used when data is * * being temporarily held in the buffer. */ @@ -81,11 +85,9 @@ static char *bp1; static char *fm; -/* Current truncation string (metafied), the length at which truncation * - * occurs, and the direction in which it occurs. */ +/* Non-zero if truncating the current segment of the buffer. */ -static char *truncstr; -static int trunclen, truncatleft; +static int trunclen; /* Current level of nesting of %{ / %} sequences. */ @@ -95,10 +97,6 @@ static int dontcount; static char *rstring, *Rstring; -/* If non-zero, Inpar, Outpar and Nularg can be added to the buffer. */ - -static int nonsp; - /* Perform prompt expansion on a string, putting the result in a * * permanently-allocated string. If ns is non-zero, this string * * may have embedded Inpar and Outpar, which indicate a toggling * @@ -130,9 +128,8 @@ promptexpand(char *s, int ns, char *rs, char *Rs) rstring = rs; Rstring = Rs; - nonsp = ns; fm = s; - bp = buf = zalloc(bufspc = 256); + bp = bufline = buf = zalloc(bufspc = 256); bp1 = NULL; trunclen = 0; putpromptchar(1, '\0'); @@ -140,6 +137,15 @@ promptexpand(char *s, int ns, char *rs, char *Rs) if(dontcount) *bp++ = Outpar; *bp = 0; + if (!ns) { + /* If zero, Inpar, Outpar and Nularg should be removed. */ + for (bp = buf; *bp; bp++) { + if (*bp == Meta) + bp++; + else if (*bp == Inpar || *bp == Outpar || *bp == Nularg) + chuck(bp); + } + } return buf; } @@ -164,7 +170,7 @@ putpromptchar(int doprint, int endchar) arg = zstrtol(fm, &fm, 10); } if (*fm == '(') { - int tc; + int tc, otrunclen; if (idigit(*++fm)) { arg = zstrtol(fm, &fm, 10); @@ -224,6 +230,12 @@ putpromptchar(int doprint, int endchar) if (getegid() == arg) test = 1; break; + case 'l': + *bp = '\0'; + countprompt(bufline, &t0, 0); + if (t0 >= arg) + test = 1; + break; case 'L': if (shlvl >= arg) test = 1; @@ -249,10 +261,15 @@ putpromptchar(int doprint, int endchar) if (!*fm || !(sep = *++fm)) return 0; fm++; + /* Don't do the current truncation until we get back */ + otrunclen = trunclen; + trunclen = 0; if (!putpromptchar(test == 1 && doprint, sep) || !*++fm || !putpromptchar(test == 0 && doprint, ')')) { + trunclen = otrunclen; return 0; } + trunclen = otrunclen; continue; } if (!doprint) @@ -377,72 +394,24 @@ putpromptchar(int doprint, int endchar) tsetcap(TCUNDERLINEEND, 1); break; case '[': - if (idigit(*++fm)) - trunclen = zstrtol(fm, &fm, 10); - else - trunclen = arg; - if (trunclen) { - truncatleft = *fm && *fm != ']' && *fm++ == '<'; - bp1 = bp; - while (*fm && *fm != ']') { - if (*fm == '\\' && fm[1]) - ++fm; - addbufspc(1); - *bp++ = *fm++; - } - addbufspc(2); - if (bp1 == bp) - *bp++ = '<'; - *bp = '\0'; - zsfree(truncstr); - truncstr = ztrdup(bp = bp1); - bp1 = NULL; - } else { - while (*fm && *fm != ']') { - if (*fm == '\\' && fm[1]) - fm++; - fm++; - } - } - if(!*fm) - return 0; + if (idigit(*++fm)) + arg = zstrtol(fm, &fm, 10); + if (!prompttrunc(arg, ']', doprint, endchar)) + return *fm; break; case '<': case '>': - if((trunclen = arg)) { - char ch = *fm++; - truncatleft = ch == '<'; - bp1 = bp; - while (*fm && *fm != ch) { - if (*fm == '\\' && fm[1]) - ++fm; - addbufspc(1); - *bp++ = *fm++; - } - addbufspc(1); - *bp = '\0'; - zsfree(truncstr); - truncstr = ztrdup(bp = bp1); - bp1 = NULL; - } else { - char ch = *fm++; - while(*fm && *fm != ch) { - if (*fm == '\\' && fm[1]) - fm++; - fm++; - } - } - if(!*fm) - return 0; + if (!prompttrunc(arg, *fm, doprint, endchar)) + return *fm; break; case '{': /*}*/ - if (!dontcount++ && nonsp) { + if (!dontcount++) { addbufspc(1); *bp++ = Inpar; } break; case /*{*/ '}': - if (dontcount && !--dontcount && nonsp) { + if (dontcount && !--dontcount) { addbufspc(1); *bp++ = Outpar; } @@ -569,7 +538,7 @@ putpromptchar(int doprint, int endchar) break; } } else if(*fm == '!' && isset(PROMPTBANG)) { - if(doprint) + if(doprint) { if(fm[1] == '!') { fm++; addbufspc(1); @@ -579,6 +548,7 @@ putpromptchar(int doprint, int endchar) sprintf(bp, "%d", curhist); bp += strlen(bp); } + } } else { char c = *fm == Meta ? *++fm ^ 32 : *fm; @@ -604,6 +574,8 @@ pputc(char c) c ^= 32; } *bp++ = c; + if (c == '\n' && !dontcount) + bufline = bp; } /* Make sure there is room for `need' more characters in the buffer. */ @@ -627,46 +599,19 @@ addbufspc(int need) } /* stradd() adds a metafied string to the prompt, * - * in a visible representation, doing truncation. */ + * in a visible representation. */ /**/ void stradd(char *d) { - /* dlen is the full length of the string we want to add */ - int dlen = niceztrlen(d); - char *ps, *pd, *pc, *t; - int tlen, maxlen; - addbufspc(dlen); + char *ps, *pc; + addbufspc(niceztrlen(d)); /* This loop puts the nice representation of the string into the prompt * - * buffer. It might be modified later. Note that bp isn't changed. */ - for(ps=d, pd=bp; *ps; ps++) + * buffer. */ + for(ps=d; *ps; ps++) for(pc=nicechar(*ps == Meta ? STOUC(*++ps)^32 : STOUC(*ps)); *pc; pc++) - *pd++ = *pc; - if(!trunclen || dlen <= trunclen) { - /* No truncation is needed, so update bp and return, * - * leaving the full string in the prompt. */ - bp += dlen; - return; - } - /* We need to truncate. t points to the truncation string -- which is * - * inserted literally, without nice representation. tlen is its * - * length, and maxlen is the amout of the main string that we want to * - * keep. Note that if the truncation string is longer than the * - * truncation length (tlen > trunclen), the truncation string is used * - * in full. */ - addbufspc(tlen = ztrlen(t = truncstr)); - maxlen = tlen < trunclen ? trunclen - tlen : 0; - if(truncatleft) { - memmove(bp + strlen(t), bp + dlen - maxlen, maxlen); - while(*t) - *bp++ = *t++; - bp += maxlen; - } else { - bp += maxlen; - while(*t) - *bp++ = *t++; - } + *bp++ = *pc; } /* tsetcap(), among other things, can write a termcap string into the buffer. */ @@ -684,12 +629,12 @@ tsetcap(int cap, int flag) tputs(tcstr[cap], 1, putshout); break; case 1: - if (!dontcount && nonsp) { + if (!dontcount) { addbufspc(1); *bp++ = Inpar; } tputs(tcstr[cap], 1, putstr); - if (!dontcount && nonsp) { + if (!dontcount) { int glitch = 0; if (cap == TCSTANDOUTBEG || cap == TCSTANDOUTEND) @@ -764,3 +709,108 @@ countprompt(char *str, int *wp, int *hp) if(hp) *hp = h; } + +/**/ +static int +prompttrunc(int arg, int truncchar, int doprint, int endchar) +{ + if (arg) { + char ch = *fm, *ptr = bp, *truncstr; + int truncatleft = ch == '<'; + + /* + * If there is already a truncation active, return so that + * can be finished, backing up so that the new truncation + * can be started afterwards. + */ + if (trunclen) { + while (*--fm != '%') + ; + fm--; + return 0; + } + + trunclen = arg; + if (*fm != ']') + fm++; + while (*fm && *fm != truncchar) { + if (*fm == '\\' && fm[1]) + ++fm; + addbufspc(1); + *bp++ = *fm++; + } + if (!*fm) + return 0; + if (bp == ptr && truncchar == ']') { + addbufspc(1); + *bp++ = '<'; + } + truncstr = ztrduppfx(ptr, bp - ptr); + + bp = ptr; + fm++; + putpromptchar(doprint, endchar); + *bp = '\0'; + if (bp - ptr > trunclen) { + /* + * We need to truncate. t points to the truncation string -- * + * which is inserted literally, without nice representation. * + * tlen is its length, and maxlen is the amount of the main * + * string that we want to keep. Note that if the truncation * + * string is longer than the truncation length (tlen > * + * trunclen), the truncation string is used in full. * + */ + char *t = truncstr; + int fullen = bp - ptr; + int tlen = ztrlen(t), maxlen; + if (tlen > fullen) { + addbufspc(tlen - fullen); + bp += tlen - fullen; + } else + bp -= fullen - trunclen; + maxlen = tlen < trunclen ? trunclen - tlen : 0; + if (truncatleft) { + if (maxlen) + memmove(ptr + strlen(t), ptr + fullen - maxlen, + maxlen); + while (*t) + *ptr++ = *t++; + } else { + ptr += maxlen; + while (*t) + *ptr++ = *t++; + } + } + zsfree(truncstr); + trunclen = 0; + /* + * We may have returned early from the previous putpromptchar * + * because we found another truncation following this one. * + * In that case we need to do the rest now. * + */ + if (!*fm) + return 0; + if (*fm != endchar) { + fm++; + /* + * With trunclen set to zero, we always reach endchar * + * (or the terminating NULL) this time round. * + */ + if (!putpromptchar(doprint, endchar)) + return 0; + /* Now we have to trick it into matching endchar again */ + fm--; + } + } else { + if (*fm != ']') + fm++; + while(*fm && *fm != truncchar) { + if (*fm == '\\' && fm[1]) + fm++; + fm++; + } + if (trunclen || !*fm) + return 0; + } + return 1; +} diff --git a/Src/subst.c b/Src/subst.c index 8f840d266..cc1ae3027 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -716,6 +716,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) int eval = 0; int nojoin = 0; char inbrace = 0; /* != 0 means ${...}, otherwise $... */ + char hkeys = 0; /* 1 means get keys from associative array */ + char hvals = 1; /* > hkeys get values of associative array */ *s++ = '\0'; if (!ialnum(*s) && *s != '#' && *s != Pound && *s != '-' && @@ -732,12 +734,16 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) if (*s == Inbrace) { inbrace = 1; s++; - if (*s == '(' || *s == Inpar) { + if (*s == '!' && s[1] != Outbrace && emulation == EMULATE_KSH) { + hkeys = 1; + s++; + } else if (*s == '(' || *s == Inpar) { char *t, sav; int tt = 0; long num; int escapes = 0; int klen; +#define UNTOK(C) (itok(C) ? ztokens[(C) - Pound] : (C)) #define UNTOK_AND_ESCAPE(X) {\ untokenize(X = dupstring(s + 1));\ if (escapes) {\ @@ -851,7 +857,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) prenum = num; else postnum = num; - if (s[1] != sav) + if (UNTOK(s[1]) != UNTOK(sav)) break; t = get_strarg(++s); if (!*t) @@ -865,7 +871,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) *t = sav; sav = *s; s = t + 1; - if (*s != sav) { + if (UNTOK(*s) != UNTOK(sav)) { s--; break; } @@ -886,6 +892,13 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) escapes = 1; break; + case 'k': + hkeys = 1; + break; + case 'v': + hvals = 2; + break; + default: flagerr: zerr("error in flags", NULL, 0); @@ -986,9 +999,16 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) if (getindex(&s, v) || s == os) break; } - if ((isarr = v->isarr)) + if ((isarr = v->isarr)) { + /* No way to reach here with v->inv != 0, so getvaluearr() * + * will definitely be called by getarrvalue(). Slicing of * + * associations isn't done, so use v->a and v->b for flags */ + if (PM_TYPE(v->pm->flags) == PM_HASHED) { + v->a = hkeys; + v->b = hvals; + } aval = getarrvalue(v); - else { + } else { if (v->pm->flags & PM_ARRAY) { int tmplen = arrlen(v->pm->gets.afn(v->pm)); diff --git a/Src/text.c b/Src/text.c index b7df8012f..836a6a0a8 100644 --- a/Src/text.c +++ b/Src/text.c @@ -450,6 +450,8 @@ getsimptext(Cmd cmd) taddchr('('); taddlist(v->arr); taddstr(") "); + } else if (PM_TYPE(v->type) == PM_HASHED) { + /* XXX */ } else { taddstr(v->str); taddchr(' '); diff --git a/Src/utils.c b/Src/utils.c index 87f82f7df..44223867f 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -510,8 +510,8 @@ adduserdir(char *s, char *t, int flags, int always) if ((flags & ND_USERNAME) && nameddirtab->getnode2(nameddirtab, s)) return; - /* Never hash PWD, because it's never useful */ - if (!strcmp(s, "PWD")) + /* Never hash PWD unless it was explicitly requested */ + if (!always && !strcmp(s, "PWD")) return; /* Normal parameter assignments generate calls to this function, * diff --git a/Src/zsh.export b/Src/zsh.export index 8f676c7fd..701aeb990 100644 --- a/Src/zsh.export +++ b/Src/zsh.export @@ -59,6 +59,7 @@ freeheap getaparam gethashnode gethashnode2 +gethparam getiparam getkeystring getlinknode diff --git a/Src/zsh.h b/Src/zsh.h index d833278c9..837a76e88 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -538,6 +538,7 @@ struct value { int inv; /* should we return the index ? */ int a; /* first element of array slice, or -1 */ int b; /* last element of array slice, or -1 */ + char **arr; /* cache for hash turned into array */ }; /* structure for foo=bar assignments */ @@ -813,6 +814,7 @@ struct param { char **arr; /* value if declared array (PM_ARRAY) */ char *str; /* value if declared string (PM_SCALAR) */ long val; /* value if declared integer (PM_INTEGER) */ + HashTable hash; /* value if declared assoc (PM_HASHED) */ } u; /* pointer to function to set value of this parameter */ @@ -820,6 +822,7 @@ struct param { void (*cfn) _((Param, char *)); void (*ifn) _((Param, long)); void (*afn) _((Param, char **)); + void (*hfn) _((Param, HashTable)); } sets; /* pointer to function to get value of this parameter */ @@ -827,6 +830,7 @@ struct param { char *(*cfn) _((Param)); long (*ifn) _((Param)); char **(*afn) _((Param)); + HashTable (*hfn) _((Param)); } gets; /* pointer to function to unset this parameter */ @@ -845,8 +849,9 @@ struct param { #define PM_SCALAR 0 /* scalar */ #define PM_ARRAY (1<<0) /* array */ #define PM_INTEGER (1<<1) /* integer */ +#define PM_HASHED (1<<15) /* association */ -#define PM_TYPE(X) (X & (PM_SCALAR|PM_INTEGER|PM_ARRAY)) +#define PM_TYPE(X) (X & (PM_SCALAR|PM_INTEGER|PM_ARRAY|PM_HASHED)) #define PM_LEFT (1<<2) /* left justify and remove leading blanks */ #define PM_RIGHT_B (1<<3) /* right justify and fill with leading blanks */ |