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