db_output.c revision 2320
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.7 1994/08/13 03:49:21 wollman 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); ch = *p--;)
255				db_putchar(ch);
256
257			if (!ul)
258				break;
259
260			for (tmp = 0; n = *p++;) {
261				if (ul & (1 << (n - 1))) {
262					db_putchar(tmp ? ',' : '<');
263					for (; (n = *p) > ' '; ++p)
264						db_putchar(n);
265					tmp = 1;
266				} else
267					for (; *p > ' '; ++p);
268			}
269			if (tmp)
270				db_putchar('>');
271			break;
272		case '*':
273			width = va_arg (ap, int);
274			if (width < 0) {
275				ladjust = !ladjust;
276				width = -width;
277			}
278			goto reswitch;
279		case 'c':
280			db_putchar(va_arg(ap, int));
281			break;
282		case 's':
283			p = va_arg(ap, char *);
284			width -= strlen (p);
285			if (!ladjust && width > 0)
286				while (width--)
287					db_putchar (padc);
288			while (ch = *p++)
289				db_putchar(ch);
290			if (ladjust && width > 0)
291				while (width--)
292					db_putchar (padc);
293			break;
294		case 'r':
295			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
296			if ((long)ul < 0) {
297				neg = 1;
298				ul = -(long)ul;
299			}
300			base = db_radix;
301			if (base < 8 || base > 16)
302				base = 10;
303			goto number;
304		case 'n':
305			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
306			base = db_radix;
307			if (base < 8 || base > 16)
308				base = 10;
309			goto number;
310		case 'd':
311			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
312			if ((long)ul < 0) {
313				neg = 1;
314				ul = -(long)ul;
315			}
316			base = 10;
317			goto number;
318		case 'o':
319			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
320			base = 8;
321			goto number;
322		case 'u':
323			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
324			base = 10;
325			goto number;
326		case 'z':
327			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
328			if ((long)ul < 0) {
329				neg = 1;
330				ul = -(long)ul;
331			}
332			base = 16;
333			goto number;
334		case 'x':
335			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
336			base = 16;
337number:			p = (char *)db_ksprintn(ul, base, &tmp);
338			if (sharpflag && ul != 0) {
339				if (base == 8)
340					tmp++;
341				else if (base == 16)
342					tmp += 2;
343			}
344			if (neg)
345				tmp++;
346
347			if (!ladjust && width && (width -= tmp) > 0)
348				while (width--)
349					db_putchar(padc);
350			if (neg)
351				db_putchar ('-');
352			if (sharpflag && ul != 0) {
353				if (base == 8) {
354					db_putchar ('0');
355				} else if (base == 16) {
356					db_putchar ('0');
357					db_putchar ('x');
358				}
359			}
360			if (ladjust && width && (width -= tmp) > 0)
361				while (width--)
362					db_putchar(padc);
363
364			while (ch = *p--)
365				db_putchar(ch);
366			break;
367		default:
368			db_putchar('%');
369			if (lflag)
370				db_putchar('l');
371			/* FALLTHROUGH */
372		case '%':
373			db_putchar(ch);
374		}
375	}
376}
377
378