xref: /csrg-svn/old/adb/common_source/format.c (revision 36559)
1 #ifndef lint
2 static char sccsid[] = "@(#)format.c	5.1 (Berkeley) 01/16/89";
3 #endif
4 
5 /*
6  * adb - formats
7  */
8 
9 #include "defs.h"
10 #include <ctype.h>
11 
12 extern char BADMOD[];
13 extern char NOFORK[];
14 
15 /* symbol desirability in exform() */
16 enum { IFEXACT, ALWAYS, NEVER } wantsym;
17 
18 char	*exform();
19 
20 /*
21  * Execute the given format `ecount' times.
22  */
23 scanform(forcesym, fmt, space, ptype)
24 	int forcesym;
25 	char *fmt;
26 	int space, ptype;
27 {
28 	register char *p;
29 	register int c, n;
30 	register expr_t ntimes = ecount;
31 	addr_t savdot, newdot;
32 
33 	if (ntimes == 0)
34 		return;
35 	for (wantsym = forcesym ? ALWAYS : IFEXACT;; wantsym = IFEXACT) {
36 		p = fmt;
37 		savdot = dot;
38 		while (p != NULL) {	/* loop over format items */
39 			n = 0;		/* get optional count */
40 			while (isdigit(c = *p++))
41 				n = n * 10 + c - '0';
42 			if (c == 0)	/* end of format */
43 				break;
44 			p = exform(n ? n : 1, p - (c != '\\'), space, ptype);
45 		}
46 		dotinc = (newdot = dot) - savdot;
47 		dot = savdot;
48 		if (errflag != NULL && (long)ntimes < 0) {
49 			errflag = NULL;
50 			break;
51 		}
52 		checkerr();
53 		if (--ntimes == 0)
54 			break;
55 		dot = newdot;
56 	}
57 }
58 
59 /*
60  * Print a halfword or a word from dot.
61  */
62 showdot(fullword, space, ptype)
63 	int fullword, space, ptype;
64 {
65 	char c = fullword ? '4' : '2';
66 
67 	wantsym = NEVER;
68 	(void) exform(1, &c, space, ptype);
69 }
70 
71 /*
72  * The following are used inside exform().
73  *
74  * The various FT_ values specify the type of the object accessed
75  * by some format character.  FT_DULL indicates that no object is
76  * accessed (or that it is done in some peculiar way).
77  * The fsize array holds the size (in bytes)
78  * of each of those types; the fmttypes[] array lists the type for
79  * each character.  To save space, since there are many characters
80  * for some of the types, they are stored as strings.
81  */
82 enum { FT_DULL, FT_CHAR, FT_HW, FT_FW, FT_ADDR, FT_FLT, FT_DBL, FT_TM };
83 	/* these may have to be turned into `#define's */
84 
85 static char fsize[] = {		/* ordered by enumeration above! */
86 	0, sizeof(char), sizeof(hword_t), sizeof(expr_t),
87 	sizeof(addr_t), sizeof(float), sizeof(double), sizeof(time_t)
88 };
89 
90 static struct fmttypes {
91 	char	*ft_chars;
92 	int	ft_type;
93 } fmttypes[] = {
94 	{ "\t\" +-NRST^inrst", FT_DULL },
95 	{ "1BCbc", FT_CHAR },
96 	{ "2doquvxz", FT_HW },
97 	{ "4DOQUVXZ", FT_FW },
98 	{ "p", FT_ADDR },
99 	{ "f", FT_FLT },
100 	{ "F", FT_DBL },
101 	{ "Y", FT_TM },
102 	0
103 };
104 
105 /*
106  * Execute a single format item `fcount' times; set
107  * dotinc and move dot.  Return the address of the next
108  * format item, or NULL upon error reading an object.
109  *
110  * I must apologise for the length of this routine, but
111  * it is bloated mainly with type correctness.
112  */
113 char *
114 exform(fcount, fmt, space, ptype)
115 	int fcount;
116 	char *fmt;
117 	int space, ptype;
118 {
119 	register struct fmttypes *ftp;
120 	register int sz;
121 	register char *p, *s, fmtchar;
122 	addr_t savdot, off;
123 	struct nlist *sp;
124 	union {
125 		char c;
126 		hword_t hw;
127 		expr_t fw;
128 		float f;
129 		double d;
130 		time_t tm;
131 		addr_t a;
132 	} obj;
133 
134 	while (fcount > 0) {
135 		/*
136 		 * First decode the type to be used with the expression.
137 		 * If address, print dot as a symbol, save it in var 0,
138 		 * and bypass all the nonsense.
139 		 */
140 		p = fmt;
141 		fmtchar = *p++;
142 
143 		/* address: special */
144 		if (fmtchar == 'a') {
145 			pdot();
146 			wantsym = NEVER;	/* well, hardly ever */
147 			var[0] = dot;
148 			return (p);
149 		}
150 
151 		for (ftp = fmttypes; (s = ftp->ft_chars) != NULL; ftp++)
152 			while (*s != 0)
153 				if (*s++ == fmtchar)
154 					goto found;
155 		error(BADMOD);
156 		/* NOTREACHED */
157 found:
158 
159 		/* plop out a symbol, if desired */
160 		if (wantsym == ALWAYS)
161 			pdot();
162 		else if (wantsym == IFEXACT &&
163 		    (sp = findsym(dot, ptype, &off)) != NULL && off == 0)
164 			adbprintf("\n%s:%16t", sp->n_un.n_name); /* \n ??? */
165 		wantsym = NEVER;
166 
167 		/*
168 		 * Now read the sort of object we decided fmtchar represents,
169 		 * or compute it from the expression given for dot.
170 		 */
171 		sz = fsize[ftp->ft_type];
172 		if (space != SP_NONE) {
173 			/* can just read into the union */
174 			if (sz != 0)
175 				(void) adbread(space, dot, &obj, sz);
176 			else
177 				obj.fw = edot;
178 		} else {
179 			/* must decode type in order to assign, alas */
180 			switch (ftp->ft_type) {
181 
182 			case FT_CHAR:
183 				obj.c = edot;
184 				break;
185 
186 			case FT_HW:
187 				obj.hw = edot;
188 				break;
189 
190 			case FT_FW:
191 				obj.fw = edot;
192 				break;
193 
194 			case FT_DULL:
195 			case FT_ADDR:
196 				obj.a = dot;
197 				break;
198 
199 			case FT_FLT:
200 			case FT_DBL:
201 				obj.fw = 0;
202 				etofloat(edot, &obj.c, ftp->ft_type == FT_DBL);
203 				break;
204 
205 			case FT_TM:
206 				obj.fw = 0;
207 				obj.tm = edot;
208 				break;
209 
210 			default:
211 				panic("exform 1");
212 				/* NOTREACHED */
213 			}
214 		}
215 
216 		/* if we could not read the object, stop now. */
217 		if (errflag)
218 			return (NULL);
219 		if (mkfault)
220 			error((char *)NULL);
221 
222 		/*
223 		 * Now copy the value read (or assigned) to var[0].
224 		 * Here some of the types are collapsed: since the
225 		 * idea is to be able to get the value back later
226 		 * by reading var[0] and going through the type
227 		 * decoding above, it sometimes suffices to record
228 		 * as many bits as fit in an expr_t (see expr.c).
229 		 *
230 		 * Note that double precision numbers generally lose
231 		 * bits, since sizeof(double) can be > sizeof(expr_t).
232 		 */
233 		switch (ftp->ft_type) {
234 
235 		case FT_CHAR:
236 			var[0] = obj.c;
237 			break;
238 
239 		case FT_HW:
240 			var[0] = obj.hw;
241 			break;
242 
243 		case FT_FW:
244 		case FT_FLT:
245 		case FT_DBL:
246 		case FT_TM:
247 			var[0] = obj.fw;
248 			break;
249 
250 		case FT_DULL:
251 		case FT_ADDR:
252 			var[0] = obj.a;
253 			break;
254 
255 		default:
256 			panic("exform 2");
257 			/* NOTREACHED */
258 		}
259 
260 		/* set the size, if this object has a size */
261 		if (sz)
262 			dotinc = sz;
263 
264 		/* finally, do the command */
265 		if (charpos() == 0)
266 			adbprintf("%16m");
267 		switch (fmtchar) {
268 			/*
269 			 * Many of the formats translate to a %-8 or %-16
270 			 * edition of themselves; we use a single string,
271 			 * and modify the format part, for these.
272 			 */
273 			static char cfmt[] = "%-*?";
274 
275 		case ' ':
276 		case '\t':
277 			dotinc = 0;
278 			break;
279 
280 		case 't':
281 		case 'T':
282 			adbprintf("%*t", fcount);
283 			return (p);
284 
285 		case 'r':
286 		case 'R':
287 			adbprintf("%*m", fcount);
288 			return (p);
289 
290 		case 'p':
291 			psymoff("%R", obj.a, ptype, maxoff, "%16t");
292 			break;
293 
294 		case 'c':
295 			printc(obj.c);
296 			break;
297 
298 		case 'C':
299 			printesc(obj.c);
300 			break;
301 
302 		case 'b':
303 		case 'B':
304 			adbprintf("%-8O", (expr_t)(u_char)obj.c);
305 			break;
306 
307 		case 's':
308 		case 'S':
309 			savdot = dot;
310 			for (;;) {
311 				if (adbread(space, dot, &obj.c, 1) != 1 ||
312 				    iserr() || obj.c == 0)
313 					break;
314 				dot = inkdot(1);
315 				if (fmtchar == 'S')
316 					printesc(obj.c);
317 				else
318 					printc(obj.c);
319 				endline();
320 			}
321 			dotinc = dot - savdot + 1;
322 			dot = savdot;
323 			break;
324 
325 		case '1':
326 			adbprintf("%-8R", (expr_t)(u_char)obj.c);
327 			break;
328 
329 		case '2':
330 			fmtchar = 'r';
331 			/* FALLTHROUGH */
332 
333 		case 'v':
334 		case 'u': case 'd':
335 		case 'o': case 'q':
336 		case 'x': case 'z':
337 			cfmt[3] = fmtchar;
338 			adbprintf(cfmt, 8, obj.hw);
339 			break;
340 
341 		case '4':
342 			fmtchar = 'R';
343 			/* FALLTHROUGH */
344 
345 		case 'V':
346 		case 'U': case 'D':
347 		case 'O': case 'Q':
348 		case 'X': case 'Z':
349 			cfmt[3] = fmtchar;
350 			adbprintf(cfmt, 16, obj.fw);
351 			break;
352 
353 		case 'Y':
354 			adbprintf("%-24Y", obj.tm);
355 			break;
356 
357 		case 'i':
358 			printins(space);	/* also sets dotinc */
359 			printc('\n');
360 			break;
361 
362 		case 'f':
363 			s = checkfloat((caddr_t)&obj.f, 0);
364 			if (s != NULL)
365 				adbprintf("%-16s", s);
366 			else
367 				adbprintf("%-16.9f", obj.f);
368 			break;
369 
370 		case 'F':
371 			s = checkfloat((caddr_t)&obj.d, 1);
372 			if (s != NULL)
373 				adbprintf("%-32s", s);
374 			else
375 				adbprintf("%-32.18f", obj.d);
376 			break;
377 
378 		case 'n':
379 		case 'N':
380 			printc('\n');
381 			dotinc = 0;
382 			break;
383 
384 		case '"':
385 			while (*p != 0 && *p != '"')
386 				printc(*p++);
387 			if (*p)
388 				p++;
389 			dotinc = 0;
390 			break;
391 
392 		case '^':
393 			dot = inkdot(-dotinc * fcount);
394 			return (p);
395 
396 		case '+':
397 			dot = inkdot(fcount);
398 			return (p);
399 
400 		case '-':
401 			dot = inkdot(-fcount);
402 			return (p);
403 
404 		default:
405 			panic("exform 3");
406 			/* NOTREACHED */
407 		}
408 		if (space != SP_NONE)
409 			dot = inkdot(dotinc);
410 		fcount--;
411 		endline();
412 	}
413 	return (p);
414 }
415 
416 /*
417  * Print dot in its canonical format.
418  */
419 pdot()
420 {
421 
422 	psymoff("%R", dot, SP_INSTR, maxoff, ":%16t");
423 }
424 
425 /*
426  * Print character c using ASCII escape conventions.
427  */
428 printesc(c)
429 	register int c;
430 
431 {
432 
433 	c &= 0177;				/* XXX */
434 	if (isprint(c))
435 		printc(c);
436 	else
437 		adbprintf("^%c", c ^ '@');
438 }
439