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