/* * params.c - parameters * * This file is part of zsh, the Z shell. * * Copyright (c) 1992-1997 Paul Falstad * All rights reserved. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and to distribute modified versions of this software for any * purpose, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * In no event shall Paul Falstad or the Zsh Development Group be liable * to any party for direct, indirect, special, incidental, or consequential * damages arising out of the use of this software and its documentation, * even if Paul Falstad and the Zsh Development Group have been advised of * the possibility of such damage. * * Paul Falstad and the Zsh Development Group specifically disclaim any * warranties, including, but not limited to, the implied warranties of * merchantability and fitness for a particular purpose. The software * provided hereunder is on an "as is" basis, and Paul Falstad and the * Zsh Development Group have no obligation to provide maintenance, * support, updates, enhancements, or modifications. * */ #include "zsh.mdh" #include "params.pro" #include "version.h" /* what level of localness we are at */ /**/ int locallevel; /* Variables holding values of special parameters */ /**/ char **pparams, /* $argv */ **cdpath, /* $cdpath */ **fignore, /* $fignore */ **fpath, /* $fpath */ **mailpath, /* $mailpath */ **manpath, /* $manpath */ **path, /* $path */ **psvar, /* $psvar */ **watch; /* $watch */ /**/ char *argzero, /* $0 */ *underscore, /* $_ */ *home, /* $HOME */ *hostnam, /* $HOST */ *ifs, /* $IFS */ *nullcmd, /* $NULLCMD */ *oldpwd, /* $OLDPWD */ *zoptarg, /* $OPTARG */ *postedit, /* $POSTEDIT */ *prompt, /* $PROMPT */ *prompt2, /* $PROMPT2 */ *prompt3, /* $PROMPT3 */ *prompt4, /* $PROMPT4 */ *pwd, /* $PWD */ *readnullcmd, /* $READNULLCMD */ *rprompt, /* $RPROMPT */ *sprompt, /* $SPROMPT */ *term, /* $TERM */ *ttystrname, /* $TTY */ *wordchars, /* $WORDCHARS */ *zsh_name; /* $ZSH_NAME */ /**/ long lastval, /* $? */ mypid, /* $$ */ lastpid, /* $! */ columns, /* $COLUMNS */ lineno, /* $LINENO */ lines, /* $LINES */ zoptind, /* $OPTIND */ ppid, /* $PPID */ shlvl; /* $SHLVL */ /* $histchars */ /**/ unsigned char bangchar, hatchar, hashchar; /* $SECONDS = time(NULL) - shtimer.tv_sec */ /**/ struct timeval shtimer; /* 0 if this $TERM setup is usable, otherwise it contains TERM_* flags */ /**/ int termflags; /* Nodes for special parameters for parameter hash table */ static #ifdef HAVE_UNION_INIT # define BR(X) {X} struct param #else # define BR(X) X struct iparam { struct hashnode *next; char *nam; /* hash data */ int flags; /* PM_* flags (defined in zsh.h) */ void *value; void (*func1) _((void)); /* set func */ char *(*func2) _((void)); /* get func */ void (*unsetfn) _((Param, int)); /* unset func */ int ct; /* output base or field width */ char *env; /* location in environment, if exported */ char *ename; /* name of corresponding environment var */ Param old; /* old struct for use with local */ int level; /* if (old != NULL), level of localness */ } #endif special_params[] ={ #define SFN(X) BR(((void (*)_((Param, char *)))(X))) #define GFN(X) BR(((char *(*)_((Param)))(X))) #define IPDEF1(A,B,C,D) {NULL,A,PM_INTEGER|PM_SPECIAL|D,BR(NULL),SFN(C),GFN(B),stdunsetfn,10,NULL,NULL,NULL,0} IPDEF1("#", poundgetfn, nullsetfn, PM_READONLY), IPDEF1("ERRNO", errnogetfn, nullsetfn, PM_READONLY), IPDEF1("GID", gidgetfn, gidsetfn, PM_DONTIMPORT | PM_RESTRICTED), IPDEF1("EGID", egidgetfn, egidsetfn, PM_DONTIMPORT | PM_RESTRICTED), IPDEF1("HISTSIZE", histsizegetfn, histsizesetfn, PM_RESTRICTED), IPDEF1("RANDOM", randomgetfn, randomsetfn, 0), IPDEF1("SECONDS", secondsgetfn, secondssetfn, 0), IPDEF1("UID", uidgetfn, uidsetfn, PM_DONTIMPORT | PM_RESTRICTED), IPDEF1("EUID", euidgetfn, euidsetfn, PM_DONTIMPORT | PM_RESTRICTED), IPDEF1("TTYIDLE", ttyidlegetfn, nullsetfn, PM_READONLY), #define IPDEF2(A,B,C,D) {NULL,A,PM_SCALAR|PM_SPECIAL|D,BR(NULL),SFN(C),GFN(B),stdunsetfn,0,NULL,NULL,NULL,0} IPDEF2("USERNAME", usernamegetfn, usernamesetfn, PM_DONTIMPORT|PM_RESTRICTED), IPDEF2("-", dashgetfn, nullsetfn, PM_READONLY), IPDEF2("histchars", histcharsgetfn, histcharssetfn, PM_DONTIMPORT), IPDEF2("HOME", homegetfn, homesetfn, 0), IPDEF2("TERM", termgetfn, termsetfn, 0), IPDEF2("WORDCHARS", wordcharsgetfn, wordcharssetfn, 0), IPDEF2("IFS", ifsgetfn, ifssetfn, PM_DONTIMPORT), IPDEF2("_", underscoregetfn, nullsetfn, PM_READONLY), #ifdef LC_ALL # define LCIPDEF(name) IPDEF2(name, strgetfn, lcsetfn, PM_UNSET) IPDEF2("LANG", strgetfn, langsetfn, PM_UNSET), IPDEF2("LC_ALL", strgetfn, lc_allsetfn, PM_UNSET), # ifdef LC_COLLATE LCIPDEF("LC_COLLATE"), # endif # ifdef LC_CTYPE LCIPDEF("LC_CTYPE"), # endif # ifdef LC_MESSAGES LCIPDEF("LC_MESSAGES"), # endif # ifdef LC_TIME LCIPDEF("LC_TIME"), # endif #endif #define IPDEF4(A,B) {NULL,A,PM_INTEGER|PM_READONLY|PM_SPECIAL,BR((void *)B),SFN(nullsetfn),GFN(intvargetfn),stdunsetfn,10,NULL,NULL,NULL,0} IPDEF4("!", &lastpid), IPDEF4("$", &mypid), IPDEF4("?", &lastval), IPDEF4("LINENO", &lineno), IPDEF4("PPID", &ppid), #define IPDEF5(A,B,F) {NULL,A,PM_INTEGER|PM_SPECIAL,BR((void *)B),SFN(F),GFN(intvargetfn),stdunsetfn,10,NULL,NULL,NULL,0} IPDEF5("COLUMNS", &columns, zlevarsetfn), IPDEF5("LINES", &lines, zlevarsetfn), IPDEF5("OPTIND", &zoptind, intvarsetfn), IPDEF5("SHLVL", &shlvl, intvarsetfn), #define IPDEF7(A,B) {NULL,A,PM_SCALAR|PM_SPECIAL,BR((void *)B),SFN(strvarsetfn),GFN(strvargetfn),stdunsetfn,0,NULL,NULL,NULL,0} IPDEF7("OPTARG", &zoptarg), IPDEF7("NULLCMD", &nullcmd), IPDEF7("POSTEDIT", &postedit), IPDEF7("READNULLCMD", &readnullcmd), IPDEF7("RPROMPT", &rprompt), IPDEF7("PS1", &prompt), IPDEF7("PS2", &prompt2), IPDEF7("PS3", &prompt3), IPDEF7("PS4", &prompt4), IPDEF7("RPS1", &rprompt), IPDEF7("SPROMPT", &sprompt), IPDEF7("0", &argzero), #define IPDEF8(A,B,C,D) {NULL,A,D|PM_SCALAR|PM_SPECIAL,BR((void *)B),SFN(colonarrsetfn),GFN(colonarrgetfn),stdunsetfn,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), #ifdef DYNAMIC /* MODULE_PATH is not imported for security reasons */ IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED), #endif #define IPDEF9F(A,B,C,D) {NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT,BR((void *)B),SFN(arrvarsetfn),GFN(arrvargetfn),stdunsetfn,0,NULL,C,NULL,0} #define IPDEF9(A,B,C) IPDEF9F(A,B,C,0) IPDEF9("*", &pparams, NULL), IPDEF9("@", &pparams, NULL), {NULL, NULL}, /* The following parameters are not avaible in sh/ksh compatibility * * mode. All of these has sh compatible equivalents. */ IPDEF1("ARGC", poundgetfn, nullsetfn, PM_READONLY), IPDEF2("HISTCHARS", histcharsgetfn, histcharssetfn, PM_DONTIMPORT), IPDEF4("status", &lastval), IPDEF7("prompt", &prompt), 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"), #ifdef DYNAMIC IPDEF9F("module_path", &module_path, "MODULE_PATH", PM_RESTRICTED), #endif IPDEF9F("path", &path, "PATH", PM_RESTRICTED), {NULL, NULL} }; #undef BR static Param argvparam; /* hash table containing the parameters */ /**/ HashTable paramtab; /* Set up parameter hash table. This will add predefined * * parameter entries as well as setting up parameter table * * entries for environment variables we inherit. */ /**/ void createparamtable(void) { Param ip, pm; char **new_environ, **envp, **envp2, **sigptr, **t; 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; /* Add the special parameters to the hash table */ for (ip = special_params; ip->nam; ip++) paramtab->addnode(paramtab, ztrdup(ip->nam), ip); if (emulation != EMULATE_SH && emulation != EMULATE_KSH) while ((++ip)->nam) paramtab->addnode(paramtab, ztrdup(ip->nam), ip); argvparam = (Param) paramtab->getnode(paramtab, "*"); noerrs = 1; HEAPALLOC { /* Add the standard non-special parameters which have to * * be initialized before we copy the environment variables. * * We don't want to override whatever values the users has * * given them in the environment. */ setiparam("MAILCHECK", 60); setiparam("LOGCHECK", 60); setiparam("KEYTIMEOUT", 40); setiparam("LISTMAX", 100); #ifdef HAVE_SELECT setiparam("BAUD", getbaudrate(&shttyinfo)); /* get the output baudrate */ #endif setsparam("FCEDIT", ztrdup(DEFAULT_FCEDIT)); setsparam("TMPPREFIX", ztrdup(DEFAULT_TMPPREFIX)); setsparam("TIMEFMT", ztrdup(DEFAULT_TIMEFMT)); setsparam("WATCHFMT", ztrdup(default_watchfmt)); setsparam("HOST", ztrdup(hostnam)); setsparam("LOGNAME", ztrdup((str = getlogin()) && *str ? str : cached_username)); /* Copy the environment variables we are inheriting to dynamic * * memory, so we can do mallocs and frees on it. */ num_env = arrlen(environ); new_environ = (char **) zalloc(sizeof(char *) * (num_env + 1)); *new_environ = NULL; /* Now incorporate environment variables we are inheriting * * into the parameter hash table. */ for (envp = new_environ, envp2 = environ; *envp2; envp2++) { for (str = *envp2; *str && *str != '='; str++); if (*str == '=') { iname = NULL; *str = '\0'; if (!idigit(**envp2) && isident(*envp2) && !strchr(*envp2, '[')) { iname = *envp2; if ((!(pm = (Param) paramtab->getnode(paramtab, iname)) || !(pm->flags & PM_DONTIMPORT)) && (pm = setsparam(iname, metafy(str + 1, -1, META_DUP))) && !(pm->flags & PM_EXPORTED)) { *str = '='; pm->flags |= PM_EXPORTED; pm->env = *envp++ = ztrdup(*envp2); *envp = NULL; if (pm->flags & PM_SPECIAL) pm->env = replenv(pm->env, getsparam(pm->nam)); } } *str = '='; } } environ = new_environ; pm = (Param) paramtab->getnode(paramtab, "HOME"); if (!(pm->flags & PM_EXPORTED)) { pm->flags |= PM_EXPORTED; pm->env = addenv("HOME", home); } pm = (Param) paramtab->getnode(paramtab, "LOGNAME"); if (!(pm->flags & PM_EXPORTED)) { pm->flags |= PM_EXPORTED; pm->env = addenv("LOGNAME", pm->u.str); } pm = (Param) paramtab->getnode(paramtab, "SHLVL"); if (!(pm->flags & PM_EXPORTED)) pm->flags |= PM_EXPORTED; sprintf(buf, "%d", (int)++shlvl); pm->env = addenv("SHLVL", buf); /* Add the standard non-special parameters */ set_pwd_env(); setsparam("MACHTYPE", ztrdup(MACHTYPE)); setsparam("OSTYPE", ztrdup(OSTYPE)); setsparam("TTY", ztrdup(ttystrname)); setsparam("VENDOR", ztrdup(VENDOR)); setsparam("ZSH_NAME", ztrdup(zsh_name)); setsparam("ZSH_VERSION", ztrdup(ZSH_VERSION)); setaparam("signals", sigptr = zalloc((SIGCOUNT+4) * sizeof(char *))); for (t = sigs; (*sigptr++ = ztrdup(*t++)); ); } LASTALLOC; noerrs = 0; } /* 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 * * scope, it is hidden by a newly created parameter. An already existing * * parameter node at the current level may be `created' and returned * * provided it is unset and not special. If the parameter can't be * * created because it already exists, the PM_UNSET flag is cleared. */ /**/ Param createparam(char *name, int flags) { Param pm, oldpm; if (name != nulstring) { oldpm = (Param) paramtab->getnode(paramtab, name); if (oldpm && oldpm->level == locallevel) { if (!(oldpm->flags & PM_UNSET) || (oldpm->flags & PM_SPECIAL)) { oldpm->flags &= ~PM_UNSET; return NULL; } if ((oldpm->flags & PM_RESTRICTED) && isset(RESTRICTED)) { zerr("%s: restricted", name, 0); return NULL; } pm = oldpm; pm->ct = 0; oldpm = pm->old; } else { pm = (Param) zcalloc(sizeof *pm); if ((pm->old = oldpm)) { /* needed to avoid freeing oldpm */ paramtab->removenode(paramtab, name); } paramtab->addnode(paramtab, ztrdup(name), pm); } if (isset(ALLEXPORT) && !oldpm) flags |= PM_EXPORTED; } else pm = (Param) alloc(sizeof *pm); pm->flags = flags; if(!(pm->flags & PM_SPECIAL)) { switch (PM_TYPE(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; default: DPUTS(1, "BUG: tried to create param node without valid flag"); break; } pm->unsetfn = stdunsetfn; } return pm; } /* Return 1 if the string s is a valid identifier, else return 0. */ /**/ int isident(char *s) { char *ss; int ne; ne = noeval; /* save the current value of noeval */ if (!*s) /* empty string is definitely not valid */ return 0; /* find the first character in `s' not in the iident type table */ for (ss = s; *ss; ss++) if (!iident(*ss)) break; /* If this exhaust `s' or the next two characters * * are [(, then it is a valid identifier. */ if (!*ss || (*ss == '[' && ss[1] == '(')) return 1; /* Else if the next character is not [, then it is * * definitely not a valid identifier. */ if (*ss != '[') return 0; noeval = 1; (void)mathevalarg(++ss, &ss); if (*ss == ',') (void)mathevalarg(++ss, &ss); noeval = ne; /* restore the value of noeval */ if (*ss != ']' || ss[1]) return 0; return 1; } static char **garr; /**/ static long getarg(char **str, int *inv, Value v, int a2, long *w) { int num = 1, word = 0, rev = 0, ind = 0, down = 0, l, i; char *s = *str, *sep = NULL, *t, sav, *d, **ta, **p, *tt; long r = 0; Comp c; /* first parse any subscription flags */ if (*s == '(' || *s == Inpar) { int escapes = 0; int waste; for (s++; *s != ')' && *s != Outpar && s != *str; s++) { switch (*s) { case 'r': rev = 1; down = ind = 0; break; case 'R': rev = down = 1; ind = 0; break; case 'i': rev = ind = 1; down = 0; break; case 'I': rev = ind = down = 1; break; case 'w': /* If the parameter is a scalar, then make subscription * * work on a per-word basis instead of characters. */ word = 1; break; case 'f': word = 1; sep = "\n"; break; case 'e': /* obsolate compatibility flag without any real effect */ break; case 'n': t = get_strarg(++s); if (!*t) goto flagerr; sav = *t; *t = '\0'; num = mathevalarg(s + 1, &d); if (!num) num = 1; *t = sav; s = t; break; case 'p': escapes = 1; break; case 's': /* This gives the string that separates words * * (for use with the `w' flag. */ t = get_strarg(++s); if (!*t) goto flagerr; sav = *t; *t = '\0'; sep = escapes ? getkeystring(s + 1, &waste, 1, &waste) : dupstring(s + 1); *t = sav; s = t; break; default: flagerr: num = 1; word = rev = ind = down = 0; sep = NULL; s = *str - 1; } } if (s != *str) s++; } if (num < 0) { down = !down; num = -num; } *inv = ind; for (t=s, i=0; *t && ((*t != ']' && *t != Outbrack && *t != ',') || i); t++) if (*t == '[' || *t == Inbrack) i++; else if (*t == ']' || *t == Outbrack) i--; if (!*t) return 0; s = dupstrpfx(s, t - s); *str = tt = t; if (parsestr(s)) return 0; singsub(&s); if (!rev) { if (!(r = mathevalarg(s, &s)) || (isset(KSHARRAYS) && r >= 0)) r++; if (word && !v->isarr) { s = t = getstrvalue(v); i = wordcount(s, sep, 0); if (r < 0) r += i + 1; if (r < 1) r = 1; if (r > i) r = i; if (!s || !*s) return 0; while ((d = findword(&s, sep)) && --r); if (!d) return 0; if (!a2 && *tt != ',') *w = (long)(s - t) - 1; return (a2 ? s : d + 1) - t; } else if (!v->isarr && !word) { s = getstrvalue(v); if (r > 0) { for (t = s + r - 1; *s && s < t;) if (*s++ == Meta) s++, t++, r++; } else { r += ztrlen(s); for (t = s + r; *s && s < t; r--) if (*s++ == Meta) t++, r++; r -= strlen(s); } } } else { if (!v->isarr && !word) { l = strlen(s); if (a2) { if (!l || *s != '*') { d = (char *) ncalloc(l + 2); *d = '*'; strcpy(d + 1, s); s = d; } } else { if (!l || s[l - 1] != '*') { d = (char *) ncalloc(l + 2); strcpy(d, s); strcat(d, "*"); s = d; } } } tokenize(s); if ((c = parsereg(s))) { if (v->isarr) { ta = getarrvalue(v); if (!ta || !*ta) return 0; if (down) for (r = -1, p = ta + arrlen(ta) - 1; p >= ta; r--, p--) { if (domatch(*p, c, 0) && !--num) return r; } else for (r = 1, p = ta; *p; r++, p++) if (domatch(*p, c, 0) && !--num) return r; } else if (word) { ta = sepsplit(d = s = getstrvalue(v), sep, 1); if (down) { for (p = ta + (r = arrlen(ta)) - 1; p >= ta; p--, r--) if (domatch(*p, c, 0) && !--num) break; if (p < ta) return 0; } else { for (r = 1, p = ta; *p; r++, p++) if (domatch(*p, c, 0) && !--num) break; if (!*p) return 0; } if (a2) r++; for (i = 0; (t = findword(&d, sep)) && *t; i++) if (!--r) { r = (long)(t - s + (a2 ? -1 : 1)); if (!a2 && *tt != ',') *w = r + strlen(ta[i]) - 2; return r; } return a2 ? -1 : 0; } else { d = getstrvalue(v); if (!d || !*d) return 0; if (a2) { if (down) for (r = -2, t = d + strlen(d) - 1; t >= d; r--, t--) { sav = *t; *t = '\0'; if (domatch(d, c, 0) && !--num) { *t = sav; return r; } *t = sav; } else for (r = 0, t = d; *t; r++, t++) { sav = *t; *t = '\0'; if (domatch(d, c, 0) && !--num) { *t = sav; return r; } *t = sav; } } else { if (down) for (r = -1, t = d + strlen(d) - 1; t >= d; r--, t--) { if (domatch(t, c, 0) && !--num) return r; } else for (r = 1, t = d; *t; r++, t++) if (domatch(t, c, 0) && !--num) return r; } return 0; } } } return r; } /**/ int getindex(char **pptr, Value v) { int a, b, inv = 0; char *s = *pptr, *tbrack; *s++ = '['; for (tbrack = s; *tbrack && *tbrack != ']' && *tbrack != Outbrack; tbrack++) if (itok(*tbrack)) *tbrack = ztokens[*tbrack - Pound]; if (*tbrack == Outbrack) *tbrack = ']'; if ((s[0] == '*' || s[0] == '@') && s[1] == ']') { if (v->isarr) v->isarr = (s[0] == '*') ? 1 : -1; v->a = 0; v->b = -1; s += 2; } else { long we = 0, dummy; a = getarg(&s, &inv, v, 0, &we); if (inv) { if (!v->isarr && a != 0) { char *t, *p; t = getstrvalue(v); if (a > 0) { for (p = t + a - 1; p-- > t; ) if (*p == Meta) a--; } else a = -ztrlen(t + a + strlen(t)); } if (a > 0 && isset(KSHARRAYS)) a--; v->inv = 1; v->isarr = 0; v->a = v->b = a; if (*s == ',') { zerr("invalid subscript", NULL, 0); while (*s != ']' && *s != Outbrack) s++; *pptr = s; return 1; } if (*s == ']' || *s == Outbrack) s++; } else { if (a > 0) a--; if (*s == ',') { s++; b = getarg(&s, &inv, v, 1, &dummy); if (b > 0) b--; } else { b = we ? we : a; } if (*s == ']' || *s == Outbrack) { s++; if (v->isarr && a == b) v->isarr = 0; v->a = a; v->b = b; } else s = *pptr; } } *pptr = s; return 0; } /**/ Value getvalue(char **pptr, int bracks) { char *s, *t; char sav; Value v; int ppar = 0; s = t = *pptr; garr = NULL; if (idigit(*s)) if (bracks >= 0) ppar = zstrtol(s, &s, 10); else ppar = *s++ - '0'; else if (iident(*s)) while (iident(*s)) s++; else if (*s == Quest) *s++ = '?'; else if (*s == Pound) *s++ = '#'; else if (*s == String) *s++ = '$'; else if (*s == Qstring) *s++ = '$'; else if (*s == Star) *s++ = '*'; else if (*s == '#' || *s == '-' || *s == '?' || *s == '$' || *s == '_' || *s == '!' || *s == '@' || *s == '*') s++; else return NULL; if ((sav = *s)) *s = '\0'; if (ppar) { v = (Value) hcalloc(sizeof *v); v->pm = argvparam; v->inv = 0; v->a = v->b = ppar - 1; if (sav) *s = sav; } else { Param pm; int isvarat; isvarat = !strcmp(t, "@"); pm = (Param) paramtab->getnode(paramtab, *t == '0' ? "0" : t); if (sav) *s = sav; *pptr = s; if (!pm || (pm->flags & PM_UNSET)) return NULL; v = (Value) hcalloc(sizeof *v); if (PM_TYPE(pm->flags) == PM_ARRAY) v->isarr = isvarat ? -1 : 1; v->pm = pm; v->inv = 0; v->a = 0; v->b = -1; if (bracks > 0 && (*s == '[' || *s == Inbrack)) { if (getindex(&s, v)) { *pptr = s; return v; } } else if (v->isarr && iident(*t) && isset(KSHARRAYS)) v->b = 0, v->isarr = 0; } if (!bracks && *s) return NULL; *pptr = s; if (v->a > MAX_ARRLEN || v->a < -MAX_ARRLEN) { zerr("subscript to %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); return NULL; } return v; } /**/ char * getstrvalue(Value v) { char *s, **ss; static char buf[(sizeof(long) * 8) + 4]; if (!v) return hcalloc(1); HEAPALLOC { if (v->inv) { sprintf(buf, "%d", v->a); s = dupstring(buf); LASTALLOC_RETURN s; } switch(PM_TYPE(v->pm->flags)) { case PM_ARRAY: if (v->isarr) s = sepjoin(v->pm->gets.afn(v->pm), 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]; } LASTALLOC_RETURN s; case PM_INTEGER: convbase(s = buf, v->pm->gets.ifn(v->pm), v->pm->ct); break; case PM_SCALAR: s = v->pm->gets.cfn(v->pm); break; default: s = NULL; DPUTS(1, "BUG: param node without valid type"); break; } if (v->a == 0 && v->b == -1) LASTALLOC_RETURN s; if (v->a < 0) v->a += strlen(s); if (v->b < 0) v->b += strlen(s); s = (v->a > (int)strlen(s)) ? dupstring("") : dupstring(s + v->a); if (v->b < v->a) s[0] = '\0'; else if (v->b - v->a < (int)strlen(s)) s[v->b - v->a + 1 + (s[v->b - v->a] == Meta)] = '\0'; } LASTALLOC; return s; } static char *nular[] = {"", NULL}; /**/ char ** getarrvalue(Value v) { char **s; if (!v) return arrdup(nular); if (v->inv) { char buf[DIGBUFSIZE]; s = arrdup(nular); sprintf(buf, "%d", v->a); s[0] = dupstring(buf); return s; } s = v->pm->gets.afn(v->pm); if (v->a == 0 && v->b == -1) return s; if (v->a < 0) v->a += arrlen(s); if (v->b < 0) v->b += arrlen(s); if (v->a > arrlen(s) || v->a < 0) s = arrdup(nular); else s = arrdup(s) + v->a; if (v->b < v->a) s[0] = NULL; else if (v->b - v->a < arrlen(s)) s[v->b - v->a + 1] = NULL; return s; } /**/ long getintvalue(Value v) { if (!v || v->isarr) return 0; if (v->inv) return v->a; if (PM_TYPE(v->pm->flags) == PM_INTEGER) return v->pm->gets.ifn(v->pm); return matheval(getstrvalue(v)); } /**/ static void setstrvalue(Value v, char *val) { char buf[(sizeof(long) * 8) + 4]; if (v->pm->flags & PM_READONLY) { zerr("read-only variable: %s", v->pm->nam, 0); zsfree(val); return; } if ((v->pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) { zerr("%s: restricted", v->pm->nam, 0); zsfree(val); return; } switch (PM_TYPE(v->pm->flags)) { case PM_SCALAR: MUSTUSEHEAP("setstrvalue"); if (v->a == 0 && v->b == -1) { (v->pm->sets.cfn) (v->pm, val); if (v->pm->flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z) && !v->pm->ct) v->pm->ct = strlen(val); } else { char *z, *x; int zlen; z = dupstring((v->pm->gets.cfn) (v->pm)); zlen = strlen(z); if (v->inv && unset(KSHARRAYS)) v->a--, v->b--; if (v->a < 0) { v->a += zlen; if (v->a < 0) v->a = 0; } if (v->a > zlen) v->a = zlen; if (v->b < 0) v->b += zlen; if (v->b > zlen - 1) v->b = zlen - 1; x = (char *) zalloc(v->a + strlen(val) + zlen - v->b); strncpy(x, z, v->a); strcpy(x + v->a, val); strcat(x + v->a, z + v->b + 1); (v->pm->sets.cfn) (v->pm, x); zsfree(val); } break; case PM_INTEGER: if (val) { (v->pm->sets.ifn) (v->pm, matheval(val)); zsfree(val); } if (!v->pm->ct && lastbase != -1) v->pm->ct = lastbase; break; case PM_ARRAY: MUSTUSEHEAP("setstrvalue"); { char **ss = (char **) zalloc(2 * sizeof(char *)); ss[0] = val; ss[1] = NULL; setarrvalue(v, ss); } break; } if ((!v->pm->env && !(v->pm->flags & PM_EXPORTED) && !(isset(ALLEXPORT) && !v->pm->old)) || (v->pm->flags & PM_ARRAY) || v->pm->ename) return; if (PM_TYPE(v->pm->flags) == PM_INTEGER) convbase(val = buf, v->pm->gets.ifn(v->pm), v->pm->ct); else val = v->pm->gets.cfn(v->pm); if (v->pm->env) v->pm->env = replenv(v->pm->env, val); else { v->pm->flags |= PM_EXPORTED; v->pm->env = addenv(v->pm->nam, val); } } /**/ static void setintvalue(Value v, long val) { char buf[DIGBUFSIZE]; if (v->pm->flags & PM_READONLY) { zerr("read-only variable: %s", v->pm->nam, 0); return; } if ((v->pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) { zerr("%s: restricted", v->pm->nam, 0); return; } switch (PM_TYPE(v->pm->flags)) { case PM_SCALAR: case PM_ARRAY: sprintf(buf, "%ld", val); setstrvalue(v, ztrdup(buf)); break; case PM_INTEGER: (v->pm->sets.ifn) (v->pm, val); setstrvalue(v, NULL); break; } } /**/ static void setarrvalue(Value v, char **val) { if (v->pm->flags & PM_READONLY) { zerr("read-only variable: %s", v->pm->nam, 0); freearray(val); return; } if ((v->pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) { zerr("%s: restricted", v->pm->nam, 0); freearray(val); return; } if (PM_TYPE(v->pm->flags) != PM_ARRAY) { 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 { char **old, **new, **p, **q, **r; int n, ll, i; if (v->inv && unset(KSHARRAYS)) v->a--, v->b--; q = old = v->pm->gets.afn(v->pm); n = arrlen(old); if (v->a < 0) v->a += n; if (v->b < 0) v->b += n; if (v->a < 0) v->a = 0; if (v->b < 0) v->b = 0; ll = v->a + arrlen(val); if (v->b < n) ll += n - v->b; p = new = (char **) zcalloc(sizeof(char *) * (ll + 1)); for (i = 0; i < v->a; i++) *p++ = i < n ? ztrdup(*q++) : ztrdup(""); for (r = val; *r;) *p++ = ztrdup(*r++); if (v->b + 1 < n) for (q = old + v->b + 1; *q;) *p++ = ztrdup(*q++); *p = NULL; (v->pm->sets.afn) (v->pm, new); freearray(val); } } /* Retrieve an integer parameter */ /**/ long getiparam(char *s) { Value v; if (!(v = getvalue(&s, 1))) return 0; return getintvalue(v); } /* Retrieve a scalar (string) parameter */ /**/ char * getsparam(char *s) { Value v; if (!(v = getvalue(&s, 0))) return NULL; return getstrvalue(v); } /* Retrieve an array parameter */ /**/ char ** getaparam(char *s) { Value v; if (!idigit(*s) && (v = getvalue(&s, 0)) && PM_TYPE(v->pm->flags) == PM_ARRAY) return v->pm->gets.afn(v->pm); return NULL; } /**/ Param setsparam(char *s, char *val) { Value v; char *t = s; char *ss; if (!isident(s)) { zerr("not an identifier: %s", s, 0); zsfree(val); errflag = 1; return NULL; } if ((ss = strchr(s, '['))) { *ss = '\0'; if (!(v = getvalue(&s, 1))) createparam(t, PM_ARRAY); *ss = '['; v = NULL; } else { if (!(v = getvalue(&s, 1))) createparam(t, PM_SCALAR); else if (PM_TYPE(v->pm->flags) == PM_ARRAY && !(v->pm->flags & PM_SPECIAL) && unset(KSHARRAYS)) { unsetparam(t); createparam(t, PM_SCALAR); v = NULL; } } if (!v && !(v = getvalue(&t, 1))) { zsfree(val); return NULL; } setstrvalue(v, val); return v->pm; } /**/ Param setaparam(char *s, char **val) { Value v; char *t = s; char *ss; if (!isident(s)) { zerr("not an identifier: %s", s, 0); freearray(val); errflag = 1; return NULL; } if ((ss = strchr(s, '['))) { *ss = '\0'; if (!(v = getvalue(&s, 1))) createparam(t, PM_ARRAY); *ss = '['; v = NULL; } else { if (!(v = getvalue(&s, 1))) createparam(t, PM_ARRAY); else if (PM_TYPE(v->pm->flags) != PM_ARRAY && !(v->pm->flags & PM_SPECIAL)) { int uniq = v->pm->flags & PM_UNIQUE; unsetparam(t); createparam(t, PM_ARRAY | uniq); v = NULL; } } if (!v) if (!(v = getvalue(&t, 1))) return NULL; if (isset(KSHARRAYS) && !ss) /* the whole array should be set instead of only the first element */ v->b = -1; setarrvalue(v, val); return v->pm; } /**/ Param setiparam(char *s, long val) { Value v; char *t = s; Param pm; if (!isident(s)) { zerr("not an identifier: %s", s, 0); errflag = 1; return NULL; } if (!(v = getvalue(&s, 1))) { pm = createparam(t, PM_INTEGER); DPUTS(!pm, "BUG: parameter not created"); pm->u.val = val; return pm; } setintvalue(v, val); return v->pm; } /* Unset a parameter */ /**/ void unsetparam(char *s) { Param pm; if ((pm = (Param) paramtab->getnode(paramtab, s))) unsetparam_pm(pm, 0, 1); } /* Unset a parameter */ /**/ void unsetparam_pm(Param pm, int altflag, int exp) { Param oldpm, altpm; if ((pm->flags & PM_READONLY) && pm->level <= locallevel) { zerr("read-only variable: %s", pm->nam, 0); return; } if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) { zerr("%s: restricted", pm->nam, 0); return; } pm->unsetfn(pm, exp); if ((pm->flags & PM_EXPORTED) && pm->env) { delenv(pm->env); zsfree(pm->env); pm->env = NULL; } /* remove it under its alternate name if necessary */ if (pm->ename && !altflag) { altpm = (Param) paramtab->getnode(paramtab, pm->ename); if (altpm) unsetparam_pm(altpm, 1, exp); } /* If this was a local variable, we need to keep the old * * struct so that it is resurrected at the right level. * * This is partly because when an array/scalar value is set * * and the parameter used to be the other sort, unsetparam() * * 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) return; paramtab->removenode(paramtab, pm->nam); /* remove parameter node from table */ if (pm->old) { oldpm = pm->old; paramtab->addnode(paramtab, oldpm->nam, oldpm); if ((PM_TYPE(oldpm->flags) == PM_SCALAR) && oldpm->sets.cfn == strsetfn) adduserdir(oldpm->nam, oldpm->u.str, 0, 0); } paramtab->freenode((HashNode) pm); /* free parameter node */ } /* Standard function to unset a parameter. This is mostly delegated to * * the specific set function. */ /**/ void 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; } pm->flags |= PM_UNSET; } /* Function to get value of an integer parameter */ /**/ static long intgetfn(Param pm) { return pm->u.val; } /* Function to set value of an integer parameter */ /**/ static void intsetfn(Param pm, long x) { pm->u.val = x; } /* Function to get value of a scalar (string) parameter */ /**/ char * strgetfn(Param pm) { return pm->u.str ? pm->u.str : (char *) hcalloc(1); } /* Function to set value of a scalar (string) parameter */ /**/ static void strsetfn(Param pm, char *x) { zsfree(pm->u.str); pm->u.str = x; adduserdir(pm->nam, x, 0, 0); } /* Function to get value of an array parameter */ /**/ static char ** arrgetfn(Param pm) { static char *nullarray = NULL; return pm->u.arr ? pm->u.arr : &nullarray; } /* Function to set value of an array parameter */ /**/ static void arrsetfn(Param pm, char **x) { if (pm->u.arr && pm->u.arr != x) freearray(pm->u.arr); if (pm->flags & PM_UNIQUE) uniqarray(x); pm->u.arr = x; } /* This function is used as the set function for * * special parameters that cannot be set by the user. */ /**/ void nullsetfn(Param pm, char *x) { zsfree(x); } /* Function to get value of generic special integer * * parameter. data is pointer to global variable * * containing the integer value. */ /**/ long intvargetfn(Param pm) { return *((long *)pm->u.data); } /* Function to set value of generic special integer * * parameter. data is pointer to global variable * * where the value is to be stored. */ /**/ void intvarsetfn(Param pm, long x) { *((long *)pm->u.data) = x; } /* Function to set value of any ZLE-related integer * * parameter. data is pointer to global variable * * where the value is to be stored. */ /**/ void zlevarsetfn(Param pm, long x) { if ((long *)pm->u.data == & columns) { if(x <= 0) x = tccolumns > 0 ? tccolumns : 80; if (x > 2) termflags &= ~TERM_NARROW; else termflags |= TERM_NARROW; } else if ((long *)pm->u.data == & lines) { if(x <= 0) x = tclines > 0 ? tclines : 24; if (x > 2) termflags &= ~TERM_SHORT; else termflags |= TERM_SHORT; } *((long *)pm->u.data) = x; } /* Function to set value of generic special scalar * * parameter. data is pointer to a character pointer * * representing the scalar (string). */ /**/ void strvarsetfn(Param pm, char *x) { char **q = ((char **)pm->u.data); zsfree(*q); *q = x; } /* Function to get value of generic special scalar * * parameter. data is pointer to a character pointer * * representing the scalar (string). */ /**/ char * strvargetfn(Param pm) { char *s = *((char **)pm->u.data); if (!s) return hcalloc(1); return s; } /* Function to get value of generic special array * * parameter. data is a pointer to the pointer to * * a pointer (a pointer to a variable length array * * of pointers). */ /**/ char ** arrvargetfn(Param pm) { return *((char ***)pm->u.data); } /* Function to set value of generic special array parameter. * * data is pointer to a variable length array of pointers which * * represents this array of scalars (strings). If pm->ename is * * non NULL, then it is a colon separated environment variable * * version of this array which will need to be updated. */ /**/ void arrvarsetfn(Param pm, char **x) { char ***dptr = (char ***)pm->u.data; if (*dptr != x) freearray(*dptr); if (pm->flags & PM_UNIQUE) uniqarray(x); *dptr = x ? x : mkarray(NULL); if (pm->ename && x) arrfixenv(pm->ename, x); } /**/ char * colonarrgetfn(Param pm) { return zjoin(*(char ***)pm->u.data, ':'); } /**/ void colonarrsetfn(Param pm, char *x) { char ***dptr = (char ***)pm->u.data; freearray(*dptr); *dptr = x ? colonsplit(x, pm->flags & PM_UNIQUE) : mkarray(NULL); if (pm->ename) arrfixenv(pm->nam, *dptr); zsfree(x); } /**/ int uniqarray(char **x) { int changes = 0; char **t, **p = x; if (!x || !*x) return 0; while (*++p) for (t = x; t < p; t++) if (!strcmp(*p, *t)) { zsfree(*p); for (t = p--; (*t = t[1]) != NULL; t++); changes++; break; } return changes; } /* Function to get value of special parameter `#' and `ARGC' */ /**/ long poundgetfn(Param pm) { return arrlen(pparams); } /* Function to get value for special parameter `RANDOM' */ /**/ long randomgetfn(Param pm) { return rand() & 0x7fff; } /* Function to set value of special parameter `RANDOM' */ /**/ void randomsetfn(Param pm, long v) { srand((unsigned int)v); } /* Function to get value for special parameter `SECONDS' */ /**/ long secondsgetfn(Param pm) { return time(NULL) - shtimer.tv_sec; } /* Function to set value of special parameter `SECONDS' */ /**/ void secondssetfn(Param pm, long x) { shtimer.tv_sec = time(NULL) - x; shtimer.tv_usec = 0; } /* Function to get value for special parameter `USERNAME' */ /**/ char * usernamegetfn(Param pm) { return get_username(); } /* Function to set value of special parameter `USERNAME' */ /**/ void usernamesetfn(Param pm, char *x) { #if defined(HAVE_SETUID) && defined(HAVE_GETPWNAM) struct passwd *pswd; if (x && (pswd = getpwnam(x)) && (pswd->pw_uid != cached_uid)) { # ifdef HAVE_INITGROUPS initgroups(x, pswd->pw_gid); # endif if(!setgid(pswd->pw_gid) && !setuid(pswd->pw_uid)) { zsfree(cached_username); cached_username = ztrdup(pswd->pw_name); cached_uid = pswd->pw_uid; } } #endif /* HAVE_SETUID && HAVE_GETPWNAM */ } /* Function to get value for special parameter `UID' */ /**/ long uidgetfn(Param pm) { return getuid(); } /* Function to set value of special parameter `UID' */ /**/ void uidsetfn(Param pm, uid_t x) { #ifdef HAVE_SETUID setuid(x); #endif } /* Function to get value for special parameter `EUID' */ /**/ long euidgetfn(Param pm) { return geteuid(); } /* Function to set value of special parameter `EUID' */ /**/ void euidsetfn(Param pm, uid_t x) { #ifdef HAVE_SETEUID seteuid(x); #endif } /* Function to get value for special parameter `GID' */ /**/ long gidgetfn(Param pm) { return getgid(); } /* Function to set value of special parameter `GID' */ /**/ void gidsetfn(Param pm, gid_t x) { #ifdef HAVE_SETUID setgid(x); #endif } /* Function to get value for special parameter `EGID' */ /**/ long egidgetfn(Param pm) { return getegid(); } /* Function to set value of special parameter `EGID' */ /**/ void egidsetfn(Param pm, gid_t x) { #ifdef HAVE_SETEUID setegid(x); #endif } /**/ long ttyidlegetfn(Param pm) { struct stat ttystat; if (SHTTY == -1 || fstat(SHTTY, &ttystat)) return -1; return time(NULL) - ttystat.st_atime; } /* Function to get value for special parameter `IFS' */ /**/ char * ifsgetfn(Param pm) { return ifs; } /* Function to set value of special parameter `IFS' */ /**/ void ifssetfn(Param pm, char *x) { zsfree(ifs); ifs = x; inittyptab(); } /* Functions to set value of special parameters `LANG' and `LC_*' */ #ifdef LC_ALL static struct localename { char *name; int category; } lc_names[] = { #ifdef LC_COLLATE {"LC_COLLATE", LC_COLLATE}, #endif #ifdef LC_CTYPE {"LC_CTYPE", LC_CTYPE}, #endif #ifdef LC_MESSAGES {"LC_MESSAGES", LC_MESSAGES}, #endif #ifdef LC_TIME {"LC_TIME", LC_TIME}, #endif {NULL, 0} }; /**/ static void setlang(char *x) { struct localename *ln; setlocale(LC_ALL, x ? x : ""); for (ln = lc_names; ln->name; ln++) if ((x = getsparam(ln->name))) setlocale(ln->category, x); } /**/ void lc_allsetfn(Param pm, char *x) { strsetfn(pm, x); if (!x) setlang(getsparam("LANG")); else setlocale(LC_ALL, x); } /**/ void langsetfn(Param pm, char *x) { strsetfn(pm, x); setlang(x); } /**/ void lcsetfn(Param pm, char *x) { struct localename *ln; strsetfn(pm, x); if (getsparam("LC_ALL")) return; if (!x) x = getsparam("LANG"); for (ln = lc_names; ln->name; ln++) if (!strcmp(ln->name, pm->nam)) setlocale(ln->category, x ? x : ""); } #endif /* Function to get value for special parameter `HISTSIZE' */ /**/ long histsizegetfn(Param pm) { return histsiz; } /* Function to set value of special parameter `HISTSIZE' */ /**/ void histsizesetfn(Param pm, long v) { if ((histsiz = v) <= 2) histsiz = 2; resizehistents(); } /* Function to get value for special parameter `ERRNO' */ /**/ long errnogetfn(Param pm) { return errno; } /* Function to get value for special parameter `histchar' */ /**/ char * histcharsgetfn(Param pm) { static char buf[4]; buf[0] = bangchar; buf[1] = hatchar; buf[2] = hashchar; buf[3] = '\0'; return buf; } /* Function to set value of special parameter `histchar' */ /**/ void histcharssetfn(Param pm, char *x) { if (x) { bangchar = x[0]; hatchar = (bangchar) ? x[1] : '\0'; hashchar = (hatchar) ? x[2] : '\0'; zsfree(x); } else { bangchar = '!'; hashchar = '#'; hatchar = '^'; } inittyptab(); } /* Function to get value for special parameter `HOME' */ /**/ char * homegetfn(Param pm) { return home; } /* Function to set value of special parameter `HOME' */ /**/ void homesetfn(Param pm, char *x) { zsfree(home); if (x && isset(CHASELINKS) && (home = xsymlink(x))) zsfree(x); else home = x ? x : ztrdup(""); finddir(NULL); } /* Function to get value for special parameter `WORDCHARS' */ /**/ char * wordcharsgetfn(Param pm) { return wordchars; } /* Function to set value of special parameter `WORDCHARS' */ /**/ void wordcharssetfn(Param pm, char *x) { zsfree(wordchars); wordchars = x; inittyptab(); } /* Function to get value for special parameter `_' */ /**/ char * underscoregetfn(Param pm) { return underscore; } /* Function to get value for special parameter `TERM' */ /**/ char * termgetfn(Param pm) { return term; } /* Function to set value of special parameter `TERM' */ /**/ void termsetfn(Param pm, char *x) { zsfree(term); term = x ? x : ztrdup(""); /* If non-interactive, delay setting up term till we need it. */ if (unset(INTERACTIVE) || !*term) termflags |= TERM_UNKNOWN; else init_term(); } /* We could probably replace the replenv with the actual code to * * do the replacing, since we've already scanned for the string. */ /**/ static void arrfixenv(char *s, char **t) { char **ep, *u; int len_s; Param pm; MUSTUSEHEAP("arrfixenv"); if (t == path) cmdnamtab->emptytable(cmdnamtab); u = zjoin(t, ':'); len_s = strlen(s); pm = (Param) paramtab->getnode(paramtab, s); for (ep = environ; *ep; ep++) if (!strncmp(*ep, s, len_s) && (*ep)[len_s] == '=') { pm->env = replenv(*ep, u); return; } if (isset(ALLEXPORT)) pm->flags |= PM_EXPORTED; if (pm->flags & PM_EXPORTED) pm->env = addenv(s, u); } /* Given *name = "foo", it searchs the environment for string * * "foo=bar", and returns a pointer to the beginning of "bar" */ /**/ char * zgetenv(char *name) { char **ep, *s, *t; for (ep = environ; *ep; ep++) { for (s = *ep, t = name; *s && *s == *t; s++, t++); if (*s == '=' && !*t) return s + 1; } return NULL; } /* Change the value of an existing environment variable */ /**/ char * replenv(char *e, char *value) { char **ep, *s; int len_value; for (ep = environ; *ep; ep++) if (*ep == e) { for (len_value = 0, s = value; *s && (*s++ != Meta || *s++ != 32); len_value++); s = e; while (*s++ != '='); *ep = (char *) zrealloc(e, s - e + len_value + 1); s = s - e + *ep - 1; while (*s++) if ((*s = *value++) == Meta) *s = *value++ ^ 32; return *ep; } return NULL; } /* Given strings *name = "foo", *value = "bar", * * return a new string *str = "foo=bar". */ /**/ static char * mkenvstr(char *name, char *value) { char *str, *s; int len_name, len_value; len_name = strlen(name); for (len_value = 0, s = value; *s && (*s++ != Meta || *s++ != 32); len_value++); s = str = (char *) zalloc(len_name + len_value + 2); strcpy(s, name); s += len_name; *s = '='; while (*s++) if ((*s = *value++) == Meta) *s = *value++ ^ 32; return str; } /* Given *name = "foo", *value = "bar", add the * * string "foo=bar" to the environment. Return a * * pointer to the location of this new environment * * string. */ /**/ char * addenv(char *name, char *value) { char **ep, *s, *t; int num_env; /* First check if there is already an environment * * variable matching string `name'. */ for (ep = environ; *ep; ep++) { for (s = *ep, t = name; *s && *s == *t; s++, t++); if (*s == '=' && !*t) { zsfree(*ep); return *ep = mkenvstr(name, value); } } /* Else we have to make room and add it */ num_env = arrlen(environ); environ = (char **) zrealloc(environ, (sizeof(char *)) * (num_env + 2)); /* Now add it at the end */ ep = environ + num_env; *ep = mkenvstr(name, value); *(ep + 1) = NULL; return *ep; } /* Delete a pointer from the list of pointers to environment * * variables by shifting all the other pointers up one slot. */ /**/ void delenv(char *x) { char **ep; for (ep = environ; *ep; ep++) { if (*ep == x) break; } if (*ep) for (; (ep[0] = ep[1]); ep++); } /**/ static void convbase(char *s, long v, int base) { int digs = 0; unsigned long x; if (v < 0) *s++ = '-', v = -v; if (base <= 1) base = 10; if (base != 10) { sprintf(s, "%d#", base); s += strlen(s); } for (x = v; x; digs++) x /= base; if (!digs) digs = 1; s[digs--] = '\0'; x = v; while (digs >= 0) { int dig = x % base; s[digs--] = (dig < 10) ? '0' + dig : dig - 10 + 'A'; x /= base; } } /* Start a parameter scope */ /**/ void startparamscope(void) { locallevel++; } /* End a parameter scope: delete the parameters local to the scope. */ /**/ void endparamscope(void) { locallevel--; scanhashtable(paramtab, 0, 0, 0, scanendscope, 0); } /**/ static void scanendscope(HashNode hn, int flags) { Param pm = (Param)hn; if(pm->level > locallevel) unsetparam_pm(pm, 0, 0); }