4.4BSD/usr/src/old/adb/common_source/command.c

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

/*-
 * Copyright (c) 1991 The Regents of the University of California.
 * All rights reserved.
 *
 * This module is believed to contain source code proprietary to AT&T.
 * Use and redistribution is subject to the Berkeley Software License
 * Agreement and your Software Agreement with AT&T (Western Electric).
 */

#ifndef lint
static char sccsid[] = "@(#)command.c	5.5 (Berkeley) 4/4/91";
#endif /* not lint */

/*
 * adb - commands
 */

#include "defs.h"
#include <ctype.h>
#include <sys/wait.h>
#include <paths.h>

extern char BADEQ[];		/* "unexpected `='" */
extern char NOMATCH[];		/* "cannot locate value" */
extern char BADVAR[];		/* "bad variable" */
extern char BADCOM[];		/* "bad command" */
extern char NOFORK[];		/* "try again" */

/*
 * executing is used in main() to see if it is necessary to
 * delete any breakpoints that might have been set; if an
 * error occurs while a subprocess command is running, executing
 * will be set.
 */
int	executing;

/* lastcom remembers the previous command */
static struct {
	int	c;		/* the command */
	int	star;		/* true iff it was in alternate space */
} lastcom;

/*
 * Execute the given command buffer.
 * If defcom is nonzero, it is used as the default command.
 */
command(buf, defcom)
	char *buf;
	int defcom;
{

	lp = buf;
	do {
		cmds(defcom);
		flushbuf();
	} while (rdc() == ';');
	unreadc();
}

static
cmds(defcom)
	int defcom;
{
	int c;
	struct reglist *reg;

	/*
	 * Pick up the optional first expression (`dot'),
	 * then, if the next character is a comma, pick up
	 * the second optional expression (`ecount').
	 */
	if (gavedot = oexpr())
		ditto = dot = edot = expv;
	else
		edot = dot;	/* probably equal, but possibly truncating */
	if (rdc() == ',') {
		if (!oexpr())
			error("count expected");
		gavecount = 1;
		ecount = expv;
	} else {
		gavecount = 0;
		ecount = 1;
		unreadc();
	}

	/*
	 * Pick up the command.  If there is no command, do the
	 * previous (or default) command, and if no dot was given,
	 * use the `next' dot.
	 */
	c = rdc();
	if (eol(c)) {
		if (defcom != 0) {
			lastcom.c = defcom;
			lastcom.star = 0;
		}
		if (!gavedot)
			dot = inkdot(dotinc);
		unreadc();
	} else {
		lastcom.c = c;
		lastcom.star = 0;
	}

	switch (lastcom.c) {

	case '=':
		fmtcom(SP_NONE, 1);
		break;

	case '/':
		fmtcom(SP_DATA, 0);
		break;

	case '?':
		fmtcom(SP_INSTR, 0);
		break;

	case '>':
		lastcom.c = 0;
		if ((reg = reglookup()) != NULL) {
			if (setreg(reg, edot))
				prints("register write failed");
			break;
		}
		if ((c = varlookup(rdc())) != -1)
			var[c] = edot;
		else
			error(BADVAR);
		break;

	case '!':
		lastcom.c = 0;
		shell();
		break;

	case '$':
		lastcom.c = 0;
		printtrace(nextchar());
		break;

	case ':':
		if (!executing) {
			executing = 1;
			subpcs(nextchar());
			executing = 0;
			lastcom.c = 0;
		}
		break;

	case 0:
		prints("adb\n");
		break;

	default:
		error(BADCOM);
		/* NOTREACHED */
	}
}

/*
 * Perform a format-based command (one in ? / or =).
 */
static
fmtcom(space, eqcom)
	int space, eqcom;
{
	/* special commands m, lL, wW do not operate in SP_NONE (`=') */
	void mcom(), lcom(), wcom();
	static struct fcmd {
		int	c;
		void	(*fn)();
	} fcmd[] = {
		{ 'm', mcom },
		{ 'l', lcom }, { 'L', lcom },
		{ 'w', wcom }, { 'W', wcom },
		0
	};
	register struct fcmd *f;
	register int c;
	int ptype = space;
	static char stformat[LINELEN] = "X\"= \"^i";
	static char eqformat[LINELEN] = "z";

	/*
	 * Are we operating in the alternate `star' space?
	 */
	if (!eqcom) {
		if (rdc() == '*')
			lastcom.star = 1;
		else
			unreadc();
		if (lastcom.star) {
			space |= SP_STAR;
			/* print as data for instr, and vice versa */
			ptype = (SP_DATA + SP_INSTR) - ptype;
		}
	}

	/*
	 * Check for the special commands first.
	 */
	c = rdc();
	for (f = fcmd; f->c; f++) {
		if (c == f->c) {
			if (eqcom)
				error(BADEQ);
			(*f->fn)(space, ptype, isupper(c));
			return;
		}
	}
	unreadc();
	getformat(eqcom ? eqformat : stformat, LINELEN);
	scanform(!eqcom, eqcom ? eqformat : stformat, space, ptype);
}

/*
 * Set a map (?m, /m commands).
 */
/* ARGSUSED */
static void
mcom(space, ptype, fullword)
	int space, ptype, fullword;
{
	register struct map *smap;
	register struct m1 *mm;
	char c;

	smap = space & SP_DATA ? &datmap : &txtmap;
	mm = space & SP_STAR ? &smap->m2 : &smap->m1;
	if (oexpr()) {
		mm->b = expv;
		if (oexpr()) {
			mm->e = expv;
			if (oexpr())
				mm->f = expv;
		}
	}
	if ((c = rdc()) == '?')
		smap->ufd = symfile.fd;
	else if (c == '/')
		smap->ufd = corefile.fd;
	else
		unreadc();
}

/*
 * Locate a value (l, L commands).
 */
static void
lcom(space, ptype, fullword)
	int space, ptype, fullword;
{
	register expr_t val, mask;
	addr_t savdot;

	/* search for exp */
	savdot = dot;
	val = rexpr();
	if (oexpr())
		mask = expv;
	else
		mask = ~0L;
	if (fullword) {
		expr_t w;

		dotinc = sizeof(w);
		for (;;) {
			(void) adbread(space, dot, &w, sizeof(w));
			if (iserr() || (w & mask) == val)
				break;
			dot = inkdot(sizeof(w));
		}
	} else {
		hword_t hw;

		dotinc = sizeof(hw);
		mask = (hword_t)mask;
		val = (hword_t)val;
		for (;;) {
			(void) adbread(space, dot, &hw, sizeof(hw));
			if (iserr() || (hw & mask) == val)
				break;
			dot = inkdot(sizeof(hw));
		}
	}
	if (iserr()) {
		dot = savdot;
		errflag = NOMATCH;
	}
	psymoff("%R", dot, ptype, maxoff, "");
}

/*
 * Write new values (w, W).
 */
static void
wcom(space, ptype, fullword)
	int space, ptype, fullword;
{
	addr_t savdot;
	hword_t hw;

	(void) rexpr();
	do {
		savdot = dot;
		pdot();
		showdot(fullword, space, ptype);	/* also advances */
		errflag = NULL;
		dot = savdot;
		if (fullword)
			(void) adbwrite(space, dot, &expv, sizeof(expv));
		else {
			hw = expv;
			(void) adbwrite(space, dot, &hw, sizeof(hw));
		}
		savdot = dot;
		adbprintf("=%8t");
		showdot(fullword, space, ptype);
		printc('\n');
	} while (oexpr() && !iserr());
	dot = savdot;
	checkerr();
}

/*
 * Do a shell escape.
 *
 * THE vfork CODE BELOW IS CURRENTLY BROKEN
 * MUST CHANGE signal TO sigvec BELOW
 */
static
shell()
{
	int rc, unixpid;
	union wait status;
	char *argp = lp;
	char *getenv(), *eshell = getenv("SHELL");

	if (eshell == 0)
		eshell = _PATH_BSHELL;
	while (readchar() != '\n')
		/* void */;
#ifndef VFORK
#define vfork fork
#endif
	if ((unixpid = vfork()) == 0) {
		*lp = 0;
		(void) signal(SIGINT, sigint);
		(void) signal(SIGQUIT, sigquit);
		execl(eshell, "sh", "-c", argp, (char *)NULL);
		_exit(16);
		/* NOTREACHED */
	}
#ifdef VFORK
	*lp = '\n';
#endif
	if (unixpid == -1)
		error(NOFORK);
	(void) signal(SIGINT, SIG_IGN);
	while ((rc = wait(&status)) != unixpid && rc != -1)
		/* void */;
	(void) signal(SIGINT, intcatch);
	prints("!");
	unreadc();
}

/*
 * Read a format into the given buffer.  If nothing is
 * read, leave the buffer alone.
 */
static
getformat(buf, n)
	char *buf;
	register int n;
{
	register char *p = buf;
	register int c, quote = 0;

	while ((c = readchar()), quote ? c != '\n' : !eol(c)) {
		if (c == '"')
			quote = !quote;
		if (--n > 0)
			*p++ = c;
	}
	unreadc();
	if (p != buf)		/* nonempty */
		*p++ = 0;
}

/*
 * Convert a (one-character) variable name to an index, or -1 for
 * error.
 */
varlookup(name)
	register int name;
{

	if (isdigit(name))
		return (name - '0');
	if (isalpha(name))
		return (isupper(name) ? name - 'A' + 10 : name - 'a' + 10);
	return (-1);
}

/* 
 * If the text at the current input point matches a register name,
 * consume that text and return a pointer to the register; otherwise
 * leave it unconsumed and return NULL.
 */
struct reglist *
reglookup()
{
	register struct reglist *p;
	register char *a, *b, c0, c1;
	char *oldlp = lp;
	extern struct reglist reglist[];

	c0 = rdc();
	c1 = readchar();
	for (p = reglist; (a = p->r_name) != NULL; p++) {
		if (*a++ != c0 || *a++ != c1)
			continue;
		b = lp;
		do {
			if (*a == 0) {	/* name matched: stop short */
				lp = b;
				return (p);
			}
		} while (*a++ == *b++);
	}
	lp = oldlp;
	return (NULL);
}