From f99f7dca7552d21782354f675c0741896c9785f1 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 8 Oct 2018 10:10:42 +0100 Subject: 43616: Various parameter setting and display fixes. Mostly to do with typeset -p and tied variables and their interaction. Some general tied variable fixes. --- Src/Modules/db_gdbm.c | 2 +- Src/Modules/parameter.c | 44 +++++++------ Src/builtin.c | 155 +++++++++++++++++++++++++++++++------------ Src/hashtable.h | 1 + Src/params.c | 172 ++++++++++++++++++++++++++++++------------------ Src/subst.c | 4 +- Src/zsh.h | 23 ++++--- 7 files changed, 262 insertions(+), 139 deletions(-) (limited to 'Src') diff --git a/Src/Modules/db_gdbm.c b/Src/Modules/db_gdbm.c index ed702b912..12dd839cf 100644 --- a/Src/Modules/db_gdbm.c +++ b/Src/Modules/db_gdbm.c @@ -809,7 +809,7 @@ myfreeparamnode(HashNode hn) zsfree(pm->node.nam); /* If this variable was tied by the user, ename was ztrdup'd */ - if (pm->node.flags & PM_TIED && pm->ename) { + if (!(pm->node.flags & PM_SPECIAL) && pm->ename) { zsfree(pm->ename); pm->ename = NULL; } diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index 783c36df3..76824cf58 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -75,6 +75,8 @@ paramtypestr(Param pm) val = dyncat(val, "-readonly"); if (f & PM_TAGGED) val = dyncat(val, "-tag"); + if (f & PM_TIED) + val = dyncat(val, "-tied"); if (f & PM_EXPORTED) val = dyncat(val, "-export"); if (f & PM_UNIQUE) @@ -2194,67 +2196,67 @@ static const struct gsu_array historywords_gsu = static struct paramdef partab[] = { SPECIALPMDEF("aliases", 0, &pmraliases_gsu, getpmralias, scanpmraliases), - SPECIALPMDEF("builtins", PM_READONLY, NULL, getpmbuiltin, scanpmbuiltins), + SPECIALPMDEF("builtins", PM_READONLY_SPECIAL, NULL, getpmbuiltin, scanpmbuiltins), SPECIALPMDEF("commands", 0, &pmcommands_gsu, getpmcommand, scanpmcommands), SPECIALPMDEF("dirstack", PM_ARRAY, &dirs_gsu, NULL, NULL), SPECIALPMDEF("dis_aliases", 0, &pmdisraliases_gsu, getpmdisralias, scanpmdisraliases), - SPECIALPMDEF("dis_builtins", PM_READONLY, + SPECIALPMDEF("dis_builtins", PM_READONLY_SPECIAL, NULL, getpmdisbuiltin, scanpmdisbuiltins), SPECIALPMDEF("dis_functions", 0, &pmdisfunctions_gsu, getpmdisfunction, scanpmdisfunctions), - SPECIALPMDEF("dis_functions_source", PM_READONLY, NULL, + SPECIALPMDEF("dis_functions_source", PM_READONLY_SPECIAL, NULL, getpmdisfunction_source, scanpmdisfunction_source), SPECIALPMDEF("dis_galiases", 0, &pmdisgaliases_gsu, getpmdisgalias, scanpmdisgaliases), - SPECIALPMDEF("dis_patchars", PM_ARRAY|PM_READONLY, + SPECIALPMDEF("dis_patchars", PM_ARRAY|PM_READONLY_SPECIAL, &dispatchars_gsu, NULL, NULL), - SPECIALPMDEF("dis_reswords", PM_ARRAY|PM_READONLY, + SPECIALPMDEF("dis_reswords", PM_ARRAY|PM_READONLY_SPECIAL, &disreswords_gsu, NULL, NULL), SPECIALPMDEF("dis_saliases", 0, &pmdissaliases_gsu, getpmdissalias, scanpmdissaliases), - SPECIALPMDEF("funcfiletrace", PM_ARRAY|PM_READONLY, + SPECIALPMDEF("funcfiletrace", PM_ARRAY|PM_READONLY_SPECIAL, &funcfiletrace_gsu, NULL, NULL), - SPECIALPMDEF("funcsourcetrace", PM_ARRAY|PM_READONLY, + SPECIALPMDEF("funcsourcetrace", PM_ARRAY|PM_READONLY_SPECIAL, &funcsourcetrace_gsu, NULL, NULL), - SPECIALPMDEF("funcstack", PM_ARRAY|PM_READONLY, + SPECIALPMDEF("funcstack", PM_ARRAY|PM_READONLY_SPECIAL, &funcstack_gsu, NULL, NULL), SPECIALPMDEF("functions", 0, &pmfunctions_gsu, getpmfunction, scanpmfunctions), - SPECIALPMDEF("functions_source", PM_READONLY, NULL, + SPECIALPMDEF("functions_source", PM_READONLY_SPECIAL, NULL, getpmfunction_source, scanpmfunction_source), - SPECIALPMDEF("functrace", PM_ARRAY|PM_READONLY, + SPECIALPMDEF("functrace", PM_ARRAY|PM_READONLY_SPECIAL, &functrace_gsu, NULL, NULL), SPECIALPMDEF("galiases", 0, &pmgaliases_gsu, getpmgalias, scanpmgaliases), - SPECIALPMDEF("history", PM_READONLY, + SPECIALPMDEF("history", PM_READONLY_SPECIAL, NULL, getpmhistory, scanpmhistory), - SPECIALPMDEF("historywords", PM_ARRAY|PM_READONLY, + SPECIALPMDEF("historywords", PM_ARRAY|PM_READONLY_SPECIAL, &historywords_gsu, NULL, NULL), - SPECIALPMDEF("jobdirs", PM_READONLY, + SPECIALPMDEF("jobdirs", PM_READONLY_SPECIAL, NULL, getpmjobdir, scanpmjobdirs), - SPECIALPMDEF("jobstates", PM_READONLY, + SPECIALPMDEF("jobstates", PM_READONLY_SPECIAL, NULL, getpmjobstate, scanpmjobstates), - SPECIALPMDEF("jobtexts", PM_READONLY, + SPECIALPMDEF("jobtexts", PM_READONLY_SPECIAL, NULL, getpmjobtext, scanpmjobtexts), - SPECIALPMDEF("modules", PM_READONLY, + SPECIALPMDEF("modules", PM_READONLY_SPECIAL, NULL, getpmmodule, scanpmmodules), SPECIALPMDEF("nameddirs", 0, &pmnameddirs_gsu, getpmnameddir, scanpmnameddirs), SPECIALPMDEF("options", 0, &pmoptions_gsu, getpmoption, scanpmoptions), - SPECIALPMDEF("parameters", PM_READONLY, + SPECIALPMDEF("parameters", PM_READONLY_SPECIAL, NULL, getpmparameter, scanpmparameters), - SPECIALPMDEF("patchars", PM_ARRAY|PM_READONLY, + SPECIALPMDEF("patchars", PM_ARRAY|PM_READONLY_SPECIAL, &patchars_gsu, NULL, NULL), - SPECIALPMDEF("reswords", PM_ARRAY|PM_READONLY, + SPECIALPMDEF("reswords", PM_ARRAY|PM_READONLY_SPECIAL, &reswords_gsu, NULL, NULL), SPECIALPMDEF("saliases", 0, &pmsaliases_gsu, getpmsalias, scanpmsaliases), - SPECIALPMDEF("userdirs", PM_READONLY, + SPECIALPMDEF("userdirs", PM_READONLY_SPECIAL, NULL, getpmuserdir, scanpmuserdirs), - SPECIALPMDEF("usergroups", PM_READONLY, + SPECIALPMDEF("usergroups", PM_READONLY_SPECIAL, NULL, getpmusergroups, scanpmusergroups) }; diff --git a/Src/builtin.c b/Src/builtin.c index 4abc7da35..c5b319b68 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -64,7 +64,7 @@ static struct builtin builtins[] = BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmprs", 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_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%TUZ:%afhi:%lp:%rtu", "xg"), + BUILTIN("export", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, BIN_EXPORT, "E:%F:%HL:%R:%TUZ:%afhi:%lp:%rtu", "xg"), BUILTIN("false", 0, bin_false, 0, -1, 0, NULL, NULL), /* * We used to behave as if the argument to -e was optional. @@ -2258,6 +2258,22 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), } else if (pm->env && !(pm->node.flags & PM_HASHELEM)) delenv(pm); DPUTS(ASG_ARRAYP(asg), "BUG: typeset got array value where scalar expected"); + if (altpm) { + struct tieddata* tdp = (struct tieddata *) pm->u.data; + if (tdp) { + if (tdp->joinchar != joinchar && !asg->value.scalar) { + /* + * Reassign the scalar to itself to do the splitting with + * the new joinchar + */ + tdp->joinchar = joinchar; + if (!(pm = assignsparam(pname, ztrdup(getsparam(pname)), 0))) + return NULL; + } + } + else + DPUTS(!tdp, "BUG: no join character to update"); + } if (asg->value.scalar && !(pm = assignsparam(pname, ztrdup(asg->value.scalar), 0))) return NULL; @@ -2325,6 +2341,9 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), zerrnam(cname, "%s: can only have a single instance", pname); return pm; } + + on |= pm->node.flags & PM_TIED; + /* * For specials, we keep the same struct but zero everything. * Maybe it would be easier to create a new struct but copy @@ -2476,7 +2495,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), return NULL; } - if (altpm && PM_TYPE(pm->node.flags) == PM_SCALAR) { + if (altpm && PM_TYPE(pm->node.flags) == PM_SCALAR && !(pm->node.flags & PM_SPECIAL)) { /* * It seems safer to set this here than in createparam(), * to make sure we only ever use the colonarr functions @@ -2646,7 +2665,17 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func) /* Given no arguments, list whatever the options specify. */ if (OPT_ISSET(ops,'p')) { - printflags |= PRINT_TYPESET; + + if (isset(POSIXBUILTINS) && SHELL_EMULATION() != EMULATE_KSH) { + if (func == BIN_EXPORT) + printflags |= PRINT_POSIX_EXPORT; + else if (func == BIN_READONLY) + printflags |= PRINT_POSIX_READONLY; + else + printflags |= PRINT_TYPESET; + } else + printflags |= PRINT_TYPESET; + if (OPT_HASARG(ops,'p')) { char *eptr; int pflag = (int)zstrtol(OPT_ARG(ops,'p'), &eptr, 10); @@ -2662,13 +2691,20 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func) } hasargs = *argv != NULL || (assigns && firstnode(assigns)); if (!hasargs) { + int exclude = 0; if (!OPT_ISSET(ops,'p')) { if (!(on|roff)) printflags |= PRINT_TYPE; if (roff || OPT_ISSET(ops,'+')) printflags |= PRINT_NAMEONLY; + } else if (printflags & (PRINT_POSIX_EXPORT|PRINT_POSIX_READONLY)) { + /* + * For POSIX export/readonly, exclude non-scalars unless + * explicitly requested. + */ + exclude = (PM_ARRAY|PM_HASHED) & ~(on|roff); } - scanhashtable(paramtab, 1, on|roff, 0, paramtab->printnode, printflags); + scanhashtable(paramtab, 1, on|roff, exclude, paramtab->printnode, printflags); unqueue_signals(); return 0; } @@ -2683,6 +2719,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func) struct asgment asg0, asg2; char *oldval = NULL, *joinstr; int joinchar, nargs; + int already_tied = 0; if (OPT_ISSET(ops,'m')) { zwarnnam(name, "incompatible options for -T"); @@ -2765,47 +2802,81 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func) joinchar = joinstr[1] ^ 32; else joinchar = *joinstr; - /* - * Keep the old value of the scalar. We need to do this - * here as if it is already tied to the same array it - * will be unset when we retie the array. This is all - * so that typeset -T is idempotent. - * - * We also need to remember here whether the damn thing is - * exported and pass that along. Isn't the world complicated? - */ - if ((pm = (Param) paramtab->getnode(paramtab, asg0.name)) - && !(pm->node.flags & PM_UNSET) - && (locallevel == pm->level || !(on & PM_LOCAL))) { - if (pm->node.flags & PM_TIED) { + + pm = (Param) paramtab->getnode(paramtab, asg0.name); + apm = (Param) paramtab->getnode(paramtab, asg->name); + + if (pm && (pm->node.flags & (PM_SPECIAL|PM_TIED)) == (PM_SPECIAL|PM_TIED)) { + /* + * Only allow typeset -T on special tied parameters if the tied + * parameter and join char are the same + */ + if (strcmp(pm->ename, asg->name) || !(apm->node.flags & PM_SPECIAL)) { + zwarnnam(name, "%s special parameter can only be tied to special parameter %s", asg0.name, pm->ename); + unqueue_signals(); + return 1; + } + if (joinchar != ':') { + zwarnnam(name, "cannot change the join character of special tied parameters"); unqueue_signals(); - if (PM_TYPE(pm->node.flags) != PM_SCALAR) { - zwarnnam(name, "already tied as non-scalar: %s", asg0.name); - } else if (!strcmp(asg->name, pm->ename)) { + return 1; + } + already_tied = 1; + } else if (apm && (apm->node.flags & (PM_SPECIAL|PM_TIED)) == (PM_SPECIAL|PM_TIED)) { + /* + * For the array variable, this covers attempts to tie the + * array to a different scalar or to the scalar after it has + * been made non-special + */ + zwarnnam(name, "%s special parameter can only be tied to special parameter %s", asg->name, apm->ename); + unqueue_signals(); + return 1; + } else if (pm) { + if (!(pm->node.flags & PM_UNSET) + && (locallevel == pm->level || !(on & PM_LOCAL))) { + if (pm->node.flags & PM_TIED) { + if (PM_TYPE(pm->node.flags) != PM_SCALAR) { + zwarnnam(name, "already tied as non-scalar: %s", asg0.name); + unqueue_signals(); + return 1; + } else if (!strcmp(asg->name, pm->ename)) { + already_tied = 1; + } else { + zwarnnam(name, "can't tie already tied scalar: %s", + asg0.name); + unqueue_signals(); + return 1; + } + } else { /* - * Already tied in the fashion requested. + * Variable already exists in the current scope but is not tied. + * We're preserving its value and export attribute but no other + * attributes upon converting to "tied". */ - struct tieddata *tdp = (struct tieddata*)pm->u.data; - int flags = (asg->flags & ASG_KEY_VALUE) ? - ASSPM_KEY_VALUE : 0; - /* Update join character */ - tdp->joinchar = joinchar; - if (asg0.value.scalar) - assignsparam(asg0.name, ztrdup(asg0.value.scalar), 0); - else if (asg->value.array) - assignaparam( - asg->name, zlinklist2array(asg->value.array),flags); - return 0; - } else { - zwarnnam(name, "can't tie already tied scalar: %s", - asg0.name); + if (!asg0.value.scalar && !asg->value.array && + !(PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED))) + oldval = ztrdup(getsparam(asg0.name)); + on |= (pm->node.flags & ~roff) & PM_EXPORTED; } - return 1; } - if (!asg0.value.scalar && !asg->value.array && - !(PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED))) - oldval = ztrdup(getsparam(asg0.name)); - on |= (pm->node.flags & PM_EXPORTED); + } + if (already_tied) { + int ret; + /* + * If already tied, we still need to call typeset_single on + * both the array and colonarray, if only to update the attributes + * of both, and of course to set the new value if one is provided + * for either of them. + */ + ret = !(typeset_single(name, asg0.name, pm, + func, on, off, roff, &asg0, apm, + ops, joinchar) && + typeset_single(name, asg->name, apm, + func, (on | PM_ARRAY) & ~PM_EXPORTED, + off & ~PM_ARRAY, roff, asg, NULL, ops, 0) + ); + unqueue_signals(); + return ret; } /* * Create the tied array; this is normal except that @@ -2832,9 +2903,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func) * Create the tied colonarray. We make it as a normal scalar * and fix up the oddities later. */ - if (!(pm=typeset_single(name, asg0.name, - (Param)paramtab->getnode(paramtab, - asg0.name), + if (!(pm=typeset_single(name, asg0.name, pm, func, on, off, roff, &asg0, apm, ops, joinchar))) { if (oldval) diff --git a/Src/hashtable.h b/Src/hashtable.h index 21398e17c..f6778664e 100644 --- a/Src/hashtable.h +++ b/Src/hashtable.h @@ -63,6 +63,7 @@ #define BIN_UNALIAS 29 #define BIN_UNFUNCTION 30 #define BIN_UNSET 31 +#define BIN_EXPORT 32 /* These currently depend on being 0 and 1. */ #define BIN_SETOPT 0 diff --git a/Src/params.c b/Src/params.c index f7ecff32a..089a958ae 100644 --- a/Src/params.c +++ b/Src/params.c @@ -290,7 +290,7 @@ static initparam special_params[] ={ #define GSU(X) BR((GsuScalar)(void *)(&(X))) #define NULL_GSU BR((GsuScalar)(void *)NULL) #define IPDEF1(A,B,C) {{NULL,A,PM_INTEGER|PM_SPECIAL|C},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0} -IPDEF1("#", pound_gsu, PM_READONLY), +IPDEF1("#", pound_gsu, PM_READONLY_SPECIAL), IPDEF1("ERRNO", errno_gsu, PM_UNSET), IPDEF1("GID", gid_gsu, PM_DONTIMPORT | PM_RESTRICTED), IPDEF1("EGID", egid_gsu, PM_DONTIMPORT | PM_RESTRICTED), @@ -300,11 +300,11 @@ IPDEF1("SAVEHIST", savehist_gsu, PM_RESTRICTED), IPDEF1("SECONDS", intseconds_gsu, 0), IPDEF1("UID", uid_gsu, PM_DONTIMPORT | PM_RESTRICTED), IPDEF1("EUID", euid_gsu, PM_DONTIMPORT | PM_RESTRICTED), -IPDEF1("TTYIDLE", ttyidle_gsu, PM_READONLY), +IPDEF1("TTYIDLE", ttyidle_gsu, PM_READONLY_SPECIAL), #define IPDEF2(A,B,C) {{NULL,A,PM_SCALAR|PM_SPECIAL|C},BR(NULL),GSU(B),0,0,NULL,NULL,NULL,0} IPDEF2("USERNAME", username_gsu, PM_DONTIMPORT|PM_RESTRICTED), -IPDEF2("-", dash_gsu, PM_READONLY), +IPDEF2("-", dash_gsu, PM_READONLY_SPECIAL), IPDEF2("histchars", histchars_gsu, PM_DONTIMPORT), IPDEF2("HOME", home_gsu, PM_UNSET), IPDEF2("TERM", term_gsu, PM_UNSET), @@ -337,7 +337,7 @@ LCIPDEF("LC_TIME"), # endif #endif /* USE_LOCALE */ -#define IPDEF4(A,B) {{NULL,A,PM_INTEGER|PM_READONLY|PM_SPECIAL},BR((void *)B),GSU(varint_readonly_gsu),10,0,NULL,NULL,NULL,0} +#define IPDEF4(A,B) {{NULL,A,PM_INTEGER|PM_READONLY_SPECIAL},BR((void *)B),GSU(varint_readonly_gsu),10,0,NULL,NULL,NULL,0} IPDEF4("!", &lastpid), IPDEF4("$", &mypid), IPDEF4("?", &lastval), @@ -377,10 +377,9 @@ IPDEF7("PS3", &prompt3), IPDEF7R("PS4", &prompt4), IPDEF7("SPROMPT", &sprompt), -#define IPDEF9F(A,B,C,D) {{NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(vararray_gsu),0,0,NULL,C,NULL,0} -#define IPDEF9(A,B,C) IPDEF9F(A,B,C,0) -IPDEF9F("*", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY), -IPDEF9F("@", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY), +#define IPDEF9(A,B,C,D) {{NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(vararray_gsu),0,0,NULL,C,NULL,0} +IPDEF9("*", &pparams, NULL, PM_ARRAY|PM_READONLY_SPECIAL|PM_DONTIMPORT), +IPDEF9("@", &pparams, NULL, PM_ARRAY|PM_READONLY_SPECIAL|PM_DONTIMPORT), /* * This empty row indicates the end of parameters available in @@ -389,17 +388,17 @@ IPDEF9F("@", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY), {{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0}, #define IPDEF8(A,B,C,D) {{NULL,A,D|PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(colonarr_gsu),0,0,NULL,C,NULL,0} -IPDEF8("CDPATH", &cdpath, "cdpath", 0), -IPDEF8("FIGNORE", &fignore, "fignore", 0), -IPDEF8("FPATH", &fpath, "fpath", 0), -IPDEF8("MAILPATH", &mailpath, "mailpath", 0), -IPDEF8("WATCH", &watch, "watch", 0), -IPDEF8("PATH", &path, "path", PM_RESTRICTED), -IPDEF8("PSVAR", &psvar, "psvar", 0), -IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, "zsh_eval_context", PM_READONLY), +IPDEF8("CDPATH", &cdpath, "cdpath", PM_TIED), +IPDEF8("FIGNORE", &fignore, "fignore", PM_TIED), +IPDEF8("FPATH", &fpath, "fpath", PM_TIED), +IPDEF8("MAILPATH", &mailpath, "mailpath", PM_TIED), +IPDEF8("WATCH", &watch, "watch", PM_TIED), +IPDEF8("PATH", &path, "path", PM_RESTRICTED|PM_TIED), +IPDEF8("PSVAR", &psvar, "psvar", PM_TIED), +IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, "zsh_eval_context", PM_READONLY_SPECIAL|PM_TIED), /* MODULE_PATH is not imported for security reasons */ -IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED), +IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED|PM_TIED), #define IPDEF10(A,B) {{NULL,A,PM_ARRAY|PM_SPECIAL},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0} @@ -409,7 +408,7 @@ IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED), */ /* All of these have sh compatible equivalents. */ -IPDEF1("ARGC", argc_gsu, PM_READONLY), +IPDEF1("ARGC", argc_gsu, PM_READONLY_SPECIAL), IPDEF2("HISTCHARS", histchars_gsu, PM_DONTIMPORT), IPDEF4("status", &lastval), IPDEF7("prompt", &prompt), @@ -417,20 +416,20 @@ IPDEF7("PROMPT", &prompt), IPDEF7("PROMPT2", &prompt2), IPDEF7("PROMPT3", &prompt3), IPDEF7("PROMPT4", &prompt4), -IPDEF8("MANPATH", &manpath, "manpath", 0), -IPDEF9("argv", &pparams, NULL), -IPDEF9("fignore", &fignore, "FIGNORE"), -IPDEF9("cdpath", &cdpath, "CDPATH"), -IPDEF9("fpath", &fpath, "FPATH"), -IPDEF9("mailpath", &mailpath, "MAILPATH"), -IPDEF9("manpath", &manpath, "MANPATH"), -IPDEF9("psvar", &psvar, "PSVAR"), -IPDEF9("watch", &watch, "WATCH"), +IPDEF8("MANPATH", &manpath, "manpath", PM_TIED), +IPDEF9("argv", &pparams, NULL, 0), +IPDEF9("fignore", &fignore, "FIGNORE", PM_TIED), +IPDEF9("cdpath", &cdpath, "CDPATH", PM_TIED), +IPDEF9("fpath", &fpath, "FPATH", PM_TIED), +IPDEF9("mailpath", &mailpath, "MAILPATH", PM_TIED), +IPDEF9("manpath", &manpath, "MANPATH", PM_TIED), +IPDEF9("psvar", &psvar, "PSVAR", PM_TIED), +IPDEF9("watch", &watch, "WATCH", PM_TIED), -IPDEF9F("zsh_eval_context", &zsh_eval_context, "ZSH_EVAL_CONTEXT", PM_READONLY), +IPDEF9("zsh_eval_context", &zsh_eval_context, "ZSH_EVAL_CONTEXT", PM_TIED|PM_READONLY_SPECIAL), -IPDEF9F("module_path", &module_path, "MODULE_PATH", PM_RESTRICTED), -IPDEF9F("path", &path, "PATH", PM_RESTRICTED), +IPDEF9("module_path", &module_path, "MODULE_PATH", PM_TIED|PM_RESTRICTED), +IPDEF9("path", &path, "PATH", PM_TIED|PM_RESTRICTED), /* These are known to zsh alone. */ @@ -451,7 +450,7 @@ IPDEF8("MAILPATH", &mailpath, NULL, 0), IPDEF8("WATCH", &watch, NULL, 0), IPDEF8("PATH", &path, NULL, PM_RESTRICTED), IPDEF8("PSVAR", &psvar, NULL, 0), -IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, NULL, PM_READONLY), +IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, NULL, PM_READONLY_SPECIAL), /* MODULE_PATH is not imported for security reasons */ IPDEF8("MODULE_PATH", &module_path, NULL, PM_DONTIMPORT|PM_RESTRICTED), @@ -464,7 +463,7 @@ IPDEF8("MODULE_PATH", &module_path, NULL, PM_DONTIMPORT|PM_RESTRICTED), * and $@, this is not readonly. This parameter is not directly * visible in user space. */ -static initparam argvparam_pm = IPDEF9F("", &pparams, NULL, \ +static initparam argvparam_pm = IPDEF9("", &pparams, NULL, \ PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT); #undef BR @@ -5024,10 +5023,10 @@ arrfixenv(char *s, char **t) if (!(pm->node.flags & PM_EXPORTED)) return; - if (pm->node.flags & PM_TIED) - joinchar = STOUC(((struct tieddata *)pm->u.data)->joinchar); - else + if (pm->node.flags & PM_SPECIAL) joinchar = ':'; + else + joinchar = STOUC(((struct tieddata *)pm->u.data)->joinchar); addenv(pm, t ? zjoin(t, joinchar, 1) : ""); } @@ -5650,7 +5649,7 @@ freeparamnode(HashNode hn) pm->gsu.s->unsetfn(pm, 1); zsfree(pm->node.nam); /* If this variable was tied by the user, ename was ztrdup'd */ - if (pm->node.flags & PM_TIED) + if (!(pm->node.flags & PM_SPECIAL)) zsfree(pm->ename); zfree(pm, sizeof(struct param)); } @@ -5685,7 +5684,9 @@ static const struct paramtypes pmtypes[] = { { PM_UPPER, "uppercase", 'u', 0}, { PM_READONLY, "readonly", 'r', 0}, { PM_TAGGED, "tagged", 't', 0}, - { PM_EXPORTED, "exported", 'x', 0} + { PM_EXPORTED, "exported", 'x', 0}, + { PM_UNIQUE, "unique", 'U', 0}, + { PM_TIED, "tied", 'T', 0} }; #define PMTYPES_SIZE ((int)(sizeof(pmtypes)/sizeof(struct paramtypes))) @@ -5774,10 +5775,6 @@ printparamvalue(Param p, int printflags) } break; } - if ((printflags & (PRINT_KV_PAIR|PRINT_LINE)) == PRINT_KV_PAIR) - putchar(' '); - else if (!(printflags & PRINT_KV_PAIR)) - putchar('\n'); } /**/ @@ -5785,36 +5782,41 @@ mod_export void printparamnode(HashNode hn, int printflags) { Param p = (Param) hn; + Param peer = NULL; if (p->node.flags & PM_UNSET) { - if (isset(POSIXBUILTINS) && (p->node.flags & PM_READONLY) && - (printflags & PRINT_TYPESET)) - { + if (printflags & (PRINT_POSIX_READONLY|PRINT_POSIX_EXPORT) && + p->node.flags & (PM_READONLY|PM_EXPORTED)) { /* - * Special POSIX rules: show the parameter as readonly + * Special POSIX rules: show the parameter as readonly/exported * even though it's unset, but with no value. */ printflags |= PRINT_NAMEONLY; } - else if (p->node.flags & PM_EXPORTED) - printflags |= PRINT_NAMEONLY; else return; } if (p->node.flags & PM_AUTOLOAD) printflags |= PRINT_NAMEONLY; - if (printflags & PRINT_TYPESET) { - if ((p->node.flags & (PM_READONLY|PM_SPECIAL)) == - (PM_READONLY|PM_SPECIAL) || - (p->node.flags & PM_AUTOLOAD)) { + if (printflags & (PRINT_TYPESET|PRINT_POSIX_READONLY|PRINT_POSIX_EXPORT)) { + if (p->node.flags & (PM_RO_BY_DESIGN|PM_AUTOLOAD)) { /* * It's not possible to restore the state of * these, so don't output. */ return; } - if (locallevel && p->level >= locallevel) { + /* + * The zsh variants of export -p/readonly -p also report other + * flags to indicate other attributes or scope. The POSIX variants + * don't. + */ + if (printflags & PRINT_POSIX_EXPORT) { + printf("export "); + } else if (printflags & PRINT_POSIX_READONLY) { + printf("readonly "); + } else if (locallevel && p->level >= locallevel) { printf("typeset "); /* printf("local "); */ } else if ((p->node.flags & PM_EXPORTED) && !(p->node.flags & (PM_ARRAY|PM_HASHED))) { @@ -5861,22 +5863,48 @@ printparamnode(HashNode hn, int printflags) } } } - if (p->node.flags & PM_UNIQUE) { - if (!doneminus) { - putchar('-'); - doneminus = 1; - } - putchar('U'); - } if (doneminus) putchar(' '); + + if (p->node.flags & PM_TIED) { + /* + * For scalars tied to arrays,s + * * typeset +m outputs + * array tied SCALAR array + * tied array SCALAR + * * typeset -p outputs: + * typeset -T SCALAR array (for hidden values) + * typeset -T SCALAR array=(values) + * for both scalar and array (flags may be different) + * + * We choose to print the value for the array instead of the scalar + * as scalars can't disambiguate between + * typeset -T SCALAR array=() + * and + * typeset -T SCALAR array=('') + * (same for (a b:c)...) + */ + Param tmp = (Param) paramtab->getnode(paramtab, p->ename); + + /* + * Swap param and tied peer for typeset -p output + */ + if (!(printflags & PRINT_TYPESET) || (p->node.flags & PM_ARRAY)) + peer = tmp; + else { + peer = p; + p = tmp; + } + + quotedzputs(peer->node.nam, stdout); + putchar(' '); + } } if ((printflags & PRINT_NAMEONLY) || - ((p->node.flags & PM_HIDEVAL) && !(printflags & PRINT_INCLUDEVALUE))) { - zputs(p->node.nam, stdout); - putchar('\n'); - } else { + ((p->node.flags & PM_HIDEVAL) && !(printflags & PRINT_INCLUDEVALUE))) + quotedzputs(p->node.nam, stdout); + else { if (printflags & PRINT_KV_PAIR) { if (printflags & PRINT_LINE) printf("\n "); @@ -5888,4 +5916,22 @@ printparamnode(HashNode hn, int printflags) printparamvalue(p, printflags); } + if (peer && (printflags & PRINT_TYPESET) && !(p->node.flags & PM_SPECIAL)) { + /* + * append the join char for tied parameters if different from colon + * for typeset -p output. + */ + unsigned char joinchar = STOUC(((struct tieddata *)peer->u.data)->joinchar); + if (joinchar != ':') { + char buf[2]; + buf[0] = joinchar; + buf[1] = '\0'; + putchar(' '); + quotedzputs(buf, stdout); + } + } + if ((printflags & (PRINT_KV_PAIR|PRINT_LINE)) == PRINT_KV_PAIR) + putchar(' '); + else if (!(printflags & PRINT_KV_PAIR)) + putchar('\n'); } diff --git a/Src/subst.c b/Src/subst.c index c1021fbf3..c706b9688 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -2552,8 +2552,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, val = dyncat(val, "-readonly"); if (f & PM_TAGGED) val = dyncat(val, "-tag"); - if (f & PM_TAGGED_LOCAL) - val = dyncat(val, "-tag_local"); + if (f & PM_TIED) + val = dyncat(val, "-tied"); if (f & PM_EXPORTED) val = dyncat(val, "-export"); if (f & PM_UNIQUE) diff --git a/Src/zsh.h b/Src/zsh.h index b81db1527..8d39a0493 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1886,18 +1886,21 @@ struct tieddata { #define PM_ANONYMOUS (1<<20) /* (function) anonymous function */ #define PM_LOCAL (1<<21) /* this parameter will be made local */ #define PM_SPECIAL (1<<22) /* special builtin parameter */ -#define PM_DONTIMPORT (1<<23) /* do not import this variable */ -#define PM_RESTRICTED (1<<24) /* cannot be changed in restricted mode */ -#define PM_UNSET (1<<25) /* has null value */ -#define PM_REMOVABLE (1<<26) /* special can be removed from paramtab */ -#define PM_AUTOLOAD (1<<27) /* autoloaded from module */ -#define PM_NORESTORE (1<<28) /* do not restore value of local special */ -#define PM_AUTOALL (1<<28) /* autoload all features in module +#define PM_RO_BY_DESIGN (1<<23) /* to distinguish from specials that can be + made read-only by the user */ +#define PM_READONLY_SPECIAL (PM_SPECIAL|PM_READONLY|PM_RO_BY_DESIGN) +#define PM_DONTIMPORT (1<<24) /* do not import this variable */ +#define PM_RESTRICTED (1<<25) /* cannot be changed in restricted mode */ +#define PM_UNSET (1<<26) /* has null value */ +#define PM_REMOVABLE (1<<27) /* special can be removed from paramtab */ +#define PM_AUTOLOAD (1<<28) /* autoloaded from module */ +#define PM_NORESTORE (1<<29) /* do not restore value of local special */ +#define PM_AUTOALL (1<<29) /* autoload all features in module * when loading: valid only if PM_AUTOLOAD * is also present. */ -#define PM_HASHELEM (1<<29) /* is a hash-element */ -#define PM_NAMEDDIR (1<<30) /* has a corresponding nameddirtab entry */ +#define PM_HASHELEM (1<<30) /* is a hash-element */ +#define PM_NAMEDDIR (1<<31) /* has a corresponding nameddirtab entry */ /* The option string corresponds to the first of the variables above */ #define TYPESET_OPTSTR "aiEFALRZlurtxUhHTkz" @@ -2138,6 +2141,8 @@ typedef groupset *Groupset; #define PRINT_INCLUDEVALUE (1<<4) #define PRINT_TYPESET (1<<5) #define PRINT_LINE (1<<6) +#define PRINT_POSIX_EXPORT (1<<7) +#define PRINT_POSIX_READONLY (1<<8) /* flags for printing for the whence builtin */ #define PRINT_WHENCE_CSH (1<<7) -- cgit 1.4.1