This is params.c in view mode; [Download] [Up]
/*
* $Id: params.c,v 2.41 1996/10/15 20:16:35 hzoli Exp $
*
* params.c - parameters
*
* This file is part of zsh, the Z shell.
*
* Copyright (c) 1992-1996 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.h"
static Param argvparam;
/* 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->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;
#ifdef ZSH_HASH_DEBUG
paramtab->printinfo = printhashtabinfo;
paramtab->tablename = ztrdup("paramtab");
#endif
/* 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 {
int allexp = opts[ALLEXPORT];
opts[ALLEXPORT] = 0;
/* 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 = ztrdup(*envp2);
str = iname + (str - *envp2);
*str = '\0';
if (!idigit(*iname) && isident(iname) && !strchr(iname, '[') &&
!((pm = (Param) paramtab->getnode(paramtab, iname)) &&
(pm->flags & (PM_DONTIMPORT | PM_EXPORTED))) &&
(pm = setsparam(iname, metafy(str + 1, -1, META_DUP)))) {
*str = '=';
pm->flags |= PM_EXPORTED;
if (pm->flags & PM_SPECIAL) {
zsfree(iname);
iname = mkenvstr(pm->nam, getsparam(pm->nam));
}
pm->env = *envp++ = iname;
*envp = NULL;
} else
zsfree(iname);
}
}
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, "PWD");
if (!(pm->flags & PM_EXPORTED)) {
pm->flags |= PM_EXPORTED;
pm->env = addenv("PWD", pwd);
}
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 */
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++)); );
opts[ALLEXPORT] = allexp;
} LASTALLOC;
noerrs = 0;
}
/* Create a new parameter node */
/**/
Param
createparam(char *name, int flags)
{
Param pm, oldpm, altpm;
int spec;
if (name != nulstring) {
oldpm = (Param) paramtab->getnode(paramtab, name);
spec = oldpm && (oldpm->flags & PM_SPECIAL);
if ((oldpm && oldpm->level == locallevel) || spec) {
if (oldpm && !(oldpm->flags & PM_UNSET))
return NULL;
pm = oldpm;
pm->ct = 0;
oldpm = pm->old;
pm->flags = (flags & (PM_EXPORTED | PM_LEFT | PM_RIGHT_B |
PM_RIGHT_Z | PM_LOWER | PM_UPPER |
PM_READONLY | PM_TAGGED | PM_UNIQUE)) |
(pm->flags & (PM_SCALAR | PM_INTEGER | PM_ARRAY | PM_SPECIAL));
if (pm->ename &&
(altpm = (Param) paramtab->getnode(paramtab, pm->ename))) {
altpm->flags &= ~(PM_UNSET | PM_UNIQUE | PM_UPPER | PM_LEFT |
PM_RIGHT_B | PM_RIGHT_Z | PM_LOWER |
PM_READONLY | PM_TAGGED | PM_EXPORTED);
}
} 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)
pm->flags |= PM_EXPORTED;
} else {
pm = (Param) alloc(sizeof *pm);
spec = 0;
}
if (!spec) {
pm->flags = flags;
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;
#ifdef DEBUG
default:
DPUTS(1, "oops, tried to create param node without valid flag");
break;
#endif
}
}
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;
}
char **garr;
/**/
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, "oops, 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));
}
/**/
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;
}
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);
}
}
/**/
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;
}
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;
}
}
/**/
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 (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);
}
/* Unset a parameter */
/**/
void
unsetparam_pm(Param pm, int altflag)
{
Param oldpm, altpm;
int spec;
if ((pm->flags & PM_READONLY) && pm->level <= locallevel) {
zerr("read-only variable: %s", pm->nam, 0);
return;
}
spec = (pm->flags & PM_SPECIAL) && !pm->level;
switch (PM_TYPE(pm->flags)) {
case PM_SCALAR:
(pm->sets.cfn) (pm, NULL);
break;
case PM_ARRAY:
(pm->sets.afn) (pm, NULL);
break;
}
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);
unsetparam_pm(altpm, 1);
}
if ((locallevel && locallevel == pm->level) || spec) {
pm->flags |= PM_UNSET;
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 */
}
/* Function to get value of an integer parameter */
/**/
long
intgetfn(Param pm)
{
return pm->u.val;
}
/* Function to set value of an integer parameter */
/**/
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 */
/**/
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 */
/**/
char **
arrgetfn(Param pm)
{
static char *nullarray = NULL;
return pm->u.arr ? pm->u.arr : &nullarray;
}
/* Function to set value of an array parameter */
/**/
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->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->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)
{
long *p = (long *)pm->data;
*p = x;
if (p == &lines || p == &columns)
adjustwinsize(2 + (p == &columns));
}
/* 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->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->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->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->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->data, ':');
}
/**/
void
colonarrsetfn(Param pm, char *x)
{
char ***dptr = (char ***)pm->data;
freearray(*dptr);
*dptr = x ? colonsplit(x, pm->flags & PM_UNIQUE) : mkarray(NULL);
zsfree(x);
if (pm->ename)
arrfixenv(pm->nam, *dptr);
}
/**/
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)
{
#ifdef HAVE_SETUID
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 = x;
cached_uid = pswd->pw_uid;
return;
}
}
zsfree(x);
#endif
}
/* 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}
};
/**/
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)
{
strsetfn(pm, x);
if (getsparam("LC_ALL"))
return;
if (!x)
x = getsparam("LANG");
setlocale((int) pm->data, 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 `-' */
/**/
char *
dashgetfn(Param pm)
{
static char buf[63];
char *val = buf;
int optno;
for(optno = 1; optno < OPT_SIZE; optno++)
if(optid(optns[optno]) &&
opts[optno] == !(optid(optns[optno]) & OPT_REV))
*val++ = optid(optns[optno]) & ~OPT_REV;
*val = '\0';
return buf;
}
/* 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. */
/**/
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);
if (isset(ALLEXPORT))
pm->flags |= PM_EXPORTED;
if (pm->flags & PM_EXPORTED) {
for (ep = environ; *ep; ep++)
if (!strncmp(*ep, s, len_s) && (*ep)[len_s] == '=') {
pm->env = replenv(*ep, u);
return;
}
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". */
/**/
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++);
}
/**/
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;
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.