1 /* $NetBSD: db_output.c,v 1.15 1996/10/28 08:42:13 fvdl 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 #include <dev/cons.h> 37 38 #include <machine/db_machdep.h> 39 40 #include <ddb/db_command.h> 41 #include <ddb/db_output.h> 42 #include <ddb/db_interface.h> 43 #include <ddb/db_sym.h> 44 #include <ddb/db_extern.h> 45 46 /* 47 * Character output - tracks position in line. 48 * To do this correctly, we should know how wide 49 * the output device is - then we could zero 50 * the line position when the output device wraps 51 * around to the start of the next line. 52 * 53 * Instead, we count the number of spaces printed 54 * since the last printing character so that we 55 * don't print trailing spaces. This avoids most 56 * of the wraparounds. 57 */ 58 59 #ifndef DB_MAX_LINE 60 #define DB_MAX_LINE 24 /* maximum line */ 61 #define DB_MAX_WIDTH 80 /* maximum width */ 62 #endif DB_MAX_LINE 63 64 #define DB_MIN_MAX_WIDTH 20 /* minimum max width */ 65 #define DB_MIN_MAX_LINE 3 /* minimum max line */ 66 #define CTRL(c) ((c) & 0xff) 67 68 int db_output_position = 0; /* output column */ 69 int db_output_line = 0; /* output line number */ 70 int db_last_non_space = 0; /* last non-space character */ 71 int db_tab_stop_width = 8; /* how wide are tab stops? */ 72 #define NEXT_TAB(i) \ 73 ((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width) 74 int db_max_line = DB_MAX_LINE; /* output max lines */ 75 int db_max_width = DB_MAX_WIDTH; /* output line width */ 76 77 static void db_more __P((void)); 78 static char *db_ksprintn __P((u_long, int, int *)); 79 static void db_printf_guts __P((const char *, va_list)); 80 81 /* 82 * Force pending whitespace. 83 */ 84 void 85 db_force_whitespace() 86 { 87 register int last_print, next_tab; 88 89 last_print = db_last_non_space; 90 while (last_print < db_output_position) { 91 next_tab = NEXT_TAB(last_print); 92 if (next_tab <= db_output_position) { 93 while (last_print < next_tab) { /* DON'T send a tab!!! */ 94 cnputc(' '); 95 last_print++; 96 } 97 } 98 else { 99 cnputc(' '); 100 last_print++; 101 } 102 } 103 db_last_non_space = db_output_position; 104 } 105 106 static void 107 db_more() 108 { 109 register char *p; 110 int quit_output = 0; 111 112 for (p = "--db_more--"; *p; p++) 113 cnputc(*p); 114 switch(cngetc()) { 115 case ' ': 116 db_output_line = 0; 117 break; 118 case 'q': 119 case CTRL('c'): 120 db_output_line = 0; 121 quit_output = 1; 122 break; 123 default: 124 db_output_line--; 125 break; 126 } 127 p = "\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b"; 128 while (*p) 129 cnputc(*p++); 130 if (quit_output) { 131 db_error(0); 132 /* NOTREACHED */ 133 } 134 } 135 136 /* 137 * Output character. Buffer whitespace. 138 */ 139 void 140 db_putchar(c) 141 int c; /* character to output */ 142 { 143 if (db_max_line >= DB_MIN_MAX_LINE && db_output_line >= db_max_line-1) 144 db_more(); 145 if (c > ' ' && c <= '~') { 146 /* 147 * Printing character. 148 * If we have spaces to print, print them first. 149 * Use tabs if possible. 150 */ 151 db_force_whitespace(); 152 cnputc(c); 153 db_output_position++; 154 if (db_max_width >= DB_MIN_MAX_WIDTH 155 && db_output_position >= db_max_width-1) { 156 /* auto new line */ 157 cnputc('\n'); 158 db_output_position = 0; 159 db_last_non_space = 0; 160 db_output_line++; 161 } 162 db_last_non_space = db_output_position; 163 } 164 else if (c == '\n') { 165 /* Return */ 166 cnputc(c); 167 db_output_position = 0; 168 db_last_non_space = 0; 169 db_output_line++; 170 db_check_interrupt(); 171 } 172 else if (c == '\t') { 173 /* assume tabs every 8 positions */ 174 db_output_position = NEXT_TAB(db_output_position); 175 } 176 else if (c == ' ') { 177 /* space */ 178 db_output_position++; 179 } 180 else if (c == '\007') { 181 /* bell */ 182 cnputc(c); 183 } 184 /* other characters are assumed non-printing */ 185 } 186 187 /* 188 * Return output position 189 */ 190 int 191 db_print_position() 192 { 193 return (db_output_position); 194 } 195 196 /* 197 * Printing 198 */ 199 extern int db_radix; 200 201 /*VARARGS1*/ 202 void 203 #if __STDC__ 204 db_printf(const char *fmt, ...) 205 #else 206 db_printf(fmt, va_alist) 207 const char *fmt; 208 va_dcl 209 #endif 210 { 211 va_list listp; 212 va_start(listp, fmt); 213 db_printf_guts (fmt, listp); 214 va_end(listp); 215 } 216 217 /* alternate name */ 218 219 /*VARARGS1*/ 220 void 221 #if __STDC__ 222 kdbprintf(const char *fmt, ...) 223 #else 224 kdbprintf(fmt, va_alist) 225 char *fmt; 226 va_dcl 227 #endif 228 { 229 va_list listp; 230 va_start(listp, fmt); 231 db_printf_guts (fmt, listp); 232 va_end(listp); 233 } 234 235 /* 236 * End line if too long. 237 */ 238 void 239 db_end_line() 240 { 241 if (db_output_position >= db_max_width) 242 db_printf("\n"); 243 } 244 245 /* 246 * Put a number (base <= 16) in a buffer in reverse order; return an 247 * optional length and a pointer to the NULL terminated (preceded?) 248 * buffer. 249 */ 250 static char * 251 db_ksprintn(ul, base, lenp) 252 register u_long ul; 253 register int base, *lenp; 254 { /* A long in base 8, plus NULL. */ 255 static char buf[sizeof(long) * NBBY / 3 + 2]; 256 register char *p; 257 258 p = buf; 259 do { 260 *++p = "0123456789abcdef"[ul % base]; 261 } while (ul /= base); 262 if (lenp) 263 *lenp = p - buf; 264 return (p); 265 } 266 267 static void 268 db_printf_guts(fmt, ap) 269 register const char *fmt; 270 va_list ap; 271 { 272 register char *p; 273 register int ch, n; 274 u_long ul; 275 int base, lflag, tmp, width; 276 char padc; 277 int ladjust; 278 int sharpflag; 279 int neg; 280 281 for (;;) { 282 padc = ' '; 283 width = 0; 284 while ((ch = *(const u_char *)fmt++) != '%') { 285 if (ch == '\0') 286 return; 287 db_putchar(ch); 288 } 289 lflag = 0; 290 ladjust = 0; 291 sharpflag = 0; 292 neg = 0; 293 reswitch: switch (ch = *(const u_char *)fmt++) { 294 case '0': 295 case '.': 296 padc = '0'; 297 goto reswitch; 298 case '1': case '2': case '3': case '4': 299 case '5': case '6': case '7': case '8': case '9': 300 for (width = 0;; ++fmt) { 301 width = width * 10 + ch - '0'; 302 ch = *fmt; 303 if (ch < '0' || ch > '9') 304 break; 305 } 306 goto reswitch; 307 case 'l': 308 lflag = 1; 309 goto reswitch; 310 case '-': 311 ladjust = 1; 312 goto reswitch; 313 case '#': 314 sharpflag = 1; 315 goto reswitch; 316 case 'b': 317 ul = va_arg(ap, int); 318 p = va_arg(ap, char *); 319 for (p = db_ksprintn(ul, *p++, NULL); 320 (ch = *p--) !='\0';) 321 db_putchar(ch); 322 323 if (!ul) 324 break; 325 326 for (tmp = 0; (n = *p++) != '\0';) { 327 if (ul & (1 << (n - 1))) { 328 db_putchar(tmp ? ',' : '<'); 329 for (; (n = *p) > ' '; ++p) 330 db_putchar(n); 331 tmp = 1; 332 } else 333 for (; *p > ' '; ++p); 334 } 335 if (tmp) 336 db_putchar('>'); 337 break; 338 case '*': 339 width = va_arg (ap, int); 340 if (width < 0) { 341 ladjust = !ladjust; 342 width = -width; 343 } 344 goto reswitch; 345 case ':': 346 p = va_arg(ap, char *); 347 db_printf_guts (p, va_arg(ap, va_list)); 348 break; 349 case 'c': 350 db_putchar(va_arg(ap, int)); 351 break; 352 case 's': 353 p = va_arg(ap, char *); 354 width -= strlen (p); 355 if (!ladjust && width > 0) 356 while (width--) 357 db_putchar (padc); 358 while ((ch = *p++) != '\0') 359 db_putchar(ch); 360 if (ladjust && width > 0) 361 while (width--) 362 db_putchar (padc); 363 break; 364 case 'r': 365 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 366 if ((long)ul < 0) { 367 neg = 1; 368 ul = -(long)ul; 369 } 370 base = db_radix; 371 if (base < 8 || base > 16) 372 base = 10; 373 goto number; 374 case 'n': 375 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 376 base = db_radix; 377 if (base < 8 || base > 16) 378 base = 10; 379 goto number; 380 case 'd': 381 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 382 if ((long)ul < 0) { 383 neg = 1; 384 ul = -(long)ul; 385 } 386 base = 10; 387 goto number; 388 case 'o': 389 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 390 base = 8; 391 goto number; 392 case 'p': 393 db_putchar ('0'); 394 db_putchar ('x'); 395 ul = (u_long) va_arg(ap, void *); 396 base = 16; 397 goto number; 398 case 'u': 399 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 400 base = 10; 401 goto number; 402 case 'z': 403 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 404 if ((long)ul < 0) { 405 neg = 1; 406 ul = -(long)ul; 407 } 408 base = 16; 409 goto number; 410 case 'x': 411 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 412 base = 16; 413 number: p = (char *)db_ksprintn(ul, base, &tmp); 414 if (sharpflag && ul != 0) { 415 if (base == 8) 416 tmp++; 417 else if (base == 16) 418 tmp += 2; 419 } 420 if (neg) 421 tmp++; 422 423 if (!ladjust && width && (width -= tmp) > 0) 424 while (width--) 425 db_putchar(padc); 426 if (neg) 427 db_putchar ('-'); 428 if (sharpflag && ul != 0) { 429 if (base == 8) { 430 db_putchar ('0'); 431 } else if (base == 16) { 432 db_putchar ('0'); 433 db_putchar ('x'); 434 } 435 } 436 if (ladjust && width && (width -= tmp) > 0) 437 while (width--) 438 db_putchar(padc); 439 440 while ((ch = *p--) != '\0') 441 db_putchar(ch); 442 break; 443 default: 444 db_putchar('%'); 445 if (lflag) 446 db_putchar('l'); 447 /* FALLTHROUGH */ 448 case '%': 449 db_putchar(ch); 450 } 451 } 452 } 453