xref: /freebsd/sys/ddb/db_output.c (revision a316b26e50bbed7cf655fbba726ab87d8ab7599d)
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.9 1994/09/27 03:34:54 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 <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  */
56 int	db_output_position = 0;		/* output column */
57 int	db_last_non_space = 0;		/* last non-space character */
58 int	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)
61 int	db_max_width = 80;		/* output line width */
62 
63 
64 static void db_printf_guts(const char *, va_list);
65 
66 /*
67  * Force pending whitespace.
68  */
69 void
70 db_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  */
94 void
95 db_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  */
141 int
142 db_print_position()
143 {
144 	return (db_output_position);
145 }
146 
147 /*
148  * Printing
149  */
150 void
151 db_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*/
162 void
163 kdbprintf(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  */
174 void
175 db_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  */
186 static char *
187 db_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 
203 static void
204 db_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;
229 reswitch:	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;
340 number:			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