db_output.c revision 12662
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.13 1995/11/29 10:25:29 phk 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 <vm/vm_param.h>
41#include <machine/stdarg.h>
42#include <ddb/ddb.h>
43#include <ddb/db_output.h>
44#include <machine/cons.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 */
58static int	db_output_position = 0;		/* output column */
59static int	db_last_non_space = 0;		/* last non-space character */
60int	db_tab_stop_width = 8;		/* how wide are tab stops? */
61#define	NEXT_TAB(i) \
62	((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width)
63int	db_max_width = 80;		/* output line width */
64
65static char	*db_ksprintn __P((u_long ul, int base, int *lenp));
66static void	db_printf_guts __P((const char *, va_list));
67
68/*
69 * Force pending whitespace.
70 */
71void
72db_force_whitespace()
73{
74	register int last_print, next_tab;
75
76	last_print = db_last_non_space;
77	while (last_print < db_output_position) {
78	    next_tab = NEXT_TAB(last_print);
79	    if (next_tab <= db_output_position) {
80		while (last_print < next_tab) { /* DON'T send a tab!!! */
81			cnputc(' ');
82			last_print++;
83		}
84	    }
85	    else {
86		cnputc(' ');
87		last_print++;
88	    }
89	}
90	db_last_non_space = db_output_position;
91}
92
93/*
94 * Output character.  Buffer whitespace.
95 */
96void
97db_putchar(c)
98	int	c;		/* character to output */
99{
100	if (c > ' ' && c <= '~') {
101	    /*
102	     * Printing character.
103	     * If we have spaces to print, print them first.
104	     * Use tabs if possible.
105	     */
106	    db_force_whitespace();
107	    cnputc(c);
108	    db_output_position++;
109	    db_last_non_space = db_output_position;
110	}
111	else if (c == '\n') {
112	    /* Newline */
113	    cnputc(c);
114	    db_output_position = 0;
115	    db_last_non_space = 0;
116	    db_check_interrupt();
117	}
118	else if (c == '\r') {
119	    /* Return */
120	    cnputc(c);
121	    db_output_position = 0;
122	    db_last_non_space = 0;
123	    db_check_interrupt();
124	}
125	else if (c == '\t') {
126	    /* assume tabs every 8 positions */
127	    db_output_position = NEXT_TAB(db_output_position);
128	}
129	else if (c == ' ') {
130	    /* space */
131	    db_output_position++;
132	}
133	else if (c == '\007') {
134	    /* bell */
135	    cnputc(c);
136	}
137	/* other characters are assumed non-printing */
138}
139
140/*
141 * Return output position
142 */
143int
144db_print_position()
145{
146	return (db_output_position);
147}
148
149/*
150 * Printing
151 */
152void
153db_printf(const char *fmt, ...)
154{
155	va_list	listp;
156	va_start(listp, fmt);
157	db_printf_guts (fmt, listp);
158	va_end(listp);
159}
160
161/*
162 * End line if too long.
163 */
164void
165db_end_line()
166{
167	if (db_output_position >= db_max_width)
168	    db_printf("\n");
169}
170
171/*
172 * Put a number (base <= 16) in a buffer in reverse order; return an
173 * optional length and a pointer to the NULL terminated (preceded?)
174 * buffer.
175 */
176static char *
177db_ksprintn(ul, base, lenp)
178	register u_long ul;
179	register int base, *lenp;
180{					/* A long in base 8, plus NULL. */
181	static char buf[sizeof(long) * NBBY / 3 + 2];
182	register char *p;
183
184	p = buf;
185	do {
186		*++p = "0123456789abcdef"[ul % base];
187	} while (ul /= base);
188	if (lenp)
189		*lenp = p - buf;
190	return (p);
191}
192
193static void
194db_printf_guts(fmt, ap)
195	register const char *fmt;
196	va_list ap;
197{
198	register char *p;
199	register int ch, n;
200	u_long ul;
201	int base, lflag, tmp, width;
202	char padc;
203	int ladjust;
204	int sharpflag;
205	int neg;
206
207	for (;;) {
208		padc = ' ';
209		width = 0;
210		while ((ch = *(u_char *)fmt++) != '%') {
211			if (ch == '\0')
212				return;
213			db_putchar(ch);
214		}
215		lflag = 0;
216		ladjust = 0;
217		sharpflag = 0;
218		neg = 0;
219reswitch:	switch (ch = *(u_char *)fmt++) {
220		case '0':
221			padc = '0';
222			goto reswitch;
223		case '1': case '2': case '3': case '4':
224		case '5': case '6': case '7': case '8': case '9':
225			for (width = 0;; ++fmt) {
226				width = width * 10 + ch - '0';
227				ch = *fmt;
228				if (ch < '0' || ch > '9')
229					break;
230			}
231			goto reswitch;
232		case 'l':
233			lflag = 1;
234			goto reswitch;
235		case '-':
236			ladjust = 1;
237			goto reswitch;
238		case '#':
239			sharpflag = 1;
240			goto reswitch;
241		case 'b':
242			ul = va_arg(ap, int);
243			p = va_arg(ap, char *);
244			for (p = db_ksprintn(ul, *p++, NULL); *p;p--)
245				db_putchar(*p);
246
247			if (!ul)
248				break;
249
250			for (tmp = 0; *p;) {
251				n = *p++;
252				if (ul & (1 << (n - 1))) {
253					db_putchar(tmp ? ',' : '<');
254					for (; (n = *p) > ' '; ++p)
255						db_putchar(n);
256					tmp = 1;
257				} else
258					for (; *p > ' '; ++p);
259			}
260			if (tmp)
261				db_putchar('>');
262			break;
263		case '*':
264			width = va_arg (ap, int);
265			if (width < 0) {
266				ladjust = !ladjust;
267				width = -width;
268			}
269			goto reswitch;
270		case 'c':
271			db_putchar(va_arg(ap, int));
272			break;
273		case 's':
274			p = va_arg(ap, char *);
275			if (p == NULL)
276				p = "(null)";
277			width -= strlen (p);
278			if (!ladjust && width > 0)
279				while (width--)
280					db_putchar (padc);
281			for (;*p;p++)
282				db_putchar(*p);
283			if (ladjust && width > 0)
284				while (width--)
285					db_putchar (padc);
286			break;
287		case 'r':
288			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
289			if ((long)ul < 0) {
290				neg = 1;
291				ul = -(long)ul;
292			}
293			base = db_radix;
294			if (base < 8 || base > 16)
295				base = 10;
296			goto number;
297		case 'n':
298			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
299			base = db_radix;
300			if (base < 8 || base > 16)
301				base = 10;
302			goto number;
303		case 'd':
304			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
305			if ((long)ul < 0) {
306				neg = 1;
307				ul = -(long)ul;
308			}
309			base = 10;
310			goto number;
311		case 'o':
312			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
313			base = 8;
314			goto number;
315		case 'u':
316			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
317			base = 10;
318			goto number;
319		case 'z':
320			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
321			if ((long)ul < 0) {
322				neg = 1;
323				ul = -(long)ul;
324			}
325			base = 16;
326			goto number;
327		case 'x':
328			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
329			base = 16;
330number:			p = (char *)db_ksprintn(ul, base, &tmp);
331			if (sharpflag && ul != 0) {
332				if (base == 8)
333					tmp++;
334				else if (base == 16)
335					tmp += 2;
336			}
337			if (neg)
338				tmp++;
339
340			if (!ladjust && width && (width -= tmp) > 0)
341				while (width--)
342					db_putchar(padc);
343			if (neg)
344				db_putchar ('-');
345			if (sharpflag && ul != 0) {
346				if (base == 8) {
347					db_putchar ('0');
348				} else if (base == 16) {
349					db_putchar ('0');
350					db_putchar ('x');
351				}
352			}
353			if (ladjust && width && (width -= tmp) > 0)
354				while (width--)
355					db_putchar(padc);
356
357			for (;*p;p--)
358				db_putchar(*p);
359			break;
360		default:
361			db_putchar('%');
362			if (lflag)
363				db_putchar('l');
364			/* FALLTHROUGH */
365		case '%':
366			db_putchar(ch);
367		}
368	}
369}
370