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