1 /* 2 * Mach Operating System 3 * Copyright (c) 1991,1990 Carnegie Mellon University 4 * All Rights Reserved. 5 * 6 * Permission to use, copy, modify and distribute this software and its 7 * documentation is hereby granted, provided that both the copyright 8 * notice and this permission notice appear in all copies of the 9 * software, derivative works or modified versions, and any portions 10 * thereof, and that both notices appear in supporting documentation. 11 * 12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 15 * 16 * Carnegie Mellon requests users of this software to return to 17 * 18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 19 * School of Computer Science 20 * Carnegie Mellon University 21 * Pittsburgh PA 15213-3890 22 * 23 * any improvements or extensions that they make and grant Carnegie the 24 * rights to redistribute these changes. 25 * 26 * $Id: db_output.c,v 1.12 1995/11/24 14:13:38 bde Exp $ 27 */ 28 29 /* 30 * Author: David B. Golub, Carnegie Mellon University 31 * Date: 7/90 32 */ 33 34 /* 35 * Printf and character output for debugger. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <machine/stdarg.h> 41 #include <ddb/ddb.h> 42 #include <ddb/db_output.h> 43 #include <machine/cons.h> 44 45 /* 46 * Character output - tracks position in line. 47 * To do this correctly, we should know how wide 48 * the output device is - then we could zero 49 * the line position when the output device wraps 50 * around to the start of the next line. 51 * 52 * Instead, we count the number of spaces printed 53 * since the last printing character so that we 54 * don't print trailing spaces. This avoids most 55 * of the wraparounds. 56 */ 57 static int db_output_position = 0; /* output column */ 58 static int db_last_non_space = 0; /* last non-space character */ 59 int db_tab_stop_width = 8; /* how wide are tab stops? */ 60 #define NEXT_TAB(i) \ 61 ((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width) 62 int db_max_width = 80; /* output line width */ 63 64 static char *db_ksprintn __P((u_long ul, int base, int *lenp)); 65 static void db_printf_guts __P((const char *, va_list)); 66 67 /* 68 * Force pending whitespace. 69 */ 70 void 71 db_force_whitespace() 72 { 73 register int last_print, next_tab; 74 75 last_print = db_last_non_space; 76 while (last_print < db_output_position) { 77 next_tab = NEXT_TAB(last_print); 78 if (next_tab <= db_output_position) { 79 while (last_print < next_tab) { /* DON'T send a tab!!! */ 80 cnputc(' '); 81 last_print++; 82 } 83 } 84 else { 85 cnputc(' '); 86 last_print++; 87 } 88 } 89 db_last_non_space = db_output_position; 90 } 91 92 /* 93 * Output character. Buffer whitespace. 94 */ 95 void 96 db_putchar(c) 97 int c; /* character to output */ 98 { 99 if (c > ' ' && c <= '~') { 100 /* 101 * Printing character. 102 * If we have spaces to print, print them first. 103 * Use tabs if possible. 104 */ 105 db_force_whitespace(); 106 cnputc(c); 107 db_output_position++; 108 db_last_non_space = db_output_position; 109 } 110 else if (c == '\n') { 111 /* Newline */ 112 cnputc(c); 113 db_output_position = 0; 114 db_last_non_space = 0; 115 db_check_interrupt(); 116 } 117 else if (c == '\r') { 118 /* Return */ 119 cnputc(c); 120 db_output_position = 0; 121 db_last_non_space = 0; 122 db_check_interrupt(); 123 } 124 else if (c == '\t') { 125 /* assume tabs every 8 positions */ 126 db_output_position = NEXT_TAB(db_output_position); 127 } 128 else if (c == ' ') { 129 /* space */ 130 db_output_position++; 131 } 132 else if (c == '\007') { 133 /* bell */ 134 cnputc(c); 135 } 136 /* other characters are assumed non-printing */ 137 } 138 139 /* 140 * Return output position 141 */ 142 int 143 db_print_position() 144 { 145 return (db_output_position); 146 } 147 148 /* 149 * Printing 150 */ 151 void 152 db_printf(const char *fmt, ...) 153 { 154 va_list listp; 155 va_start(listp, fmt); 156 db_printf_guts (fmt, listp); 157 va_end(listp); 158 } 159 160 /* 161 * End line if too long. 162 */ 163 void 164 db_end_line() 165 { 166 if (db_output_position >= db_max_width) 167 db_printf("\n"); 168 } 169 170 /* 171 * Put a number (base <= 16) in a buffer in reverse order; return an 172 * optional length and a pointer to the NULL terminated (preceded?) 173 * buffer. 174 */ 175 static char * 176 db_ksprintn(ul, base, lenp) 177 register u_long ul; 178 register int base, *lenp; 179 { /* A long in base 8, plus NULL. */ 180 static char buf[sizeof(long) * NBBY / 3 + 2]; 181 register char *p; 182 183 p = buf; 184 do { 185 *++p = "0123456789abcdef"[ul % base]; 186 } while (ul /= base); 187 if (lenp) 188 *lenp = p - buf; 189 return (p); 190 } 191 192 static void 193 db_printf_guts(fmt, ap) 194 register const char *fmt; 195 va_list ap; 196 { 197 register char *p; 198 register int ch, n; 199 u_long ul; 200 int base, lflag, tmp, width; 201 char padc; 202 int ladjust; 203 int sharpflag; 204 int neg; 205 206 for (;;) { 207 padc = ' '; 208 width = 0; 209 while ((ch = *(u_char *)fmt++) != '%') { 210 if (ch == '\0') 211 return; 212 db_putchar(ch); 213 } 214 lflag = 0; 215 ladjust = 0; 216 sharpflag = 0; 217 neg = 0; 218 reswitch: switch (ch = *(u_char *)fmt++) { 219 case '0': 220 padc = '0'; 221 goto reswitch; 222 case '1': case '2': case '3': case '4': 223 case '5': case '6': case '7': case '8': case '9': 224 for (width = 0;; ++fmt) { 225 width = width * 10 + ch - '0'; 226 ch = *fmt; 227 if (ch < '0' || ch > '9') 228 break; 229 } 230 goto reswitch; 231 case 'l': 232 lflag = 1; 233 goto reswitch; 234 case '-': 235 ladjust = 1; 236 goto reswitch; 237 case '#': 238 sharpflag = 1; 239 goto reswitch; 240 case 'b': 241 ul = va_arg(ap, int); 242 p = va_arg(ap, char *); 243 for (p = db_ksprintn(ul, *p++, NULL); *p;p--) 244 db_putchar(*p); 245 246 if (!ul) 247 break; 248 249 for (tmp = 0; *p;) { 250 n = *p++; 251 if (ul & (1 << (n - 1))) { 252 db_putchar(tmp ? ',' : '<'); 253 for (; (n = *p) > ' '; ++p) 254 db_putchar(n); 255 tmp = 1; 256 } else 257 for (; *p > ' '; ++p); 258 } 259 if (tmp) 260 db_putchar('>'); 261 break; 262 case '*': 263 width = va_arg (ap, int); 264 if (width < 0) { 265 ladjust = !ladjust; 266 width = -width; 267 } 268 goto reswitch; 269 case 'c': 270 db_putchar(va_arg(ap, int)); 271 break; 272 case 's': 273 p = va_arg(ap, char *); 274 if (p == NULL) 275 p = "(null)"; 276 width -= strlen (p); 277 if (!ladjust && width > 0) 278 while (width--) 279 db_putchar (padc); 280 for (;*p;p++) 281 db_putchar(*p); 282 if (ladjust && width > 0) 283 while (width--) 284 db_putchar (padc); 285 break; 286 case 'r': 287 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 288 if ((long)ul < 0) { 289 neg = 1; 290 ul = -(long)ul; 291 } 292 base = db_radix; 293 if (base < 8 || base > 16) 294 base = 10; 295 goto number; 296 case 'n': 297 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 298 base = db_radix; 299 if (base < 8 || base > 16) 300 base = 10; 301 goto number; 302 case 'd': 303 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 304 if ((long)ul < 0) { 305 neg = 1; 306 ul = -(long)ul; 307 } 308 base = 10; 309 goto number; 310 case 'o': 311 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 312 base = 8; 313 goto number; 314 case 'u': 315 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 316 base = 10; 317 goto number; 318 case 'z': 319 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 320 if ((long)ul < 0) { 321 neg = 1; 322 ul = -(long)ul; 323 } 324 base = 16; 325 goto number; 326 case 'x': 327 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 328 base = 16; 329 number: p = (char *)db_ksprintn(ul, base, &tmp); 330 if (sharpflag && ul != 0) { 331 if (base == 8) 332 tmp++; 333 else if (base == 16) 334 tmp += 2; 335 } 336 if (neg) 337 tmp++; 338 339 if (!ladjust && width && (width -= tmp) > 0) 340 while (width--) 341 db_putchar(padc); 342 if (neg) 343 db_putchar ('-'); 344 if (sharpflag && ul != 0) { 345 if (base == 8) { 346 db_putchar ('0'); 347 } else if (base == 16) { 348 db_putchar ('0'); 349 db_putchar ('x'); 350 } 351 } 352 if (ladjust && width && (width -= tmp) > 0) 353 while (width--) 354 db_putchar(padc); 355 356 for (;*p;p--) 357 db_putchar(*p); 358 break; 359 default: 360 db_putchar('%'); 361 if (lflag) 362 db_putchar('l'); 363 /* FALLTHROUGH */ 364 case '%': 365 db_putchar(ch); 366 } 367 } 368 } 369