diff options
Diffstat (limited to 'Src/builtin.c')
-rw-r--r-- | Src/builtin.c | 309 |
1 files changed, 224 insertions, 85 deletions
diff --git a/Src/builtin.c b/Src/builtin.c index 0edc07024..ba384068d 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -53,7 +53,7 @@ static struct builtin builtins[] = BUILTIN("cd", BINF_SKIPINVALID | BINF_SKIPDASH | BINF_DASHDASHVALID, bin_cd, 0, 2, BIN_CD, "qsPL", NULL), BUILTIN("chdir", BINF_SKIPINVALID | BINF_SKIPDASH | BINF_DASHDASHVALID, bin_cd, 0, 2, BIN_CD, "qsPL", NULL), BUILTIN("continue", BINF_PSPECIAL, bin_break, 0, 1, BIN_CONTINUE, NULL, NULL), - BUILTIN("declare", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%klmprtuxz", NULL), + BUILTIN("declare", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%klmprtuxz", NULL), BUILTIN("dirs", 0, bin_dirs, 0, -1, 0, "clpv", NULL), BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmprs", NULL), BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL), @@ -62,7 +62,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, bin_typeset, 0, -1, BIN_EXPORT, "E:%F:%HL:%R:%TUZ:%afhi:%lprtu", "xg"), + BUILTIN("export", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, BIN_EXPORT, "E:%F:%HL:%R:%TUZ:%afhi:%lprtu", "xg"), BUILTIN("false", 0, bin_false, 0, -1, 0, NULL, NULL), /* * We used to behave as if the argument to -e was optional. @@ -71,7 +71,7 @@ static struct builtin builtins[] = */ BUILTIN("fc", 0, bin_fc, 0, -1, BIN_FC, "aAdDe:EfiIlLmnpPrRt:W", NULL), BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL), - BUILTIN("float", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%Z:%ghlprtux", "E"), + BUILTIN("float", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%Z:%ghlprtux", "E"), BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "kmMtTuUx:z", NULL), BUILTIN("getln", 0, bin_read, 0, -1, 0, "ecnAlE", "zr"), BUILTIN("getopts", 0, bin_getopts, 2, -1, 0, NULL, NULL), @@ -82,11 +82,11 @@ static struct builtin builtins[] = #endif BUILTIN("history", 0, bin_fc, 0, -1, BIN_FC, "adDEfiLmnpPrt:", "l"), - BUILTIN("integer", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "HL:%R:%Z:%ghi:%lprtux", "i"), + BUILTIN("integer", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "HL:%R:%Z:%ghi:%lprtux", "i"), BUILTIN("jobs", 0, bin_fg, 0, -1, BIN_JOBS, "dlpZrs", NULL), BUILTIN("kill", BINF_HANDLES_OPTS, bin_kill, 0, -1, 0, NULL, NULL), BUILTIN("let", 0, bin_let, 1, -1, 0, NULL, NULL), - BUILTIN("local", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%ahi:%lprtux", NULL), + BUILTIN("local", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%ahi:%lprtux", NULL), BUILTIN("log", 0, bin_log, 0, 0, 0, NULL, NULL), BUILTIN("logout", 0, bin_break, 0, 1, BIN_LOGOUT, NULL, NULL), @@ -106,7 +106,7 @@ static struct builtin builtins[] = BUILTIN("pwd", 0, bin_pwd, 0, 0, 0, "rLP", NULL), BUILTIN("r", 0, bin_fc, 0, -1, BIN_R, "IlLnr", NULL), BUILTIN("read", 0, bin_read, 0, -1, 0, "cd:ek:%lnpqrst:%zu:AE", NULL), - BUILTIN("readonly", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%lptux", "r"), + BUILTIN("readonly", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%lptux", "r"), BUILTIN("rehash", 0, bin_hash, 0, 0, 0, "df", "r"), BUILTIN("return", BINF_PSPECIAL, bin_break, 0, 1, BIN_RETURN, NULL, NULL), BUILTIN("set", BINF_PSPECIAL | BINF_HANDLES_OPTS, bin_set, 0, -1, 0, NULL, NULL), @@ -120,7 +120,7 @@ static struct builtin builtins[] = BUILTIN("trap", BINF_PSPECIAL | BINF_HANDLES_OPTS, 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, "ampfsSw", "v"), - BUILTIN("typeset", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%klprtuxmz", NULL), + BUILTIN("typeset", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%klprtuxmz", NULL), BUILTIN("umask", 0, bin_umask, 0, 1, 0, "S", NULL), BUILTIN("unalias", 0, bin_unhash, 0, -1, BIN_UNALIAS, "ams", NULL), BUILTIN("unfunction", 0, bin_unhash, 1, -1, BIN_UNFUNCTION, "m", "f"), @@ -246,7 +246,7 @@ new_optarg(Options ops) /**/ int -execbuiltin(LinkList args, Builtin bn) +execbuiltin(LinkList args, LinkList assigns, Builtin bn) { char *pp, *name, *optstr; int flags, sense, argc, execop, xtr = isset(XTRACE); @@ -443,11 +443,44 @@ execbuiltin(LinkList args, Builtin bn) fputc(' ', xtrerr); quotedzputs(*fullargv++, xtrerr); } + if (assigns) { + LinkNode node; + for (node = firstnode(assigns); node; incnode(node)) { + Asgment asg = (Asgment)node; + fputc(' ', xtrerr); + quotedzputs(asg->name, xtrerr); + if (asg->is_array) { + LinkNode arrnode; + fprintf(xtrerr, "=("); + for (arrnode = firstnode(asg->value.array); + arrnode; + incnode(arrnode)) { + fputc(' ', xtrerr); + quotedzputs((char *)getdata(arrnode), xtrerr); + } + fprintf(xtrerr, " )"); + } else if (asg->value.scalar) { + fputc('=', xtrerr); + quotedzputs(asg->value.scalar, xtrerr); + } + } + } fputc('\n', xtrerr); fflush(xtrerr); } /* call the handler function, and return its return value */ - return (*(bn->handlerfunc)) (name, argv, &ops, bn->funcid); + if (flags & BINF_ASSIGN) + { + /* + * Takes two sets of arguments. + */ + HandlerFuncAssign assignfunc = (HandlerFuncAssign)bn->handlerfunc; + return (*(assignfunc)) (name, argv, assigns, &ops, bn->funcid); + } + else + { + return (*(bn->handlerfunc)) (name, argv, &ops, bn->funcid); + } } } @@ -1452,12 +1485,13 @@ bin_fc(char *nam, char **argv, Options ops, int func) if (!asgf) asgf = asgl = a; else { - asgl->next = a; + asgl->node.next = &a->node; asgl = a; } a->name = *argv; - a->value = s; - a->next = NULL; + a->is_array = 0; + a->value.scalar = s; + a->node.next = a->node.prev = NULL; argv++; } /* interpret and check first history line specifier */ @@ -1631,8 +1665,8 @@ fcsubs(char **sp, struct asgment *sub) /* loop through the linked list */ while (sub) { oldstr = sub->name; - newstr = sub->value; - sub = sub->next; + newstr = sub->value.scalar; + sub = (Asgment)sub->node.next; oldpos = s; /* loop over occurences of oldstr in s, replacing them with newstr */ while ((newpos = (char *)strstr(oldpos, oldstr))) { @@ -1820,13 +1854,22 @@ fcedit(char *ename, char *fn) /**/ static Asgment -getasg(char *s) +getasg(char ***argvp, LinkList assigns) { + char *s = **argvp; static struct asgment asg; /* sanity check for valid argument */ - if (!s) + if (!s) { + if (assigns) { + Asgment asgp = (Asgment)firstnode(assigns); + if (!asgp) + return NULL; + (void)uremnode(assigns, &asgp->node); + return asgp; + } return NULL; + } /* check if name is empty */ if (*s == '=') { @@ -1834,6 +1877,7 @@ getasg(char *s) return NULL; } asg.name = s; + asg.is_array = 0; /* search for `=' */ for (; *s && *s != '='; s++); @@ -1841,11 +1885,12 @@ getasg(char *s) /* found `=', so return with a value */ if (*s) { *s = '\0'; - asg.value = s + 1; + asg.value.scalar = s + 1; } else { /* didn't find `=', so we only have a name */ - asg.value = NULL; + asg.value.scalar = NULL; } + (*argvp)++; return &asg; } @@ -1927,7 +1972,7 @@ typeset_setwidth(const char * name, Param pm, Options ops, int on, int always) /**/ static Param typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), - int on, int off, int roff, char *value, Param altpm, + int on, int off, int roff, Asgment asg, Param altpm, Options ops, int joinchar) { int usepm, tc, keeplocal = 0, newspecial = NS_NONE, readonly; @@ -1975,7 +2020,24 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), /* attempting a type conversion, or making a tied colonarray? */ tc = 0; - if (usepm || newspecial != NS_NONE) { + if (ASG_ARRAYP(asg) && PM_TYPE(on) == PM_SCALAR && + !(usepm && (PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)))) + on |= PM_ARRAY; + if (usepm && ASG_ARRAYP(asg) && newspecial == NS_NONE && + PM_TYPE(pm->node.flags) != PM_ARRAY && + PM_TYPE(pm->node.flags) != PM_HASHED) { + if (on & (PM_EFLOAT|PM_FFLOAT|PM_INTEGER)) { + zerrnam(cname, "%s: can't assign array value to non-array", pname); + return NULL; + } + if (pm->node.flags & PM_SPECIAL) { + zerrnam(cname, "%s: can't assign array value to non-array special", pname); + return NULL; + } + tc = 1; + usepm = 0; + } + else if (usepm || newspecial != NS_NONE) { int chflags = ((off & pm->node.flags) | (on & ~pm->node.flags)) & (PM_INTEGER|PM_EFLOAT|PM_FFLOAT|PM_HASHED| PM_ARRAY|PM_TIED|PM_AUTOLOAD); @@ -2023,7 +2085,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), tc = 0; /* but don't do a normal conversion */ } } else if (!setsecondstype(pm, on, off)) { - if (value && !(pm = setsparam(pname, ztrdup(value)))) + if (asg->value.scalar && !(pm = setsparam(pname, ztrdup(asg->value.scalar)))) return NULL; usepm = 1; err = 0; @@ -2049,7 +2111,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), * Stricter rules about retaining readonly attribute in this case. */ if ((on & PM_READONLY) && (!usepm || (pm->node.flags & PM_UNSET)) && - !value) + !ASG_VALUEP(asg)) on |= PM_UNSET; else if (usepm && (pm->node.flags & PM_READONLY) && !(on & PM_READONLY)) { @@ -2068,8 +2130,14 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), * ii. we are creating a new local parameter */ if (usepm) { + if (asg->is_array ? + (asg->value.array && !(PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED))) : + (asg->value.scalar && (PM_TYPE(pm->node.flags & (PM_ARRAY|PM_HASHED))))) { + zerrnam(cname, "%s: inconsistent type for assignment", pname); + return NULL; + } on &= ~PM_LOCAL; - if (!on && !roff && !value) { + if (!on && !roff && !ASG_VALUEP(asg)) { if (OPT_ISSET(ops,'p')) paramtab->printnode(&pm->node, PRINT_TYPESET); else if (!OPT_ISSET(ops,'g') && @@ -2123,15 +2191,17 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), } if (!(pm->node.flags & (PM_ARRAY|PM_HASHED))) { if (pm->node.flags & PM_EXPORTED) { - if (!(pm->node.flags & PM_UNSET) && !pm->env && !value) + if (!(pm->node.flags & PM_UNSET) && !pm->env && !ASG_VALUEP(asg)) addenv(pm, getsparam(pname)); } else if (pm->env && !(pm->node.flags & PM_HASHELEM)) delenv(pm); - if (value && !(pm = setsparam(pname, ztrdup(value)))) + DPUTS(ASG_ARRAYP(asg), "BUG: typeset got array value where scalar expected"); + if (asg->value.scalar && !(pm = setsparam(pname, ztrdup(asg->value.scalar)))) + return NULL; + } else if (asg->value.array) { + DPUTS(!ASG_ARRAYP(asg), "BUG: typeset got scalar value where array expected"); + if (!(pm = setaparam(pname, zlinklist2array(asg->value.array)))) return NULL; - } else if (value) { - zwarnnam(cname, "can't assign new value for array %s", pname); - return NULL; } pm->node.flags |= (on & PM_READONLY); if (OPT_ISSET(ops,'p')) @@ -2139,6 +2209,13 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), return pm; } + if (asg->is_array ? + (asg->value.array && !(on & (PM_ARRAY|PM_HASHED))) : + (asg->value.scalar && (on & (PM_ARRAY|PM_HASHED)))) { + zerrnam(cname, "%s: inconsistent type for assignment", pname); + return NULL; + } + /* * We're here either because we're creating a new parameter, * or we're adding a parameter at a different local level, @@ -2158,9 +2235,14 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), /* * Try to carry over a value, but not when changing from, * to, or between non-scalar types. + * + * (We can do better now, but it does have user-visible + * implications.) */ - if (!value && !((pm->node.flags|on) & (PM_ARRAY|PM_HASHED))) - value = dupstring(getsparam(pname)); + if (!ASG_VALUEP(asg) && !((pm->node.flags|on) & (PM_ARRAY|PM_HASHED))) { + asg->value.scalar = dupstring(getsparam(pname)); + asg->is_array = 0; + } /* pname may point to pm->nam which is about to disappear */ pname = dupstring(pname); unsetparam_pm(pm, 0, 1); @@ -2251,16 +2333,17 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), return NULL; } } - if (PM_TYPE(on) == PM_SCALAR) { + if (PM_TYPE(on) == PM_SCALAR && !ASG_ARRAYP(asg)) { /* * This will either complain about bad identifiers, or will set * a hash element or array slice. This once worked by accident, * creating a stray parameter along the way via createparam(), * now called below in the isident() branch. */ - if (!(pm = setsparam(pname, ztrdup(value ? value : "")))) + if (!(pm = setsparam(pname, ztrdup(asg->value.scalar ? asg->value.scalar : "")))) return NULL; - value = NULL; + asg->value.scalar = NULL; + asg->is_array = 0; keeplocal = 0; on = pm->node.flags; } else { @@ -2331,10 +2414,17 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), pm->level = keeplocal; else if (on & PM_LOCAL) pm->level = locallevel; - if (value && !(pm->node.flags & (PM_ARRAY|PM_HASHED))) { + if (ASG_VALUEP(asg)) { Param ipm = pm; - if (!(pm = setsparam(pname, ztrdup(value)))) - return NULL; + if (pm->node.flags & (PM_ARRAY|PM_HASHED)) { + DPUTS(!ASG_ARRAYP(asg), "BUG: inconsistent scalar value for array"); + if (!(pm=setaparam(pname, zlinklist2array(asg->value.array)))) + return NULL; + } else { + DPUTS(ASG_ARRAYP(asg), "BUG: inconsistent array value for scalar"); + if (!(pm = setsparam(pname, ztrdup(asg->value.scalar)))) + return NULL; + } if (pm != ipm) { DPUTS(ipm->node.flags != pm->node.flags, "BUG: parameter recreated with wrong flags"); @@ -2371,12 +2461,6 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), } } pm->node.flags |= (on & PM_READONLY); - if (value && (pm->node.flags & (PM_ARRAY|PM_HASHED))) { - zerrnam(cname, "%s: can't assign initial value for array", pname); - /* the only safe thing to do here seems to be unset the param */ - unsetparam_pm(pm, 0, 1); - return NULL; - } if (OPT_ISSET(ops,'p')) paramtab->printnode(&pm->node, PRINT_TYPESET); @@ -2384,11 +2468,18 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), return pm; } -/* declare, export, integer, local, readonly, typeset */ +/* + * declare, export, float, integer, local, readonly, typeset + * + * Note the difference in interface from most builtins, covered by the + * BINF_ASSIGN builtin flag. This is only made use of by builtins + * called by reserved word, which only covers declare, local, readonly + * and typeset. Otherwise assigns is NULL. + */ /**/ int -bin_typeset(char *name, char **argv, Options ops, int func) +bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func) { Param pm; Asgment asg; @@ -2397,6 +2488,7 @@ bin_typeset(char *name, char **argv, Options ops, int func) int on = 0, off = 0, roff, bit = PM_ARRAY; int i; int returnval = 0, printflags = 0; + int hasargs; /* hash -f is really the builtin `functions' */ if (OPT_ISSET(ops,'f')) @@ -2449,7 +2541,8 @@ bin_typeset(char *name, char **argv, Options ops, int func) /* Given no arguments, list whatever the options specify. */ if (OPT_ISSET(ops,'p')) printflags |= PRINT_TYPESET; - if (!*argv) { + hasargs = *argv != NULL || (assigns && firstnode(assigns)); + if (!hasargs) { if (!OPT_ISSET(ops,'p')) { if (!(on|roff)) printflags |= PRINT_TYPE; @@ -2468,9 +2561,9 @@ bin_typeset(char *name, char **argv, Options ops, int func) if (on & PM_TIED) { Param apm; - struct asgment asg0; - char *oldval = NULL; - int joinchar; + struct asgment asg0, asg2; + char *oldval = NULL, *joinstr; + int joinchar, nargs; if (OPT_ISSET(ops,'m')) { zwarnnam(name, "incompatible options for -T"); @@ -2478,34 +2571,41 @@ bin_typeset(char *name, char **argv, Options ops, int func) return 1; } on &= ~off; - if (!argv[1] || (argv[2] && argv[3])) { + nargs = arrlen(argv) + (assigns ? countlinknodes(assigns) : 0); + if (nargs < 2) { zwarnnam(name, "-T requires names of scalar and array"); unqueue_signals(); return 1; } + if (nargs > 3) { + zwarnnam(name, "too many arguments for -T"); + unqueue_signals(); + return 1; + } - /* - * Third argument, if given, is character used to join - * the elements of the array in the scalar. - */ - if (!argv[2]) - joinchar = ':'; - else if (!*argv[2]) - joinchar = 0; - else if (*argv[2] == Meta) - joinchar = argv[2][1] ^ 32; - else - joinchar = *argv[2]; - - if (!(asg = getasg(argv[0]))) { + if (!(asg = getasg(&argv, assigns))) { unqueue_signals(); return 1; } asg0 = *asg; - if (!(asg = getasg(argv[1]))) { + if (ASG_ARRAYP(&asg0)) { unqueue_signals(); + zwarnnam(name, "first argument of tie must be scalar: %s", + asg0.name); return 1; } + + if (!(asg = getasg(&argv, assigns))) { + unqueue_signals(); + return 1; + } + if (!ASG_ARRAYP(asg) && asg->value.scalar) { + unqueue_signals(); + zwarnnam(name, "second argument of tie must be array: %s", + asg->name); + return 1; + } + if (!strcmp(asg0.name, asg->name)) { unqueue_signals(); zerrnam(name, "can't tie a variable to itself: %s", asg0.name); @@ -2516,6 +2616,36 @@ bin_typeset(char *name, char **argv, Options ops, int func) zerrnam(name, "can't tie array elements: %s", asg0.name); return 1; } + if (ASG_VALUEP(asg) && ASG_VALUEP(&asg0)) { + unqueue_signals(); + zerrnam(name, "only one tied parameter can have value: %s", asg0.name); + return 1; + } + + /* + * Third argument, if given, is character used to join + * the elements of the array in the scalar. + */ + if (*argv) + joinstr = *argv; + else if (assigns && firstnode(assigns)) { + Asgment nextasg = (Asgment)firstnode(assigns); + if (ASG_ARRAYP(nextasg) || ASG_VALUEP(nextasg)) { + zwarnnam(name, "third argument of tie must be join character"); + unqueue_signals(); + return 1; + } + joinstr = nextasg->name; + } else + joinstr = NULL; + if (!joinstr) + joinchar = ':'; + else if (!*joinstr) + joinchar = 0; + else if (*joinstr == Meta) + 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 @@ -2537,8 +2667,8 @@ bin_typeset(char *name, char **argv, Options ops, int func) struct tieddata *tdp = (struct tieddata*)pm->u.data; /* Update join character */ tdp->joinchar = joinchar; - if (asg0.value) - setsparam(asg0.name, ztrdup(asg0.value)); + if (asg0.value.scalar) + setsparam(asg0.name, ztrdup(asg0.value.scalar)); return 0; } else { zwarnnam(name, "can't tie already tied scalar: %s", @@ -2546,7 +2676,8 @@ bin_typeset(char *name, char **argv, Options ops, int func) } return 1; } - if (!asg0.value && !(PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED))) + 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); } @@ -2554,12 +2685,18 @@ bin_typeset(char *name, char **argv, Options ops, int func) * Create the tied array; this is normal except that * it has the PM_TIED flag set. Do it first because * we need the address. + * + * Don't attempt to set it yet, it's too early + * to be exported properly. */ + asg2.name = asg->name; + asg2.is_array = 0; + asg2.value.array = (LinkList)0; if (!(apm=typeset_single(name, asg->name, (Param)paramtab->getnode(paramtab, asg->name), func, (on | PM_ARRAY) & ~PM_EXPORTED, - off, roff, asg->value, NULL, ops, 0))) { + off, roff, &asg2, NULL, ops, 0))) { if (oldval) zsfree(oldval); unqueue_signals(); @@ -2572,7 +2709,7 @@ bin_typeset(char *name, char **argv, Options ops, int func) if (!(pm=typeset_single(name, asg0.name, (Param)paramtab->getnode(paramtab, asg0.name), - func, on, off, roff, asg0.value, apm, + func, on, off, roff, &asg0, apm, ops, joinchar))) { if (oldval) zsfree(oldval); @@ -2591,7 +2728,9 @@ bin_typeset(char *name, char **argv, Options ops, int func) if (apm->ename) zsfree(apm->ename); apm->ename = ztrdup(asg0.name); - if (oldval) + if (asg->value.array) + setaparam(asg->name, zlinklist2array(asg->value.array)); + else if (oldval) setsparam(asg0.name, oldval); unqueue_signals(); @@ -2611,18 +2750,18 @@ bin_typeset(char *name, char **argv, Options ops, int func) printflags |= PRINT_NAMEONLY; } - while ((asg = getasg(*argv++))) { + while ((asg = getasg(&argv, assigns))) { LinkList pmlist = newlinklist(); LinkNode pmnode; tokenize(asg->name); /* expand argument */ if (!(pprog = patcompile(asg->name, 0, NULL))) { untokenize(asg->name); - zwarnnam(name, "bad pattern : %s", argv[-1]); + zwarnnam(name, "bad pattern : %s", asg->name); returnval = 1; continue; } - if (OPT_PLUS(ops,'m') && !asg->value) { + if (OPT_PLUS(ops,'m') && !ASG_VALUEP(asg)) { scanmatchtable(paramtab, pprog, 1, on|roff, 0, paramtab->printnode, printflags); continue; @@ -2648,7 +2787,7 @@ bin_typeset(char *name, char **argv, Options ops, int func) for (pmnode = firstnode(pmlist); pmnode; incnode(pmnode)) { pm = (Param) getdata(pmnode); if (!typeset_single(name, pm->node.nam, pm, func, on, off, roff, - asg->value, NULL, ops, 0)) + asg, NULL, ops, 0)) returnval = 1; } } @@ -2657,7 +2796,7 @@ bin_typeset(char *name, char **argv, Options ops, int func) } /* Take arguments literally. Don't glob */ - while ((asg = getasg(*argv++))) { + while ((asg = getasg(&argv, assigns))) { HashNode hn = (paramtab == realparamtab ? gethashnode2(paramtab, asg->name) : paramtab->getnode(paramtab, asg->name)); @@ -2671,7 +2810,7 @@ bin_typeset(char *name, char **argv, Options ops, int func) continue; } if (!typeset_single(name, asg->name, (Param)hn, - func, on, off, roff, asg->value, NULL, + func, on, off, roff, asg, NULL, ops, 0)) returnval = 1; } @@ -3514,7 +3653,7 @@ bin_hash(char *name, char **argv, Options ops, UNUSED(int func)) } queue_signals(); - for (;*argv;++argv) { + while (*argv) { void *hn; if (OPT_ISSET(ops,'m')) { /* with the -m option, treat the argument as a glob pattern */ @@ -3529,12 +3668,12 @@ bin_hash(char *name, char **argv, Options ops, UNUSED(int func)) } continue; } - if (!(asg = getasg(*argv))) { + if (!(asg = getasg(&argv, NULL))) { zwarnnam(name, "bad assignment"); returnval = 1; - } else if (asg->value) { + } else if (ASG_VALUEP(asg)) { if(isset(RESTRICTED)) { - zwarnnam(name, "restricted: %s", asg->value); + zwarnnam(name, "restricted: %s", asg->value.scalar); returnval = 1; } else { /* The argument is of the form foo=bar, * @@ -3550,12 +3689,12 @@ bin_hash(char *name, char **argv, Options ops, UNUSED(int func)) } else { Nameddir nd = hn = zshcalloc(sizeof *nd); nd->node.flags = 0; - nd->dir = ztrdup(asg->value); + nd->dir = ztrdup(asg->value.scalar); } } else { Cmdnam cn = hn = zshcalloc(sizeof *cn); cn->node.flags = HASHED; - cn->u.cmd = ztrdup(asg->value); + cn->u.cmd = ztrdup(asg->value.scalar); } ht->addnode(ht, ztrdup(asg->name), hn); if(OPT_ISSET(ops,'v')) @@ -3761,12 +3900,12 @@ bin_alias(char *name, char **argv, Options ops, UNUSED(int func)) /* Take arguments literally. Don't glob */ queue_signals(); - while ((asg = getasg(*argv++))) { - if (asg->value && !OPT_ISSET(ops,'L')) { + while ((asg = getasg(&argv, NULL))) { + if (asg->value.scalar && !OPT_ISSET(ops,'L')) { /* The argument is of the form foo=bar and we are not * * forcing a listing with -L, so define an alias */ ht->addnode(ht, ztrdup(asg->name), - createaliasnode(ztrdup(asg->value), flags1)); + createaliasnode(ztrdup(asg->value.scalar), flags1)); } else if ((a = (Alias) ht->getnode(ht, asg->name))) { /* display alias if appropriate */ if (!type_opts || ht == sufaliastab || |