4.4BSD/usr/src/old/adb/common_source/format.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[] = "@(#)format.c	5.4 (Berkeley) 4/4/91";
#endif /* not lint */

/*
 * adb - formats
 */

#include "defs.h"
#include <ctype.h>
#include <vis.h>

extern char BADMOD[];
extern char NOFORK[];

/* symbol desirability in exform() */
enum { IFEXACT, ALWAYS, NEVER } wantsym;

char	*exform();

/*
 * Execute the given format `ecount' times.
 */
scanform(forcesym, fmt, space, ptype)
	int forcesym;
	char *fmt;
	int space, ptype;
{
	register char *p;
	register int c, n;
	register expr_t ntimes = ecount;
	addr_t savdot, newdot;

	if (ntimes == 0)
		return;
	for (wantsym = forcesym ? ALWAYS : IFEXACT;; wantsym = IFEXACT) {
		p = fmt;
		savdot = dot;
		while (p != NULL) {	/* loop over format items */
			n = 0;		/* get optional count */
			while (isdigit(c = *p++))
				n = n * 10 + c - '0';
			if (c == 0)	/* end of format */
				break;
			p = exform(n ? n : 1, p - (c != '\\'), space, ptype);
		}
		dotinc = (newdot = dot) - savdot;
		dot = savdot;
		if (errflag != NULL && (long)ntimes < 0) {
			errflag = NULL;
			break;
		}
		checkerr();
		if (--ntimes == 0)
			break;
		dot = newdot;
	}
}

/*
 * Print a halfword or a word from dot.
 */
showdot(fullword, space, ptype)
	int fullword, space, ptype;
{
	char c = fullword ? '4' : '2';

	wantsym = NEVER;
	(void) exform(1, &c, space, ptype);
}

/*
 * The following are used inside exform().
 *
 * The various FT_ values specify the type of the object accessed
 * by some format character.  FT_DULL indicates that no object is
 * accessed (or that it is done in some peculiar way).
 * The fsize array holds the size (in bytes)
 * of each of those types; the fmttypes[] array lists the type for
 * each character.  To save space, since there are many characters
 * for some of the types, they are stored as strings.
 */
enum { FT_DULL, FT_CHAR, FT_HW, FT_FW, FT_ADDR, FT_FLT, FT_DBL, FT_TM };
	/* these may have to be turned into `#define's */

static char fsize[] = {		/* ordered by enumeration above! */
	0, sizeof(char), sizeof(hword_t), sizeof(expr_t),
	sizeof(addr_t), sizeof(float), sizeof(double), sizeof(time_t)
};

static struct fmttypes {
	char	*ft_chars;
	int	ft_type;
} fmttypes[] = {
	{ "\t\" +-NRST^inrst", FT_DULL },
	{ "1BCbc", FT_CHAR },
	{ "2doquvxz", FT_HW },
	{ "4DOQUVXZ", FT_FW },
	{ "p", FT_ADDR },
	{ "f", FT_FLT },
	{ "F", FT_DBL },
	{ "Y", FT_TM },
	0
};

/*
 * Execute a single format item `fcount' times; set
 * dotinc and move dot.  Return the address of the next
 * format item, or NULL upon error reading an object.
 *
 * I must apologise for the length of this routine, but
 * it is bloated mainly with type correctness.
 */
char *
exform(fcount, fmt, space, ptype)
	int fcount;
	char *fmt;
	int space, ptype;
{
	register struct fmttypes *ftp;
	register int sz;
	register char *p, *s, fmtchar;
	addr_t savdot, off;
	struct nlist *sp;
	union {
		char c;
		hword_t hw;
		expr_t fw;
		float f;
		double d;
		time_t tm;
		addr_t a;
	} obj;

	while (fcount > 0) {
		/*
		 * First decode the type to be used with the expression.
		 * If address, print dot as a symbol, save it in var 0,
		 * and bypass all the nonsense.
		 */
		p = fmt;
		fmtchar = *p++;

		/* address: special */
		if (fmtchar == 'a') {
			pdot();
			wantsym = NEVER;	/* well, hardly ever */
			var[0] = dot;
			return (p);
		}

		for (ftp = fmttypes; (s = ftp->ft_chars) != NULL; ftp++)
			while (*s != 0)
				if (*s++ == fmtchar)
					goto found;
		error(BADMOD);
		/* NOTREACHED */
found:

		/* plop out a symbol, if desired */
		if (wantsym == ALWAYS)
			pdot();
		else if (wantsym == IFEXACT &&
		    (sp = findsym(dot, ptype, &off)) != NULL && off == 0)
			adbprintf("\n%s:%16t", sp->n_un.n_name); /* \n ??? */
		wantsym = NEVER;

		/*
		 * Now read the sort of object we decided fmtchar represents,
		 * or compute it from the expression given for dot.
		 */
		sz = fsize[ftp->ft_type];
		if (space != SP_NONE) {
			/* can just read into the union */
			if (sz != 0)
				(void) adbread(space, dot, &obj, sz);
			else
				obj.fw = edot;
		} else {
			/* must decode type in order to assign, alas */
			switch (ftp->ft_type) {

			case FT_CHAR:
				obj.c = edot;
				break;

			case FT_HW:
				obj.hw = edot;
				break;

			case FT_FW:
				obj.fw = edot;
				break;

			case FT_DULL:
			case FT_ADDR:
				obj.a = dot;
				break;

			case FT_FLT:
			case FT_DBL:
				obj.fw = 0;
				etofloat(edot, &obj.c, ftp->ft_type == FT_DBL);
				break;

			case FT_TM:
				obj.fw = 0;
				obj.tm = edot;
				break;

			default:
				panic("exform 1");
				/* NOTREACHED */
			}
		}

		/* if we could not read the object, stop now. */
		if (errflag)
			return (NULL);
		if (mkfault)
			error((char *)NULL);

		/*
		 * Now copy the value read (or assigned) to var[0].
		 * Here some of the types are collapsed: since the
		 * idea is to be able to get the value back later
		 * by reading var[0] and going through the type
		 * decoding above, it sometimes suffices to record
		 * as many bits as fit in an expr_t (see expr.c).
		 *
		 * Note that double precision numbers generally lose
		 * bits, since sizeof(double) can be > sizeof(expr_t).
		 */
		switch (ftp->ft_type) {

		case FT_CHAR:
			var[0] = obj.c;
			break;

		case FT_HW:
			var[0] = obj.hw;
			break;

		case FT_FW:
		case FT_FLT:
		case FT_DBL:
		case FT_TM:
			var[0] = obj.fw;
			break;

		case FT_DULL:
		case FT_ADDR:
			var[0] = obj.a;
			break;

		default:
			panic("exform 2");
			/* NOTREACHED */
		}

		/* set the size, if this object has a size */
		if (sz)
			dotinc = sz;

		/* finally, do the command */
		if (charpos() == 0)
			adbprintf("%16m");
		switch (fmtchar) {
			/*
			 * Many of the formats translate to a %-8 or %-16
			 * edition of themselves; we use a single string,
			 * and modify the format part, for these.
			 */
			static char cfmt[] = "%-*?";

		case ' ':
		case '\t':
			dotinc = 0;
			break;

		case 't':
		case 'T':
			adbprintf("%*t", fcount);
			return (p);

		case 'r':
		case 'R':
			adbprintf("%*m", fcount);
			return (p);

		case 'p':
			psymoff("%R", obj.a, ptype, maxoff, "%16t");
			break;

		case 'c':
			printc(obj.c);
			break;

		case 'C':
			printesc(obj.c);
			break;

		case 'b':
		case 'B':
			adbprintf("%-8O", (expr_t)(u_char)obj.c);
			break;

		case 's':
		case 'S':
			savdot = dot;
			for (;;) {
				if (adbread(space, dot, &obj.c, 1) != 1 ||
				    iserr() || obj.c == 0)
					break;
				dot = inkdot(1);
				if (fmtchar == 'S')
					printesc(obj.c);
				else
					printc(obj.c);
				endline();
			}
			dotinc = dot - savdot + 1;
			dot = savdot;
			break;

		case '1':
			adbprintf("%-8R", (expr_t)(u_char)obj.c);
			break;

		case '2':
			fmtchar = 'r';
			/* FALLTHROUGH */

		case 'v':
		case 'u': case 'd':
		case 'o': case 'q':
		case 'x': case 'z':
			cfmt[3] = fmtchar;
			adbprintf(cfmt, 8, obj.hw);
			break;

		case '4':
			fmtchar = 'R';
			/* FALLTHROUGH */

		case 'V':
		case 'U': case 'D':
		case 'O': case 'Q':
		case 'X': case 'Z':
			cfmt[3] = fmtchar;
			adbprintf(cfmt, 16, obj.fw);
			break;

		case 'Y':
			adbprintf("%-24Y", obj.tm);
			break;

		case 'i':
			printins(space);	/* also sets dotinc */
			printc('\n');
			break;

		case 'f':
			s = checkfloat((caddr_t)&obj.f, 0);
			if (s != NULL)
				adbprintf("%-16s", s);
			else
				adbprintf("%-16.9f", obj.f);
			break;

		case 'F':
			s = checkfloat((caddr_t)&obj.d, 1);
			if (s != NULL)
				adbprintf("%-32s", s);
			else
				adbprintf("%-32.18f", obj.d);
			break;

		case 'n':
		case 'N':
			printc('\n');
			dotinc = 0;
			break;

		case '"':
			while (*p != 0 && *p != '"')
				printc(*p++);
			if (*p)
				p++;
			dotinc = 0;
			break;

		case '^':
			dot = inkdot(-dotinc * fcount);
			return (p);

		case '+':
			dot = inkdot(fcount);
			return (p);

		case '-':
			dot = inkdot(-fcount);
			return (p);

		default:
			panic("exform 3");
			/* NOTREACHED */
		}
		if (space != SP_NONE)
			dot = inkdot(dotinc);
		fcount--;
		endline();
	}
	return (p);
}

/*
 * Print dot in its canonical format.
 */
pdot()
{

	psymoff("%R", dot, SP_INSTR, maxoff, ":%16t");
}

/*
 * Print character c using ASCII escape conventions.
 */
printesc(c)
	register int c;

{
	char visbuf[5];

	vis(visbuf, (char)c, VIS_TAB | VIS_NL | VIS_NOSLASH, 0);
	adbprintf("%s", visbuf);
}