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