xref: /netbsd-src/sys/ddb/db_output.c (revision 811e6386f8c5e4a3521c7003da29ec8673e344fa)
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  * PATCHES MAGIC                LEVEL   PATCH THAT GOT US HERE
27  * --------------------         -----   ----------------------
28  * CURRENT PATCH LEVEL:         4       00083
29  * --------------------         -----   ----------------------
30  *
31  * 14 Mar 93	Chris G. Demetriou	Fixed so that tab is not output,
32  *					use spaces instead.
33  */
34 /*
35  * HISTORY
36  * $Log: db_output.c,v $
37  * Revision 1.2  1993/03/21 18:04:42  cgd
38  * after 0.2.2 "stable" patches applied
39  *
40  * Revision 1.1.1.1  93/03/21  09:46:26  cgd
41  * initial import of 386bsd-0.1 sources
42  *
43  * Revision 1.1  1992/03/25  21:45:18  pace
44  * Initial revision
45  *
46  * Revision 2.3  91/02/05  17:06:45  mrt
47  * 	Changed to new Mach copyright
48  * 	[91/01/31  16:18:41  mrt]
49  *
50  * Revision 2.2  90/08/27  21:51:25  dbg
51  * 	Put extra features of db_doprnt in _doprnt.
52  * 	[90/08/20            dbg]
53  * 	Reduce lint.
54  * 	[90/08/07            dbg]
55  * 	Created.
56  * 	[90/07/25            dbg]
57  *
58  */
59 /*
60  * 	Author: David B. Golub, Carnegie Mellon University
61  *	Date:	7/90
62  */
63 
64 /*
65  * Printf and character output for debugger.
66  */
67 
68 #include "param.h"
69 #include <machine/stdarg.h>
70 
71 /*
72  *	Character output - tracks position in line.
73  *	To do this correctly, we should know how wide
74  *	the output device is - then we could zero
75  *	the line position when the output device wraps
76  *	around to the start of the next line.
77  *
78  *	Instead, we count the number of spaces printed
79  *	since the last printing character so that we
80  *	don't print trailing spaces.  This avoids most
81  *	of the wraparounds.
82  */
83 int	db_output_position = 0;		/* output column */
84 int	db_last_non_space = 0;		/* last non-space character */
85 int	db_tab_stop_width = 8;		/* how wide are tab stops? */
86 #define	NEXT_TAB(i) \
87 	((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width)
88 int	db_max_width = 80;		/* output line width */
89 
90 extern void	db_check_interrupt();
91 
92 /*
93  * Force pending whitespace.
94  */
95 void
96 db_force_whitespace()
97 {
98 	register int last_print, next_tab;
99 
100 	last_print = db_last_non_space;
101 	while (last_print < db_output_position) {
102 	    next_tab = NEXT_TAB(last_print);
103 	    if (next_tab <= db_output_position) {
104 		while (last_print < next_tab) { /* DON'T send a tab!!! */
105 			cnputc(' ');
106 			last_print++;
107 		}
108 	    }
109 	    else {
110 		cnputc(' ');
111 		last_print++;
112 	    }
113 	}
114 	db_last_non_space = db_output_position;
115 }
116 
117 /*
118  * Output character.  Buffer whitespace.
119  */
120 db_putchar(c)
121 	int	c;		/* character to output */
122 {
123 	if (c > ' ' && c <= '~') {
124 	    /*
125 	     * Printing character.
126 	     * If we have spaces to print, print them first.
127 	     * Use tabs if possible.
128 	     */
129 	    db_force_whitespace();
130 	    cnputc(c);
131 	    db_output_position++;
132 	    db_last_non_space = db_output_position;
133 	}
134 	else if (c == '\n') {
135 	    /* Return */
136 	    cnputc(c);
137 	    db_output_position = 0;
138 	    db_last_non_space = 0;
139 	    db_check_interrupt();
140 	}
141 	else if (c == '\t') {
142 	    /* assume tabs every 8 positions */
143 	    db_output_position = NEXT_TAB(db_output_position);
144 	}
145 	else if (c == ' ') {
146 	    /* space */
147 	    db_output_position++;
148 	}
149 	else if (c == '\007') {
150 	    /* bell */
151 	    cnputc(c);
152 	}
153 	/* other characters are assumed non-printing */
154 }
155 
156 /*
157  * Return output position
158  */
159 int
160 db_print_position()
161 {
162 	return (db_output_position);
163 }
164 
165 /*
166  * End line if too long.
167  */
168 void
169 db_end_line()
170 {
171 	if (db_output_position >= db_max_width)
172 	    db_printf("\n");
173 }
174 
175 /*
176  * Printing
177  */
178 extern int	db_radix;
179 
180 /*VARARGS1*/
181 db_printf(char *fmt, ...)
182 {
183 	va_list	listp;
184 	va_start(listp, fmt);
185 	db_printf_guts (fmt, listp);
186 	va_end(listp);
187 }
188 
189 /* alternate name */
190 
191 /*VARARGS1*/
192 kdbprintf(char *fmt, ...)
193 {
194 	va_list	listp;
195 	va_start(listp, fmt);
196 	db_printf_guts (fmt, listp);
197 	va_end(listp);
198 }
199 
200 /*
201  * Put a number (base <= 16) in a buffer in reverse order; return an
202  * optional length and a pointer to the NULL terminated (preceded?)
203  * buffer.
204  */
205 static char *
206 db_ksprintn(ul, base, lenp)
207 	register u_long ul;
208 	register int base, *lenp;
209 {					/* A long in base 8, plus NULL. */
210 	static char buf[sizeof(long) * NBBY / 3 + 2];
211 	register char *p;
212 
213 	p = buf;
214 	do {
215 		*++p = "0123456789abcdef"[ul % base];
216 	} while (ul /= base);
217 	if (lenp)
218 		*lenp = p - buf;
219 	return (p);
220 }
221 
222 db_printf_guts(fmt, ap)
223 	register const char *fmt;
224 	va_list ap;
225 {
226 	register char *p;
227 	register int ch, n;
228 	u_long ul;
229 	int base, lflag, tmp, width;
230 	char padc;
231 	int ladjust;
232 	int sharpflag;
233 	int neg;
234 
235 	for (;;) {
236 		padc = ' ';
237 		width = 0;
238 		while ((ch = *(u_char *)fmt++) != '%') {
239 			if (ch == '\0')
240 				return;
241 			db_putchar(ch);
242 		}
243 		lflag = 0;
244 		ladjust = 0;
245 		sharpflag = 0;
246 		neg = 0;
247 reswitch:	switch (ch = *(u_char *)fmt++) {
248 		case '0':
249 			padc = '0';
250 			goto reswitch;
251 		case '1': case '2': case '3': case '4':
252 		case '5': case '6': case '7': case '8': case '9':
253 			for (width = 0;; ++fmt) {
254 				width = width * 10 + ch - '0';
255 				ch = *fmt;
256 				if (ch < '0' || ch > '9')
257 					break;
258 			}
259 			goto reswitch;
260 		case 'l':
261 			lflag = 1;
262 			goto reswitch;
263 		case '-':
264 			ladjust = 1;
265 			goto reswitch;
266 		case '#':
267 			sharpflag = 1;
268 			goto reswitch;
269 		case 'b':
270 			ul = va_arg(ap, int);
271 			p = va_arg(ap, char *);
272 			for (p = db_ksprintn(ul, *p++, NULL); ch = *p--;)
273 				db_putchar(ch);
274 
275 			if (!ul)
276 				break;
277 
278 			for (tmp = 0; n = *p++;) {
279 				if (ul & (1 << (n - 1))) {
280 					db_putchar(tmp ? ',' : '<');
281 					for (; (n = *p) > ' '; ++p)
282 						db_putchar(n);
283 					tmp = 1;
284 				} else
285 					for (; *p > ' '; ++p);
286 			}
287 			if (tmp)
288 				db_putchar('>');
289 			break;
290 		case '*':
291 			width = va_arg (ap, int);
292 			if (width < 0) {
293 				ladjust = !ladjust;
294 				width = -width;
295 			}
296 			goto reswitch;
297 		case 'c':
298 			db_putchar(va_arg(ap, int));
299 			break;
300 		case 's':
301 			p = va_arg(ap, char *);
302 			width -= strlen (p);
303 			if (!ladjust && width > 0)
304 				while (width--)
305 					db_putchar (padc);
306 			while (ch = *p++)
307 				db_putchar(ch);
308 			if (ladjust && width > 0)
309 				while (width--)
310 					db_putchar (padc);
311 			break;
312 		case 'r':
313 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
314 			if ((long)ul < 0) {
315 				neg = 1;
316 				ul = -(long)ul;
317 			}
318 			base = db_radix;
319 			if (base < 8 || base > 16)
320 				base = 10;
321 			goto number;
322 		case 'n':
323 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
324 			base = db_radix;
325 			if (base < 8 || base > 16)
326 				base = 10;
327 			goto number;
328 		case 'd':
329 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
330 			if ((long)ul < 0) {
331 				neg = 1;
332 				ul = -(long)ul;
333 			}
334 			base = 10;
335 			goto number;
336 		case 'o':
337 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
338 			base = 8;
339 			goto number;
340 		case 'u':
341 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
342 			base = 10;
343 			goto number;
344 		case 'z':
345 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
346 			if ((long)ul < 0) {
347 				neg = 1;
348 				ul = -(long)ul;
349 			}
350 			base = 16;
351 			goto number;
352 		case 'x':
353 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
354 			base = 16;
355 number:			p = (char *)db_ksprintn(ul, base, &tmp);
356 			if (sharpflag && ul != 0) {
357 				if (base == 8)
358 					tmp++;
359 				else if (base == 16)
360 					tmp += 2;
361 			}
362 			if (neg)
363 				tmp++;
364 
365 			if (!ladjust && width && (width -= tmp) > 0)
366 				while (width--)
367 					db_putchar(padc);
368 			if (neg)
369 				db_putchar ('-');
370 			if (sharpflag && ul != 0) {
371 				if (base == 8) {
372 					db_putchar ('0');
373 				} else if (base == 16) {
374 					db_putchar ('0');
375 					db_putchar ('x');
376 				}
377 			}
378 			if (ladjust && width && (width -= tmp) > 0)
379 				while (width--)
380 					db_putchar(padc);
381 
382 			while (ch = *p--)
383 				db_putchar(ch);
384 			break;
385 		default:
386 			db_putchar('%');
387 			if (lflag)
388 				db_putchar('l');
389 			/* FALLTHROUGH */
390 		case '%':
391 			db_putchar(ch);
392 		}
393 	}
394 }
395 
396