1BSD/ashell/sh_set.c

Compare this file to the similar file:
Show the results in this format:

#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);
}