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