Start development on BSD 2
[unix-history] / .ref-BSD-1 / ashell / sh_set.c
#include "sh.h"
/*
* Shell:
* "set" and associated routines
*
*----------
* doset - performs the logic of the set command
* operate - performs arithmetic function of the set command
* unset - undefines variables
* xfree - frees argument storage if it is dynamic
* savestr - salts away a copy of the argument string in a safe place
* putn - returns a pointer to a string representing the argument integer
* getn - returns the number which the string argument represents or 0
*----------
* value - returns the value of a variable which is argument
* adrof - returns a pointer to the structure for the variable argument
* set - sets the argument variable to the second argument value
*/
/*
* doset performs the logic of the set command.
* command syntax is
* set [ rOPvalue ] *
* current ops are += -= ++ -- &= |= *= /= %= and =
*
* Magic operator @ actually does an unset. Good for use conditionally!
*/
doset(v)
register char *v[];
{
register int *rp;
register char *p;
char *vp, c, op;
v++;
p = *v++;
if (p == 0) {
prvars();
return;
}
do {
if (digit(*p)) {
vp = p;
p++;
} else
for (vp = p; letter(*p); p++)
continue;
if (vp == p) {
bferr(": No variable");
return;
}
op = *p;
*p++ = 0;
switch (op) {
case 0:
p--;
case '=':
set(vp, savestr(p));
continue;
case '@':
if (*p != 0) {
bferr(": Garbage after @");
return;
}
unsetv(vp);
continue;
}
c = *p++;
if (c != '=') {
if (!any(op, "+-") || c != op || *p) {
bferr(": Missing =");
return;
}
*--p = '1';
}
set(vp, operate(op, vp, p));
} while (p = *v++);
}
operate(op, vp, p)
char op, *vp, *p;
{
register int vl, vr;
vl = getn(value(vp));
vr = getn(p);
switch (op & 0177) {
case '+':
vl =+ vr;
break;
case '-':
vl =- vr;
break;
case '&':
vl =& vr;
break;
case '|':
vl =| vr;
break;
case '/':
if (vr == 0)
bferr(": Divide check");
else
vl =/ vr;
break;
case '%':
if (vr == 0)
bferr(": Mod check");
else
vl =% vr;
break;
case '*':
vl =* vr;
break;
default:
bferr(": Bad operator");
}
return (putn(vl));
}
/*
* xfree frees possibly non-dynamic storage.
* It insures thats its argument is in the heap
* before freeing it.
*/
xfree(cp)
char *cp;
{
extern char end[];
cp = (cp + 1) &~ 1;
if (cp >= end && cp < &cp)
cfree(cp);
}
savestr(s)
char *s;
{
if (s == 0)
s = "";
return (strcpy(calloc(1, strlen(s) + 1), s));
}
/* static */char *putp;
/*
* putn takes an integer and returns a pointer to
* its string representation.
* putp indexes the number as it is formed.
*/
putn(n)
{
static char number[7];
/*
sprintf(number, "%d", n);
*/
putp = number;
if (n < 0) {
n = -n;
*putp++ = '-';
}
putn1(n);
*putp = 0;
return (savestr(number));
}
putn1(n)
int n;
{
if (n > 9)
putn1(n / 10);
*putp++ = n % 10 + '0';
}
/*
* getn is used by doset to get numbers from strings.
* null string is considered to be 0 (ala SNOBOL).
*/
getn(cp)
register char *cp;
{
register n;
int sign, base;
sign = 0;
base = 10;
if (*cp == '-') {
sign++;
cp++;
if (!digit(*cp))
goto badnum;
} else if (*cp == '0')
base = 8;
n = 0;
while (digit(*cp))
n = n * base + *cp++ - '0';
if (*cp)
goto badnum;
return (sign ? -n : n);
badnum:
bferr(": Badly formed number");
return (0);
}
/*
* value takes a string name of shell
* variable and returns a pointer to its value
*/
char *
value(var)
char *var;
{
return (value1(var, &shvhed));
}
char *
value1(var, head)
char *var;
struct shvar *head;
{
register struct shvar *vp;
vp = adrof1(var, head);
return (vp == 0 ? "" : vp->value);
}
/* static */ struct shvar *shprev;
/*
* adrof takes a variable name and returns
* a pointer to its structure or 0.
* A side effect is to make shprev point to the
* structure before this one for obvious reasons.
*/
struct shvar *
adrof(var)
char *var;
{
register struct shvar *vp;
if (digit(var[0])) {
vp = rgadrof(var[0]);
if (vp == 0) {
bferr(": Bad parameter");
vp = &shvhed;
}
return (vp);
}
return (adrof1(var, &shvhed));
}
struct shvar *
adrof1(var, head)
char *var;
struct shvar *head;
{
register struct shvar *vp;
int cmp;
shprev = head;
for (vp = shprev->next; vp != 0; vp = vp->next) {
cmp = strcmp(vp->name, var);
if (cmp == 0)
return (vp);
else if (cmp > 0)
return (0);
shprev = vp;
}
return (0);
}
/*
* set sets the variable argument to
* the given value.
* The caller is responsible for putting value
* in a safe place!
*/
set(var, value)
char *var, *value;
{
set1(var, value, &shvhed);
}
set1(var, value, head)
char *var, *value;
struct shvar *head;
{
register struct shvar *vp;
vp = adrof1(var, head);
if (vp == 0) {
vp = calloc(1, sizeof *vp);
vp->name = savestr(var);
vp->next = shprev->next;
shprev->next = vp;
}
if (value == 0)
value = "";
else
xfree(vp->value);
vp->value = value;
}
unset(v)
register char *v[];
{
unset1(v, &shvhed);
}
unset1(v, head)
register char *v[];
struct shvar *head;
{
register char *var;
v++;
while (var = *v++)
unsetv1(var, head);
}
unsetv(var)
char *var;
{
unsetv1(var, &shvhed);
}
unsetv1(var, head)
char *var;
struct shvar *head;
{
register struct shvar *vp;
vp = adrof1(var, head);
if (vp == 0) {
bferr2(var, ": Undefined");
return;
}
vp = shprev->next;
shprev->next = vp->next;
xfree(vp->value);
xfree(vp);
}