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