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