db_output.c revision 1.7 1 /* $NetBSD: db_output.c,v 1.7 1994/06/29 06:31:12 cgd 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 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