xref: /netbsd-src/sys/ddb/db_output.c (revision d9158b13b5dfe46201430699a3f7a235ecf28df3)
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/18 04:46:35 mycroft Exp $
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 db_printf(char *fmt, ...)
190 {
191 	va_list	listp;
192 	va_start(listp, fmt);
193 	db_printf_guts (fmt, listp);
194 	va_end(listp);
195 }
196 
197 /* alternate name */
198 
199 /*VARARGS1*/
200 kdbprintf(char *fmt, ...)
201 {
202 	va_list	listp;
203 	va_start(listp, fmt);
204 	db_printf_guts (fmt, listp);
205 	va_end(listp);
206 }
207 
208 /*
209  * End line if too long.
210  */
211 void
212 db_end_line()
213 {
214 	if (db_output_position >= db_max_width)
215 	    db_printf("\n");
216 }
217 
218 /*
219  * Put a number (base <= 16) in a buffer in reverse order; return an
220  * optional length and a pointer to the NULL terminated (preceded?)
221  * buffer.
222  */
223 static char *
224 db_ksprintn(ul, base, lenp)
225 	register u_long ul;
226 	register int base, *lenp;
227 {					/* A long in base 8, plus NULL. */
228 	static char buf[sizeof(long) * NBBY / 3 + 2];
229 	register char *p;
230 
231 	p = buf;
232 	do {
233 		*++p = "0123456789abcdef"[ul % base];
234 	} while (ul /= base);
235 	if (lenp)
236 		*lenp = p - buf;
237 	return (p);
238 }
239 
240 db_printf_guts(fmt, ap)
241 	register const char *fmt;
242 	va_list ap;
243 {
244 	register char *p;
245 	register int ch, n;
246 	u_long ul;
247 	int base, lflag, tmp, width;
248 	char padc;
249 	int ladjust;
250 	int sharpflag;
251 	int neg;
252 
253 	for (;;) {
254 		padc = ' ';
255 		width = 0;
256 		while ((ch = *(u_char *)fmt++) != '%') {
257 			if (ch == '\0')
258 				return;
259 			db_putchar(ch);
260 		}
261 		lflag = 0;
262 		ladjust = 0;
263 		sharpflag = 0;
264 		neg = 0;
265 reswitch:	switch (ch = *(u_char *)fmt++) {
266 		case '0':
267 			padc = '0';
268 			goto reswitch;
269 		case '1': case '2': case '3': case '4':
270 		case '5': case '6': case '7': case '8': case '9':
271 			for (width = 0;; ++fmt) {
272 				width = width * 10 + ch - '0';
273 				ch = *fmt;
274 				if (ch < '0' || ch > '9')
275 					break;
276 			}
277 			goto reswitch;
278 		case 'l':
279 			lflag = 1;
280 			goto reswitch;
281 		case '-':
282 			ladjust = 1;
283 			goto reswitch;
284 		case '#':
285 			sharpflag = 1;
286 			goto reswitch;
287 		case 'b':
288 			ul = va_arg(ap, int);
289 			p = va_arg(ap, char *);
290 			for (p = db_ksprintn(ul, *p++, NULL); ch = *p--;)
291 				db_putchar(ch);
292 
293 			if (!ul)
294 				break;
295 
296 			for (tmp = 0; n = *p++;) {
297 				if (ul & (1 << (n - 1))) {
298 					db_putchar(tmp ? ',' : '<');
299 					for (; (n = *p) > ' '; ++p)
300 						db_putchar(n);
301 					tmp = 1;
302 				} else
303 					for (; *p > ' '; ++p);
304 			}
305 			if (tmp)
306 				db_putchar('>');
307 			break;
308 		case '*':
309 			width = va_arg (ap, int);
310 			if (width < 0) {
311 				ladjust = !ladjust;
312 				width = -width;
313 			}
314 			goto reswitch;
315 		case 'c':
316 			db_putchar(va_arg(ap, int));
317 			break;
318 		case 's':
319 			p = va_arg(ap, char *);
320 			width -= strlen (p);
321 			if (!ladjust && width > 0)
322 				while (width--)
323 					db_putchar (padc);
324 			while (ch = *p++)
325 				db_putchar(ch);
326 			if (ladjust && width > 0)
327 				while (width--)
328 					db_putchar (padc);
329 			break;
330 		case 'r':
331 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
332 			if ((long)ul < 0) {
333 				neg = 1;
334 				ul = -(long)ul;
335 			}
336 			base = db_radix;
337 			if (base < 8 || base > 16)
338 				base = 10;
339 			goto number;
340 		case 'n':
341 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
342 			base = db_radix;
343 			if (base < 8 || base > 16)
344 				base = 10;
345 			goto number;
346 		case 'd':
347 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
348 			if ((long)ul < 0) {
349 				neg = 1;
350 				ul = -(long)ul;
351 			}
352 			base = 10;
353 			goto number;
354 		case 'o':
355 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
356 			base = 8;
357 			goto number;
358 		case 'u':
359 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
360 			base = 10;
361 			goto number;
362 		case 'z':
363 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
364 			if ((long)ul < 0) {
365 				neg = 1;
366 				ul = -(long)ul;
367 			}
368 			base = 16;
369 			goto number;
370 		case 'x':
371 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
372 			base = 16;
373 number:			p = (char *)db_ksprintn(ul, base, &tmp);
374 			if (sharpflag && ul != 0) {
375 				if (base == 8)
376 					tmp++;
377 				else if (base == 16)
378 					tmp += 2;
379 			}
380 			if (neg)
381 				tmp++;
382 
383 			if (!ladjust && width && (width -= tmp) > 0)
384 				while (width--)
385 					db_putchar(padc);
386 			if (neg)
387 				db_putchar ('-');
388 			if (sharpflag && ul != 0) {
389 				if (base == 8) {
390 					db_putchar ('0');
391 				} else if (base == 16) {
392 					db_putchar ('0');
393 					db_putchar ('x');
394 				}
395 			}
396 			if (ladjust && width && (width -= tmp) > 0)
397 				while (width--)
398 					db_putchar(padc);
399 
400 			while (ch = *p--)
401 				db_putchar(ch);
402 			break;
403 		default:
404 			db_putchar('%');
405 			if (lflag)
406 				db_putchar('l');
407 			/* FALLTHROUGH */
408 		case '%':
409 			db_putchar(ch);
410 		}
411 	}
412 }
413 
414