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