xref: /freebsd/sys/ddb/db_output.c (revision 0c43d89a0d8e976ca494d4837f4c1f3734d2c300)
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.6 1993/12/19 00:49:45 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  */
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 	    /* Return */
111 	    cnputc(c);
112 	    db_output_position = 0;
113 	    db_last_non_space = 0;
114 	    db_check_interrupt();
115 	}
116 	else if (c == '\t') {
117 	    /* assume tabs every 8 positions */
118 	    db_output_position = NEXT_TAB(db_output_position);
119 	}
120 	else if (c == ' ') {
121 	    /* space */
122 	    db_output_position++;
123 	}
124 	else if (c == '\007') {
125 	    /* bell */
126 	    cnputc(c);
127 	}
128 	/* other characters are assumed non-printing */
129 }
130 
131 /*
132  * Return output position
133  */
134 int
135 db_print_position()
136 {
137 	return (db_output_position);
138 }
139 
140 /*
141  * Printing
142  */
143 void
144 db_printf(const char *fmt, ...)
145 {
146 	va_list	listp;
147 	va_start(listp, fmt);
148 	db_printf_guts (fmt, listp);
149 	va_end(listp);
150 }
151 
152 /* alternate name */
153 
154 /*VARARGS1*/
155 void
156 kdbprintf(char *fmt, ...)
157 {
158 	va_list	listp;
159 	va_start(listp, fmt);
160 	db_printf_guts (fmt, listp);
161 	va_end(listp);
162 }
163 
164 /*
165  * End line if too long.
166  */
167 void
168 db_end_line()
169 {
170 	if (db_output_position >= db_max_width)
171 	    db_printf("\n");
172 }
173 
174 /*
175  * Put a number (base <= 16) in a buffer in reverse order; return an
176  * optional length and a pointer to the NULL terminated (preceded?)
177  * buffer.
178  */
179 static char *
180 db_ksprintn(ul, base, lenp)
181 	register u_long ul;
182 	register int base, *lenp;
183 {					/* A long in base 8, plus NULL. */
184 	static char buf[sizeof(long) * NBBY / 3 + 2];
185 	register char *p;
186 
187 	p = buf;
188 	do {
189 		*++p = "0123456789abcdef"[ul % base];
190 	} while (ul /= base);
191 	if (lenp)
192 		*lenp = p - buf;
193 	return (p);
194 }
195 
196 static void
197 db_printf_guts(fmt, ap)
198 	register const char *fmt;
199 	va_list ap;
200 {
201 	register char *p;
202 	register int ch, n;
203 	u_long ul;
204 	int base, lflag, tmp, width;
205 	char padc;
206 	int ladjust;
207 	int sharpflag;
208 	int neg;
209 
210 	for (;;) {
211 		padc = ' ';
212 		width = 0;
213 		while ((ch = *(u_char *)fmt++) != '%') {
214 			if (ch == '\0')
215 				return;
216 			db_putchar(ch);
217 		}
218 		lflag = 0;
219 		ladjust = 0;
220 		sharpflag = 0;
221 		neg = 0;
222 reswitch:	switch (ch = *(u_char *)fmt++) {
223 		case '0':
224 			padc = '0';
225 			goto reswitch;
226 		case '1': case '2': case '3': case '4':
227 		case '5': case '6': case '7': case '8': case '9':
228 			for (width = 0;; ++fmt) {
229 				width = width * 10 + ch - '0';
230 				ch = *fmt;
231 				if (ch < '0' || ch > '9')
232 					break;
233 			}
234 			goto reswitch;
235 		case 'l':
236 			lflag = 1;
237 			goto reswitch;
238 		case '-':
239 			ladjust = 1;
240 			goto reswitch;
241 		case '#':
242 			sharpflag = 1;
243 			goto reswitch;
244 		case 'b':
245 			ul = va_arg(ap, int);
246 			p = va_arg(ap, char *);
247 			for (p = db_ksprintn(ul, *p++, NULL); ch = *p--;)
248 				db_putchar(ch);
249 
250 			if (!ul)
251 				break;
252 
253 			for (tmp = 0; n = *p++;) {
254 				if (ul & (1 << (n - 1))) {
255 					db_putchar(tmp ? ',' : '<');
256 					for (; (n = *p) > ' '; ++p)
257 						db_putchar(n);
258 					tmp = 1;
259 				} else
260 					for (; *p > ' '; ++p);
261 			}
262 			if (tmp)
263 				db_putchar('>');
264 			break;
265 		case '*':
266 			width = va_arg (ap, int);
267 			if (width < 0) {
268 				ladjust = !ladjust;
269 				width = -width;
270 			}
271 			goto reswitch;
272 		case 'c':
273 			db_putchar(va_arg(ap, int));
274 			break;
275 		case 's':
276 			p = va_arg(ap, char *);
277 			width -= strlen (p);
278 			if (!ladjust && width > 0)
279 				while (width--)
280 					db_putchar (padc);
281 			while (ch = *p++)
282 				db_putchar(ch);
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;
330 number:			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 			while (ch = *p--)
358 				db_putchar(ch);
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 
371