xref: /netbsd-src/sys/ddb/db_output.c (revision 81b108b45f75f89f1e3ffad9fb6f074e771c0935)
1 /*	$NetBSD: db_output.c,v 1.13 1996/04/01 17:27:14 christos Exp $	*/
2 
3 /*
4  * Mach Operating System
5  * Copyright (c) 1991,1990 Carnegie Mellon University
6  * All Rights Reserved.
7  *
8  * Permission to use, copy, modify and distribute this software and its
9  * documentation is hereby granted, provided that both the copyright
10  * notice and this permission notice appear in all copies of the
11  * software, derivative works or modified versions, and any portions
12  * thereof, and that both notices appear in supporting documentation.
13  *
14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17  *
18  * Carnegie Mellon requests users of this software to return to
19  *
20  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
21  *  School of Computer Science
22  *  Carnegie Mellon University
23  *  Pittsburgh PA 15213-3890
24  *
25  * any improvements or extensions that they make and grant Carnegie the
26  * rights to redistribute these changes.
27  */
28 
29 /*
30  * Printf and character output for debugger.
31  */
32 #include <sys/param.h>
33 
34 #include <machine/stdarg.h>
35 
36 #include <dev/cons.h>
37 
38 #include <machine/db_machdep.h>
39 
40 #include <ddb/db_command.h>
41 #include <ddb/db_output.h>
42 #include <ddb/db_interface.h>
43 #include <ddb/db_sym.h>
44 #include <ddb/db_extern.h>
45 
46 /*
47  *	Character output - tracks position in line.
48  *	To do this correctly, we should know how wide
49  *	the output device is - then we could zero
50  *	the line position when the output device wraps
51  *	around to the start of the next line.
52  *
53  *	Instead, we count the number of spaces printed
54  *	since the last printing character so that we
55  *	don't print trailing spaces.  This avoids most
56  *	of the wraparounds.
57  */
58 
59 #ifndef	DB_MAX_LINE
60 #define	DB_MAX_LINE		24	/* maximum line */
61 #define DB_MAX_WIDTH		80	/* maximum width */
62 #endif	DB_MAX_LINE
63 
64 #define DB_MIN_MAX_WIDTH	20	/* minimum max width */
65 #define DB_MIN_MAX_LINE		3	/* minimum max line */
66 #define CTRL(c)			((c) & 0xff)
67 
68 int	db_output_position = 0;		/* output column */
69 int	db_output_line = 0;		/* output line number */
70 int	db_last_non_space = 0;		/* last non-space character */
71 int	db_tab_stop_width = 8;		/* how wide are tab stops? */
72 #define	NEXT_TAB(i) \
73 	((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width)
74 int	db_max_line = DB_MAX_LINE;	/* output max lines */
75 int	db_max_width = DB_MAX_WIDTH;	/* output line width */
76 
77 static void db_more __P((void));
78 static char *db_ksprintn __P((u_long, int, int *));
79 static void db_printf_guts __P((const char *, va_list));
80 
81 /*
82  * Force pending whitespace.
83  */
84 void
85 db_force_whitespace()
86 {
87 	register int last_print, next_tab;
88 
89 	last_print = db_last_non_space;
90 	while (last_print < db_output_position) {
91 	    next_tab = NEXT_TAB(last_print);
92 	    if (next_tab <= db_output_position) {
93 		while (last_print < next_tab) { /* DON'T send a tab!!! */
94 			cnputc(' ');
95 			last_print++;
96 		}
97 	    }
98 	    else {
99 		cnputc(' ');
100 		last_print++;
101 	    }
102 	}
103 	db_last_non_space = db_output_position;
104 }
105 
106 static void
107 db_more()
108 {
109 	register  char *p;
110 	int quit_output = 0;
111 
112 	for (p = "--db_more--"; *p; p++)
113 	    cnputc(*p);
114 	switch(cngetc()) {
115 	case ' ':
116 	    db_output_line = 0;
117 	    break;
118 	case 'q':
119 	case CTRL('c'):
120 	    db_output_line = 0;
121 	    quit_output = 1;
122 	    break;
123 	default:
124 	    db_output_line--;
125 	    break;
126 	}
127 	p = "\b\b\b\b\b\b\b\b\b\b\b           \b\b\b\b\b\b\b\b\b\b\b";
128 	while (*p)
129 	    cnputc(*p++);
130 	if (quit_output) {
131 	    db_error(0);
132 	    /* NOTREACHED */
133 	}
134 }
135 
136 /*
137  * Output character.  Buffer whitespace.
138  */
139 void
140 db_putchar(c)
141 	int	c;		/* character to output */
142 {
143 	if (db_max_line >= DB_MIN_MAX_LINE && db_output_line >= db_max_line-1)
144 	    db_more();
145 	if (c > ' ' && c <= '~') {
146 	    /*
147 	     * Printing character.
148 	     * If we have spaces to print, print them first.
149 	     * Use tabs if possible.
150 	     */
151 	    db_force_whitespace();
152 	    cnputc(c);
153 	    db_output_position++;
154 	    if (db_max_width >= DB_MIN_MAX_WIDTH
155 		&& db_output_position >= db_max_width-1) {
156 		/* auto new line */
157 		cnputc('\n');
158 		db_output_position = 0;
159 		db_last_non_space = 0;
160 		db_output_line++;
161 	    }
162 	    db_last_non_space = db_output_position;
163 	}
164 	else if (c == '\n') {
165 	    /* Return */
166 	    cnputc(c);
167 	    db_output_position = 0;
168 	    db_last_non_space = 0;
169 	    db_output_line++;
170 	    db_check_interrupt();
171 	}
172 	else if (c == '\t') {
173 	    /* assume tabs every 8 positions */
174 	    db_output_position = NEXT_TAB(db_output_position);
175 	}
176 	else if (c == ' ') {
177 	    /* space */
178 	    db_output_position++;
179 	}
180 	else if (c == '\007') {
181 	    /* bell */
182 	    cnputc(c);
183 	}
184 	/* other characters are assumed non-printing */
185 }
186 
187 /*
188  * Return output position
189  */
190 int
191 db_print_position()
192 {
193 	return (db_output_position);
194 }
195 
196 /*
197  * Printing
198  */
199 extern int	db_radix;
200 
201 /*VARARGS1*/
202 void
203 #if __STDC__
204 db_printf(const char *fmt, ...)
205 #else
206 db_printf(fmt, va_alist)
207 	const char *fmt;
208 	va_dcl
209 #endif
210 {
211 	va_list	listp;
212 	va_start(listp, fmt);
213 	db_printf_guts (fmt, listp);
214 	va_end(listp);
215 }
216 
217 /* alternate name */
218 
219 /*VARARGS1*/
220 void
221 #if __STDC__
222 kdbprintf(const char *fmt, ...)
223 #else
224 kdbprintf(fmt, va_alist)
225 	char *fmt;
226 	va_dcl
227 #endif
228 {
229 	va_list	listp;
230 	va_start(listp, fmt);
231 	db_printf_guts (fmt, listp);
232 	va_end(listp);
233 }
234 
235 /*
236  * End line if too long.
237  */
238 void
239 db_end_line()
240 {
241 	if (db_output_position >= db_max_width)
242 	    db_printf("\n");
243 }
244 
245 /*
246  * Put a number (base <= 16) in a buffer in reverse order; return an
247  * optional length and a pointer to the NULL terminated (preceded?)
248  * buffer.
249  */
250 static char *
251 db_ksprintn(ul, base, lenp)
252 	register u_long ul;
253 	register int base, *lenp;
254 {					/* A long in base 8, plus NULL. */
255 	static char buf[sizeof(long) * NBBY / 3 + 2];
256 	register char *p;
257 
258 	p = buf;
259 	do {
260 		*++p = "0123456789abcdef"[ul % base];
261 	} while (ul /= base);
262 	if (lenp)
263 		*lenp = p - buf;
264 	return (p);
265 }
266 
267 static void
268 db_printf_guts(fmt, ap)
269 	register const char *fmt;
270 	va_list ap;
271 {
272 	register char *p;
273 	register int ch, n;
274 	u_long ul;
275 	int base, lflag, tmp, width;
276 	char padc;
277 	int ladjust;
278 	int sharpflag;
279 	int neg;
280 
281 	for (;;) {
282 		padc = ' ';
283 		width = 0;
284 		while ((ch = *(u_char *)fmt++) != '%') {
285 			if (ch == '\0')
286 				return;
287 			db_putchar(ch);
288 		}
289 		lflag = 0;
290 		ladjust = 0;
291 		sharpflag = 0;
292 		neg = 0;
293 reswitch:	switch (ch = *(u_char *)fmt++) {
294 		case '0':
295 			padc = '0';
296 			goto reswitch;
297 		case '1': case '2': case '3': case '4':
298 		case '5': case '6': case '7': case '8': case '9':
299 			for (width = 0;; ++fmt) {
300 				width = width * 10 + ch - '0';
301 				ch = *fmt;
302 				if (ch < '0' || ch > '9')
303 					break;
304 			}
305 			goto reswitch;
306 		case 'l':
307 			lflag = 1;
308 			goto reswitch;
309 		case '-':
310 			ladjust = 1;
311 			goto reswitch;
312 		case '#':
313 			sharpflag = 1;
314 			goto reswitch;
315 		case 'b':
316 			ul = va_arg(ap, int);
317 			p = va_arg(ap, char *);
318 			for (p = db_ksprintn(ul, *p++, NULL);
319 			     (ch = *p--) !='\0';)
320 				db_putchar(ch);
321 
322 			if (!ul)
323 				break;
324 
325 			for (tmp = 0; (n = *p++) != '\0';) {
326 				if (ul & (1 << (n - 1))) {
327 					db_putchar(tmp ? ',' : '<');
328 					for (; (n = *p) > ' '; ++p)
329 						db_putchar(n);
330 					tmp = 1;
331 				} else
332 					for (; *p > ' '; ++p);
333 			}
334 			if (tmp)
335 				db_putchar('>');
336 			break;
337 		case '*':
338 			width = va_arg (ap, int);
339 			if (width < 0) {
340 				ladjust = !ladjust;
341 				width = -width;
342 			}
343 			goto reswitch;
344 		case ':':
345 			p = va_arg(ap, char *);
346 			db_printf_guts (p, va_arg(ap, va_list));
347 			break;
348 		case 'c':
349 			db_putchar(va_arg(ap, int));
350 			break;
351 		case 's':
352 			p = va_arg(ap, char *);
353 			width -= strlen (p);
354 			if (!ladjust && width > 0)
355 				while (width--)
356 					db_putchar (padc);
357 			while ((ch = *p++) != '\0')
358 				db_putchar(ch);
359 			if (ladjust && width > 0)
360 				while (width--)
361 					db_putchar (padc);
362 			break;
363 		case 'r':
364 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
365 			if ((long)ul < 0) {
366 				neg = 1;
367 				ul = -(long)ul;
368 			}
369 			base = db_radix;
370 			if (base < 8 || base > 16)
371 				base = 10;
372 			goto number;
373 		case 'n':
374 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
375 			base = db_radix;
376 			if (base < 8 || base > 16)
377 				base = 10;
378 			goto number;
379 		case 'd':
380 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
381 			if ((long)ul < 0) {
382 				neg = 1;
383 				ul = -(long)ul;
384 			}
385 			base = 10;
386 			goto number;
387 		case 'o':
388 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
389 			base = 8;
390 			goto number;
391 		case 'p':
392 			db_putchar ('0');
393 			db_putchar ('x');
394 			ul = (u_long) va_arg(ap, void *);
395 			base = 16;
396 			goto number;
397 		case 'u':
398 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
399 			base = 10;
400 			goto number;
401 		case 'z':
402 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
403 			if ((long)ul < 0) {
404 				neg = 1;
405 				ul = -(long)ul;
406 			}
407 			base = 16;
408 			goto number;
409 		case 'x':
410 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
411 			base = 16;
412 number:			p = (char *)db_ksprintn(ul, base, &tmp);
413 			if (sharpflag && ul != 0) {
414 				if (base == 8)
415 					tmp++;
416 				else if (base == 16)
417 					tmp += 2;
418 			}
419 			if (neg)
420 				tmp++;
421 
422 			if (!ladjust && width && (width -= tmp) > 0)
423 				while (width--)
424 					db_putchar(padc);
425 			if (neg)
426 				db_putchar ('-');
427 			if (sharpflag && ul != 0) {
428 				if (base == 8) {
429 					db_putchar ('0');
430 				} else if (base == 16) {
431 					db_putchar ('0');
432 					db_putchar ('x');
433 				}
434 			}
435 			if (ladjust && width && (width -= tmp) > 0)
436 				while (width--)
437 					db_putchar(padc);
438 
439 			while ((ch = *p--) != '\0')
440 				db_putchar(ch);
441 			break;
442 		default:
443 			db_putchar('%');
444 			if (lflag)
445 				db_putchar('l');
446 			/* FALLTHROUGH */
447 		case '%':
448 			db_putchar(ch);
449 		}
450 	}
451 }
452