xref: /netbsd-src/sys/ddb/db_output.c (revision ce0bb6e8d2e560ecacbe865a848624f94498063b)
1 /*	$NetBSD: db_output.c,v 1.8 1994/06/29 22:41:41 deraadt Exp $	*/
2 
3 /*
4  * Mach Operating System
5  * Copyright (c) 1991,1990 Carnegie Mellon University
6  * All Rights Reserved.
7  *
8  * Permission to use, copy, modify and distribute this software and its
9  * documentation is hereby granted, provided that both the copyright
10  * notice and this permission notice appear in all copies of the
11  * software, derivative works or modified versions, and any portions
12  * thereof, and that both notices appear in supporting documentation.
13  *
14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17  *
18  * Carnegie Mellon requests users of this software to return to
19  *
20  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
21  *  School of Computer Science
22  *  Carnegie Mellon University
23  *  Pittsburgh PA 15213-3890
24  *
25  * any improvements or extensions that they make and grant Carnegie the
26  * rights to redistribute these changes.
27  */
28 
29 /*
30  * Printf and character output for debugger.
31  */
32 #include <sys/param.h>
33 
34 #include <machine/stdarg.h>
35 
36 /*
37  *	Character output - tracks position in line.
38  *	To do this correctly, we should know how wide
39  *	the output device is - then we could zero
40  *	the line position when the output device wraps
41  *	around to the start of the next line.
42  *
43  *	Instead, we count the number of spaces printed
44  *	since the last printing character so that we
45  *	don't print trailing spaces.  This avoids most
46  *	of the wraparounds.
47  */
48 
49 #ifndef	DB_MAX_LINE
50 #define	DB_MAX_LINE		24	/* maximum line */
51 #define DB_MAX_WIDTH		80	/* maximum width */
52 #endif	DB_MAX_LINE
53 
54 #define DB_MIN_MAX_WIDTH	20	/* minimum max width */
55 #define DB_MIN_MAX_LINE		3	/* minimum max line */
56 #define CTRL(c)			((c) & 0xff)
57 
58 int	db_output_position = 0;		/* output column */
59 int	db_output_line = 0;		/* output line number */
60 int	db_last_non_space = 0;		/* last non-space character */
61 int	db_tab_stop_width = 8;		/* how wide are tab stops? */
62 #define	NEXT_TAB(i) \
63 	((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width)
64 int	db_max_line = DB_MAX_LINE;	/* output max lines */
65 int	db_max_width = DB_MAX_WIDTH;	/* output line width */
66 
67 extern void	db_check_interrupt();
68 
69 /*
70  * Force pending whitespace.
71  */
72 void
73 db_force_whitespace()
74 {
75 	register int last_print, next_tab;
76 
77 	last_print = db_last_non_space;
78 	while (last_print < db_output_position) {
79 	    next_tab = NEXT_TAB(last_print);
80 	    if (next_tab <= db_output_position) {
81 		while (last_print < next_tab) { /* DON'T send a tab!!! */
82 			cnputc(' ');
83 			last_print++;
84 		}
85 	    }
86 	    else {
87 		cnputc(' ');
88 		last_print++;
89 	    }
90 	}
91 	db_last_non_space = db_output_position;
92 }
93 
94 static void
95 db_more()
96 {
97 	register  char *p;
98 	int quit_output = 0;
99 
100 	for (p = "--db_more--"; *p; p++)
101 	    cnputc(*p);
102 	switch(cngetc()) {
103 	case ' ':
104 	    db_output_line = 0;
105 	    break;
106 	case 'q':
107 	case CTRL('c'):
108 	    db_output_line = 0;
109 	    quit_output = 1;
110 	    break;
111 	default:
112 	    db_output_line--;
113 	    break;
114 	}
115 	p = "\b\b\b\b\b\b\b\b\b\b\b           \b\b\b\b\b\b\b\b\b\b\b";
116 	while (*p)
117 	    cnputc(*p++);
118 	if (quit_output) {
119 	    db_error(0);
120 	    /* NOTREACHED */
121 	}
122 }
123 
124 /*
125  * Output character.  Buffer whitespace.
126  */
127 db_putchar(c)
128 	int	c;		/* character to output */
129 {
130 	if (db_max_line >= DB_MIN_MAX_LINE && db_output_line >= db_max_line-1)
131 	    db_more();
132 	if (c > ' ' && c <= '~') {
133 	    /*
134 	     * Printing character.
135 	     * If we have spaces to print, print them first.
136 	     * Use tabs if possible.
137 	     */
138 	    db_force_whitespace();
139 	    cnputc(c);
140 	    db_output_position++;
141 	    if (db_max_width >= DB_MIN_MAX_WIDTH
142 		&& db_output_position >= db_max_width-1) {
143 		/* auto new line */
144 		cnputc('\n');
145 		db_output_position = 0;
146 		db_last_non_space = 0;
147 		db_output_line++;
148 	    }
149 	    db_last_non_space = db_output_position;
150 	}
151 	else if (c == '\n') {
152 	    /* Return */
153 	    cnputc(c);
154 	    db_output_position = 0;
155 	    db_last_non_space = 0;
156 	    db_output_line++;
157 	    db_check_interrupt();
158 	}
159 	else if (c == '\t') {
160 	    /* assume tabs every 8 positions */
161 	    db_output_position = NEXT_TAB(db_output_position);
162 	}
163 	else if (c == ' ') {
164 	    /* space */
165 	    db_output_position++;
166 	}
167 	else if (c == '\007') {
168 	    /* bell */
169 	    cnputc(c);
170 	}
171 	/* other characters are assumed non-printing */
172 }
173 
174 /*
175  * Return output position
176  */
177 int
178 db_print_position()
179 {
180 	return (db_output_position);
181 }
182 
183 /*
184  * Printing
185  */
186 extern int	db_radix;
187 
188 /*VARARGS1*/
189 #ifdef __STDC__
190 db_printf(char *fmt, ...)
191 #else
192 db_printf(fmt, va_alist)
193 	char *fmt;
194 #endif
195 {
196 	va_list	listp;
197 	va_start(listp, fmt);
198 	db_printf_guts (fmt, listp);
199 	va_end(listp);
200 }
201 
202 /* alternate name */
203 
204 /*VARARGS1*/
205 #ifdef __STDC__
206 kdbprintf(char *fmt, ...)
207 #else
208 kdbprintf(fmt, va_alist)
209 	char *fmt;
210 #endif
211 {
212 	va_list	listp;
213 	va_start(listp, fmt);
214 	db_printf_guts (fmt, listp);
215 	va_end(listp);
216 }
217 
218 /*
219  * End line if too long.
220  */
221 void
222 db_end_line()
223 {
224 	if (db_output_position >= db_max_width)
225 	    db_printf("\n");
226 }
227 
228 /*
229  * Put a number (base <= 16) in a buffer in reverse order; return an
230  * optional length and a pointer to the NULL terminated (preceded?)
231  * buffer.
232  */
233 static char *
234 db_ksprintn(ul, base, lenp)
235 	register u_long ul;
236 	register int base, *lenp;
237 {					/* A long in base 8, plus NULL. */
238 	static char buf[sizeof(long) * NBBY / 3 + 2];
239 	register char *p;
240 
241 	p = buf;
242 	do {
243 		*++p = "0123456789abcdef"[ul % base];
244 	} while (ul /= base);
245 	if (lenp)
246 		*lenp = p - buf;
247 	return (p);
248 }
249 
250 db_printf_guts(fmt, ap)
251 	register const char *fmt;
252 	va_list ap;
253 {
254 	register char *p;
255 	register int ch, n;
256 	u_long ul;
257 	int base, lflag, tmp, width;
258 	char padc;
259 	int ladjust;
260 	int sharpflag;
261 	int neg;
262 
263 	for (;;) {
264 		padc = ' ';
265 		width = 0;
266 		while ((ch = *(u_char *)fmt++) != '%') {
267 			if (ch == '\0')
268 				return;
269 			db_putchar(ch);
270 		}
271 		lflag = 0;
272 		ladjust = 0;
273 		sharpflag = 0;
274 		neg = 0;
275 reswitch:	switch (ch = *(u_char *)fmt++) {
276 		case '0':
277 			padc = '0';
278 			goto reswitch;
279 		case '1': case '2': case '3': case '4':
280 		case '5': case '6': case '7': case '8': case '9':
281 			for (width = 0;; ++fmt) {
282 				width = width * 10 + ch - '0';
283 				ch = *fmt;
284 				if (ch < '0' || ch > '9')
285 					break;
286 			}
287 			goto reswitch;
288 		case 'l':
289 			lflag = 1;
290 			goto reswitch;
291 		case '-':
292 			ladjust = 1;
293 			goto reswitch;
294 		case '#':
295 			sharpflag = 1;
296 			goto reswitch;
297 		case 'b':
298 			ul = va_arg(ap, int);
299 			p = va_arg(ap, char *);
300 			for (p = db_ksprintn(ul, *p++, NULL); ch = *p--;)
301 				db_putchar(ch);
302 
303 			if (!ul)
304 				break;
305 
306 			for (tmp = 0; n = *p++;) {
307 				if (ul & (1 << (n - 1))) {
308 					db_putchar(tmp ? ',' : '<');
309 					for (; (n = *p) > ' '; ++p)
310 						db_putchar(n);
311 					tmp = 1;
312 				} else
313 					for (; *p > ' '; ++p);
314 			}
315 			if (tmp)
316 				db_putchar('>');
317 			break;
318 		case '*':
319 			width = va_arg (ap, int);
320 			if (width < 0) {
321 				ladjust = !ladjust;
322 				width = -width;
323 			}
324 			goto reswitch;
325 		case 'c':
326 			db_putchar(va_arg(ap, int));
327 			break;
328 		case 's':
329 			p = va_arg(ap, char *);
330 			width -= strlen (p);
331 			if (!ladjust && width > 0)
332 				while (width--)
333 					db_putchar (padc);
334 			while (ch = *p++)
335 				db_putchar(ch);
336 			if (ladjust && width > 0)
337 				while (width--)
338 					db_putchar (padc);
339 			break;
340 		case 'r':
341 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
342 			if ((long)ul < 0) {
343 				neg = 1;
344 				ul = -(long)ul;
345 			}
346 			base = db_radix;
347 			if (base < 8 || base > 16)
348 				base = 10;
349 			goto number;
350 		case 'n':
351 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
352 			base = db_radix;
353 			if (base < 8 || base > 16)
354 				base = 10;
355 			goto number;
356 		case 'd':
357 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
358 			if ((long)ul < 0) {
359 				neg = 1;
360 				ul = -(long)ul;
361 			}
362 			base = 10;
363 			goto number;
364 		case 'o':
365 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
366 			base = 8;
367 			goto number;
368 		case 'u':
369 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
370 			base = 10;
371 			goto number;
372 		case 'z':
373 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
374 			if ((long)ul < 0) {
375 				neg = 1;
376 				ul = -(long)ul;
377 			}
378 			base = 16;
379 			goto number;
380 		case 'x':
381 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
382 			base = 16;
383 number:			p = (char *)db_ksprintn(ul, base, &tmp);
384 			if (sharpflag && ul != 0) {
385 				if (base == 8)
386 					tmp++;
387 				else if (base == 16)
388 					tmp += 2;
389 			}
390 			if (neg)
391 				tmp++;
392 
393 			if (!ladjust && width && (width -= tmp) > 0)
394 				while (width--)
395 					db_putchar(padc);
396 			if (neg)
397 				db_putchar ('-');
398 			if (sharpflag && ul != 0) {
399 				if (base == 8) {
400 					db_putchar ('0');
401 				} else if (base == 16) {
402 					db_putchar ('0');
403 					db_putchar ('x');
404 				}
405 			}
406 			if (ladjust && width && (width -= tmp) > 0)
407 				while (width--)
408 					db_putchar(padc);
409 
410 			while (ch = *p--)
411 				db_putchar(ch);
412 			break;
413 		default:
414 			db_putchar('%');
415 			if (lflag)
416 				db_putchar('l');
417 			/* FALLTHROUGH */
418 		case '%':
419 			db_putchar(ch);
420 		}
421 	}
422 }
423 
424