|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1993 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 "AS IS" ! 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 [email protected] ! 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 Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * Common code for printf et al. ! 28: * ! 29: * The calling routine typically takes a variable number of arguments, ! 30: * and passes the address of the first one. This implementation ! 31: * assumes a straightforward, stack implementation, aligned to the ! 32: * machine's wordsize. Increasing addresses are assumed to point to ! 33: * successive arguments (left-to-right), as is the case for a machine ! 34: * with a downward-growing stack with arguments pushed right-to-left. ! 35: * ! 36: * To write, for example, fprintf() using this routine, the code ! 37: * ! 38: * fprintf(fd, format, args) ! 39: * FILE *fd; ! 40: * char *format; ! 41: * { ! 42: * _doprnt(format, &args, fd); ! 43: * } ! 44: * ! 45: * would suffice. (This example does not handle the fprintf's "return ! 46: * value" correctly, but who looks at the return value of fprintf ! 47: * anyway?) ! 48: * ! 49: * This version implements the following printf features: ! 50: * ! 51: * %d decimal conversion ! 52: * %u unsigned conversion ! 53: * %x hexadecimal conversion ! 54: * %X hexadecimal conversion with capital letters ! 55: * %o octal conversion ! 56: * %c character ! 57: * %s string ! 58: * %m.n field width, precision ! 59: * %-m.n left adjustment ! 60: * %0m.n zero-padding ! 61: * %*.* width and precision taken from arguments ! 62: * ! 63: * This version does not implement %f, %e, or %g. It accepts, but ! 64: * ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not ! 65: * work correctly on machines for which sizeof(long) != sizeof(int). ! 66: * It does not even parse %D, %O, or %U; you should be using %ld, %o and ! 67: * %lu if you mean long conversion. ! 68: * ! 69: * As mentioned, this version does not return any reasonable value. ! 70: * ! 71: * Permission is granted to use, modify, or propagate this code as ! 72: * long as this notice is incorporated. ! 73: * ! 74: * Steve Summit 3/25/87 ! 75: */ ! 76: ! 77: /* ! 78: * Added formats for decoding device registers: ! 79: * ! 80: * printf("reg = %b", regval, "<base><arg>*") ! 81: * ! 82: * where <base> is the output base expressed as a control character: ! 83: * i.e. '\10' gives octal, '\20' gives hex. Each <arg> is a sequence of ! 84: * characters, the first of which gives the bit number to be inspected ! 85: * (origin 1), and the rest (up to a control character (<= 32)) give the ! 86: * name of the register. Thus ! 87: * printf("reg = %b\n", 3, "\10\2BITTWO\1BITONE") ! 88: * would produce ! 89: * reg = 3<BITTWO,BITONE> ! 90: * ! 91: * If the second character in <arg> is also a control character, it ! 92: * indicates the last bit of a bit field. In this case, printf will extract ! 93: * bits <1> to <2> and print it. Characters following the second control ! 94: * character are printed before the bit field. ! 95: * printf("reg = %b\n", 0xb, "\10\4\3FIELD1=\2BITTWO\1BITONE") ! 96: * would produce ! 97: * reg = b<FIELD1=2,BITONE> ! 98: */ ! 99: /* ! 100: * Added for general use: ! 101: * # prefix for alternate format: ! 102: * 0x (0X) for hex ! 103: * leading 0 for octal ! 104: * + print '+' if positive ! 105: * blank print ' ' if positive ! 106: * ! 107: * z signed hexadecimal ! 108: * r signed, 'radix' ! 109: * n unsigned, 'radix' ! 110: * ! 111: * D,U,O,Z same as corresponding lower-case versions ! 112: * (compatibility) ! 113: */ ! 114: ! 115: #include <mach/boolean.h> ! 116: #include <kern/lock.h> ! 117: #include <kern/strings.h> ! 118: #include <sys/varargs.h> ! 119: ! 120: #define isdigit(d) ((d) >= '0' && (d) <= '9') ! 121: #define Ctod(c) ((c) - '0') ! 122: ! 123: #define MAXBUF (sizeof(long int) * 8) /* enough for binary */ ! 124: ! 125: ! 126: void printnum( ! 127: register unsigned long u, ! 128: register int base, ! 129: void (*putc)( char, vm_offset_t ), ! 130: vm_offset_t putc_arg) ! 131: { ! 132: char buf[MAXBUF]; /* build number here */ ! 133: register char * p = &buf[MAXBUF-1]; ! 134: static char digs[] = "0123456789abcdef"; ! 135: ! 136: do { ! 137: *p-- = digs[u % base]; ! 138: u /= base; ! 139: } while (u != 0); ! 140: ! 141: while (++p != &buf[MAXBUF]) ! 142: (*putc)(*p, putc_arg); ! 143: ! 144: } ! 145: ! 146: boolean_t _doprnt_truncates = FALSE; ! 147: ! 148: /* printf could be called at _any_ point during system initialization, ! 149: including before printf_init() gets called from the "normal" place ! 150: in kern/startup.c. */ ! 151: boolean_t _doprnt_lock_initialized = FALSE; ! 152: decl_simple_lock_data(,_doprnt_lock) ! 153: ! 154: void printf_init() ! 155: { ! 156: if (!_doprnt_lock_initialized) ! 157: { ! 158: _doprnt_lock_initialized = TRUE; ! 159: simple_lock_init(&_doprnt_lock); ! 160: } ! 161: } ! 162: ! 163: void _doprnt( ! 164: register char *fmt, ! 165: va_list *argp, ! 166: /* character output routine */ ! 167: void (*putc)( char, vm_offset_t), ! 168: int radix, /* default radix - for '%r' */ ! 169: vm_offset_t putc_arg) ! 170: { ! 171: int length; ! 172: int prec; ! 173: boolean_t ladjust; ! 174: char padc; ! 175: long n; ! 176: unsigned long u; ! 177: int plus_sign; ! 178: int sign_char; ! 179: boolean_t altfmt, truncate; ! 180: int base; ! 181: register char c; ! 182: ! 183: printf_init(); ! 184: ! 185: #if 0 ! 186: /* Make sure that we get *some* printout, no matter what */ ! 187: simple_lock(&_doprnt_lock); ! 188: #else ! 189: { ! 190: register int i = 0; ! 191: while (i < 1*1024*1024) { ! 192: if (simple_lock_try(&_doprnt_lock)) ! 193: break; ! 194: i++; ! 195: } ! 196: } ! 197: #endif ! 198: ! 199: while ((c = *fmt) != '\0') { ! 200: if (c != '%') { ! 201: (*putc)(c, putc_arg); ! 202: fmt++; ! 203: continue; ! 204: } ! 205: ! 206: fmt++; ! 207: ! 208: length = 0; ! 209: prec = -1; ! 210: ladjust = FALSE; ! 211: padc = ' '; ! 212: plus_sign = 0; ! 213: sign_char = 0; ! 214: altfmt = FALSE; ! 215: ! 216: while (TRUE) { ! 217: c = *fmt; ! 218: if (c == '#') { ! 219: altfmt = TRUE; ! 220: } ! 221: else if (c == '-') { ! 222: ladjust = TRUE; ! 223: } ! 224: else if (c == '+') { ! 225: plus_sign = '+'; ! 226: } ! 227: else if (c == ' ') { ! 228: if (plus_sign == 0) ! 229: plus_sign = ' '; ! 230: } ! 231: else ! 232: break; ! 233: fmt++; ! 234: } ! 235: ! 236: if (c == '0') { ! 237: padc = '0'; ! 238: c = *++fmt; ! 239: } ! 240: ! 241: if (isdigit(c)) { ! 242: while(isdigit(c)) { ! 243: length = 10 * length + Ctod(c); ! 244: c = *++fmt; ! 245: } ! 246: } ! 247: else if (c == '*') { ! 248: length = va_arg(*argp, int); ! 249: c = *++fmt; ! 250: if (length < 0) { ! 251: ladjust = !ladjust; ! 252: length = -length; ! 253: } ! 254: } ! 255: ! 256: if (c == '.') { ! 257: c = *++fmt; ! 258: if (isdigit(c)) { ! 259: prec = 0; ! 260: while(isdigit(c)) { ! 261: prec = 10 * prec + Ctod(c); ! 262: c = *++fmt; ! 263: } ! 264: } ! 265: else if (c == '*') { ! 266: prec = va_arg(*argp, int); ! 267: c = *++fmt; ! 268: } ! 269: } ! 270: ! 271: if (c == 'l') ! 272: c = *++fmt; /* need it if sizeof(int) < sizeof(long) */ ! 273: ! 274: truncate = FALSE; ! 275: ! 276: switch(c) { ! 277: case 'b': ! 278: case 'B': ! 279: { ! 280: register char *p; ! 281: boolean_t any; ! 282: register int i; ! 283: ! 284: u = va_arg(*argp, unsigned long); ! 285: p = va_arg(*argp, char *); ! 286: base = *p++; ! 287: printnum(u, base, putc, putc_arg); ! 288: ! 289: if (u == 0) ! 290: break; ! 291: ! 292: any = FALSE; ! 293: while (i = *p++) { ! 294: /* NOTE: The '32' here is because ascii space */ ! 295: if (*p <= 32) { ! 296: /* ! 297: * Bit field ! 298: */ ! 299: register int j; ! 300: if (any) ! 301: (*putc)(',', putc_arg); ! 302: else { ! 303: (*putc)('<', putc_arg); ! 304: any = TRUE; ! 305: } ! 306: j = *p++; ! 307: for (; (c = *p) > 32; p++) ! 308: (*putc)(c, putc_arg); ! 309: printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)), ! 310: base, putc, putc_arg); ! 311: } ! 312: else if (u & (1<<(i-1))) { ! 313: if (any) ! 314: (*putc)(',', putc_arg); ! 315: else { ! 316: (*putc)('<', putc_arg); ! 317: any = TRUE; ! 318: } ! 319: for (; (c = *p) > 32; p++) ! 320: (*putc)(c, putc_arg); ! 321: } ! 322: else { ! 323: for (; *p > 32; p++) ! 324: continue; ! 325: } ! 326: } ! 327: if (any) ! 328: (*putc)('>', putc_arg); ! 329: break; ! 330: } ! 331: ! 332: case 'c': ! 333: c = va_arg(*argp, int); ! 334: (*putc)(c, putc_arg); ! 335: break; ! 336: ! 337: case 's': ! 338: { ! 339: register char *p; ! 340: register char *p2; ! 341: ! 342: if (prec == -1) ! 343: prec = 0x7fffffff; /* MAXINT */ ! 344: ! 345: p = va_arg(*argp, char *); ! 346: ! 347: if (p == (char *)0) ! 348: p = ""; ! 349: ! 350: if (length > 0 && !ladjust) { ! 351: n = 0; ! 352: p2 = p; ! 353: ! 354: for (; *p != '\0' && n < prec; p++) ! 355: n++; ! 356: ! 357: p = p2; ! 358: ! 359: while (n < length) { ! 360: (*putc)(' ', putc_arg); ! 361: n++; ! 362: } ! 363: } ! 364: ! 365: n = 0; ! 366: ! 367: while (*p != '\0') { ! 368: if (++n > prec) ! 369: break; ! 370: ! 371: (*putc)(*p++, putc_arg); ! 372: } ! 373: ! 374: if (n < length && ladjust) { ! 375: while (n < length) { ! 376: (*putc)(' ', putc_arg); ! 377: n++; ! 378: } ! 379: } ! 380: ! 381: break; ! 382: } ! 383: ! 384: case 'o': ! 385: truncate = _doprnt_truncates; ! 386: case 'O': ! 387: base = 8; ! 388: goto print_unsigned; ! 389: ! 390: case 'd': ! 391: truncate = _doprnt_truncates; ! 392: case 'D': ! 393: base = 10; ! 394: goto print_signed; ! 395: ! 396: case 'u': ! 397: truncate = _doprnt_truncates; ! 398: case 'U': ! 399: base = 10; ! 400: goto print_unsigned; ! 401: ! 402: case 'x': ! 403: truncate = _doprnt_truncates; ! 404: case 'X': ! 405: base = 16; ! 406: goto print_unsigned; ! 407: ! 408: case 'z': ! 409: truncate = _doprnt_truncates; ! 410: case 'Z': ! 411: base = 16; ! 412: goto print_signed; ! 413: ! 414: case 'r': ! 415: truncate = _doprnt_truncates; ! 416: case 'R': ! 417: base = radix; ! 418: goto print_signed; ! 419: ! 420: case 'n': ! 421: truncate = _doprnt_truncates; ! 422: case 'N': ! 423: base = radix; ! 424: goto print_unsigned; ! 425: ! 426: print_signed: ! 427: n = va_arg(*argp, long); ! 428: if (n >= 0) { ! 429: u = n; ! 430: sign_char = plus_sign; ! 431: } ! 432: else { ! 433: u = -n; ! 434: sign_char = '-'; ! 435: } ! 436: goto print_num; ! 437: ! 438: print_unsigned: ! 439: u = va_arg(*argp, unsigned long); ! 440: goto print_num; ! 441: ! 442: print_num: ! 443: { ! 444: char buf[MAXBUF]; /* build number here */ ! 445: register char * p = &buf[MAXBUF-1]; ! 446: static char digits[] = "0123456789abcdef"; ! 447: char *prefix = 0; ! 448: ! 449: if (truncate) u = (long)((int)(u)); ! 450: ! 451: if (u != 0 && altfmt) { ! 452: if (base == 8) ! 453: prefix = "0"; ! 454: else if (base == 16) ! 455: prefix = "0x"; ! 456: } ! 457: ! 458: do { ! 459: *p-- = digits[u % base]; ! 460: u /= base; ! 461: } while (u != 0); ! 462: ! 463: length -= (&buf[MAXBUF-1] - p); ! 464: if (sign_char) ! 465: length--; ! 466: if (prefix) ! 467: length -= strlen(prefix); ! 468: ! 469: if (padc == ' ' && !ladjust) { ! 470: /* blank padding goes before prefix */ ! 471: while (--length >= 0) ! 472: (*putc)(' ', putc_arg); ! 473: } ! 474: if (sign_char) ! 475: (*putc)(sign_char, putc_arg); ! 476: if (prefix) ! 477: while (*prefix) ! 478: (*putc)(*prefix++, putc_arg); ! 479: if (padc == '0') { ! 480: /* zero padding goes after sign and prefix */ ! 481: while (--length >= 0) ! 482: (*putc)('0', putc_arg); ! 483: } ! 484: while (++p != &buf[MAXBUF]) ! 485: (*putc)(*p, putc_arg); ! 486: ! 487: if (ladjust) { ! 488: while (--length >= 0) ! 489: (*putc)(' ', putc_arg); ! 490: } ! 491: break; ! 492: } ! 493: ! 494: case '\0': ! 495: fmt--; ! 496: break; ! 497: ! 498: default: ! 499: (*putc)(c, putc_arg); ! 500: } ! 501: fmt++; ! 502: } ! 503: ! 504: simple_unlock(&_doprnt_lock); ! 505: } ! 506: ! 507: /* ! 508: * Printing (to console) ! 509: */ ! 510: extern void cnputc( char, /*not really*/vm_offset_t); ! 511: ! 512: void vprintf(fmt, listp) ! 513: char * fmt; ! 514: va_list listp; ! 515: { ! 516: _doprnt(fmt, &listp, cnputc, 16, 0); ! 517: } ! 518: ! 519: /*VARARGS1*/ ! 520: void printf(fmt, va_alist) ! 521: char * fmt; ! 522: va_dcl ! 523: { ! 524: va_list listp; ! 525: va_start(listp); ! 526: vprintf(fmt, listp); ! 527: va_end(listp); ! 528: } ! 529: ! 530: int indent = 0; ! 531: ! 532: /* ! 533: * Printing (to console) with indentation. ! 534: */ ! 535: /*VARARGS1*/ ! 536: void iprintf(fmt, va_alist) ! 537: char * fmt; ! 538: va_dcl ! 539: { ! 540: va_list listp; ! 541: register int i; ! 542: ! 543: for (i = indent; i > 0; ){ ! 544: if (i >= 8) { ! 545: printf("\t"); ! 546: i -= 8; ! 547: } ! 548: else { ! 549: printf(" "); ! 550: i--; ! 551: } ! 552: } ! 553: va_start(listp); ! 554: _doprnt(fmt, &listp, cnputc, 16, 0); ! 555: va_end(listp); ! 556: } ! 557: ! 558: /* ! 559: * Printing to generic buffer ! 560: * Returns #bytes printed. ! 561: * Strings are zero-terminated. ! 562: */ ! 563: static void ! 564: sputc( ! 565: char c, ! 566: vm_offset_t arg) ! 567: { ! 568: register char **bufp = (char **) arg; ! 569: register char *p = *bufp; ! 570: *p++ = c; ! 571: *bufp = p; ! 572: } ! 573: ! 574: int ! 575: sprintf( buf, fmt, va_alist) ! 576: char *buf; ! 577: char *fmt; ! 578: va_dcl ! 579: { ! 580: va_list listp; ! 581: char *start = buf; ! 582: ! 583: va_start(listp); ! 584: _doprnt(fmt, &listp, sputc, 16, (vm_offset_t)&buf); ! 585: va_end(listp); ! 586: ! 587: *buf = 0; ! 588: return (buf - start); ! 589: } ! 590: ! 591: ! 592: void safe_gets(str, maxlen) ! 593: char *str; ! 594: int maxlen; ! 595: { ! 596: register char *lp; ! 597: register int c; ! 598: char *strmax = str + maxlen - 1; /* allow space for trailing 0 */ ! 599: ! 600: lp = str; ! 601: for (;;) { ! 602: c = cngetc(); ! 603: switch (c) { ! 604: case '\n': ! 605: case '\r': ! 606: printf("\n"); ! 607: *lp++ = 0; ! 608: return; ! 609: ! 610: case '\b': ! 611: case '#': ! 612: case '\177': ! 613: if (lp > str) { ! 614: printf("\b \b"); ! 615: lp--; ! 616: } ! 617: continue; ! 618: ! 619: case '@': ! 620: case 'u'&037: ! 621: lp = str; ! 622: printf("\n\r"); ! 623: continue; ! 624: ! 625: default: ! 626: if (c >= ' ' && c < '\177') { ! 627: if (lp < strmax) { ! 628: *lp++ = c; ! 629: printf("%c", c); ! 630: } ! 631: else { ! 632: printf("%c", '\007'); /* beep */ ! 633: } ! 634: } ! 635: } ! 636: } ! 637: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.