|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 23: /*- ! 24: * Copyright (c) 1986, 1988, 1991, 1993 ! 25: * The Regents of the University of California. All rights reserved. ! 26: * (c) UNIX System Laboratories, Inc. ! 27: * All or some portions of this file are derived from material licensed ! 28: * to the University of California by American Telephone and Telegraph ! 29: * Co. or Unix System Laboratories, Inc. and are reproduced herein with ! 30: * the permission of UNIX System Laboratories, Inc. ! 31: * ! 32: * Redistribution and use in source and binary forms, with or without ! 33: * modification, are permitted provided that the following conditions ! 34: * are met: ! 35: * 1. Redistributions of source code must retain the above copyright ! 36: * notice, this list of conditions and the following disclaimer. ! 37: * 2. Redistributions in binary form must reproduce the above copyright ! 38: * notice, this list of conditions and the following disclaimer in the ! 39: * documentation and/or other materials provided with the distribution. ! 40: * 3. All advertising materials mentioning features or use of this software ! 41: * must display the following acknowledgement: ! 42: * This product includes software developed by the University of ! 43: * California, Berkeley and its contributors. ! 44: * 4. Neither the name of the University nor the names of its contributors ! 45: * may be used to endorse or promote products derived from this software ! 46: * without specific prior written permission. ! 47: * ! 48: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 49: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 50: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 51: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 52: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 53: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 54: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 55: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 56: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 57: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 58: * SUCH DAMAGE. ! 59: * ! 60: * @(#)subr_prf.c 8.4 (Berkeley) 5/4/95 ! 61: */ ! 62: /* HISTORY ! 63: * 22-Sep-1997 Umesh Vaishampayan ([email protected]) ! 64: * Cleaned up m68k crud. Fixed vlog() to do logpri() for ppc, too. ! 65: * ! 66: * 17-July-97 Umesh Vaishampayan ([email protected]) ! 67: * Eliminated multiple definition of constty which is defined ! 68: * in bsd/dev/XXX/cons.c ! 69: * ! 70: * 26-MAR-1997 Umesh Vaishampayan ([email protected] ! 71: * Fixed tharshing format in many functions. Cleanup. ! 72: * ! 73: * 17-Jun-1995 Mac Gillon (mgillon) at NeXT ! 74: * Purged old history ! 75: * New version based on 4.4 and NS3.3 ! 76: */ ! 77: ! 78: #include <sys/param.h> ! 79: #include <sys/systm.h> ! 80: #include <sys/buf.h> ! 81: #include <sys/conf.h> ! 82: #include <sys/reboot.h> ! 83: #include <sys/msgbuf.h> ! 84: #include <sys/proc.h> ! 85: #include <sys/ioctl.h> ! 86: #include <sys/tty.h> ! 87: #include <sys/file.h> ! 88: #include <sys/tprintf.h> ! 89: #include <sys/syslog.h> ! 90: #include <stdarg.h> ! 91: #include <sys/malloc.h> ! 92: #include <sys/lock.h> ! 93: #include <kern/parallel.h> ! 94: #import <sys/subr_prf.h> ! 95: ! 96: #include <kern/cpu_number.h> /* for cpu_number() */ ! 97: #include <machine/spl.h> ! 98: #include <libkern/libkern.h> ! 99: ! 100: struct snprintf_arg { ! 101: char *str; ! 102: size_t remain; ! 103: }; ! 104: ! 105: ! 106: /* ! 107: * In case console is off, ! 108: * panicstr contains argument to last ! 109: * call to panic. ! 110: */ ! 111: extern const char *panicstr; ! 112: ! 113: extern cnputc(); /* standard console putc */ ! 114: int (*v_putc)() = cnputc; /* routine to putc on virtual console */ ! 115: ! 116: extern struct tty cons; /* standard console tty */ ! 117: extern struct tty *constty; /* pointer to console "window" tty */ ! 118: ! 119: /* ! 120: * Record cpu that panic'd and lock around panic data ! 121: */ ! 122: ! 123: static void puts(const char *s, int flags, struct tty *ttyp); ! 124: static void printn(u_long n, int b, int flags, struct tty *ttyp, int zf, int fld_size); ! 125: ! 126: /* MP printf stuff */ ! 127: decl_simple_lock_data(,printf_lock) ! 128: #if NCPUS > 1 ! 129: boolean_t new_printf_cpu_number; /* do we need to output who we are */ ! 130: #endif ! 131: ! 132: extern void logwakeup(); ! 133: extern void halt_cpu(); ! 134: #if NeXT ! 135: extern void mini_mon(); ! 136: #endif /* NeXT */ ! 137: extern boot(); ! 138: int putchar(); ! 139: ! 140: static void ! 141: snprintf_func(int ch, void *arg); ! 142: ! 143: ! 144: ! 145: /* ! 146: * Uprintf prints to the controlling terminal for the current process. ! 147: * It may block if the tty queue is overfull. No message is printed if ! 148: * the queue does not clear in a reasonable time. ! 149: */ ! 150: void ! 151: uprintf(const char *fmt, ...) ! 152: { ! 153: register struct proc *p = current_proc(); ! 154: va_list ap; ! 155: ! 156: unix_master(); /* sessions, sigh */ ! 157: if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { ! 158: va_start(ap, fmt); ! 159: prf(fmt, ap, TOTTY, (struct tty *)p->p_session->s_ttyvp); ! 160: va_end(ap); ! 161: } ! 162: unix_release(); ! 163: } ! 164: ! 165: tpr_t ! 166: tprintf_open(p) ! 167: register struct proc *p; ! 168: { ! 169: unix_master(); /* sessions, sigh */ ! 170: if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { ! 171: SESSHOLD(p->p_session); ! 172: unix_release(); ! 173: return ((tpr_t) p->p_session); ! 174: } ! 175: unix_release(); ! 176: return ((tpr_t) NULL); ! 177: } ! 178: ! 179: void ! 180: tprintf_close(sess) ! 181: tpr_t sess; ! 182: { ! 183: unix_master(); /* sessions, sigh */ ! 184: if (sess) ! 185: SESSRELE((struct session *) sess); ! 186: unix_release(); ! 187: } ! 188: ! 189: /* ! 190: * tprintf prints on the controlling terminal associated ! 191: * with the given session. ! 192: */ ! 193: void ! 194: tprintf(tpr_t tpr, const char *fmt, ...) ! 195: { ! 196: register struct session *sess = (struct session *)tpr; ! 197: struct tty *tp = NULL; ! 198: int flags = TOLOG; ! 199: va_list ap; ! 200: ! 201: logpri(LOG_INFO); ! 202: unix_master(); /* sessions, sigh */ ! 203: if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) { ! 204: flags |= TOTTY; ! 205: tp = sess->s_ttyp; ! 206: } ! 207: if (tp != NULL) { ! 208: va_start(ap, fmt); ! 209: prf(fmt, ap, TOTTY, tp); ! 210: va_end(ap); ! 211: } ! 212: unix_release(); ! 213: logwakeup(); ! 214: } ! 215: ! 216: /* ! 217: * Ttyprintf displays a message on a tty; it should be used only by ! 218: * the tty driver, or anything that knows the underlying tty will not ! 219: * be revoke(2)'d away. Other callers should use tprintf. ! 220: */ ! 221: void ! 222: ttyprintf(struct tty *tp, const char *fmt, ...) ! 223: { ! 224: va_list ap; ! 225: ! 226: if (tp != NULL) { ! 227: va_start(ap, fmt); ! 228: prf(fmt, ap, TOTTY, tp); ! 229: va_end(ap); ! 230: } ! 231: } ! 232: ! 233: extern int log_open; ! 234: ! 235: ! 236: void ! 237: logpri(level) ! 238: int level; ! 239: { ! 240: ! 241: putchar('<', TOLOG, (struct tty *)0); ! 242: printn((u_long)level, 10, TOLOG, (struct tty *)0, 0, 0); ! 243: putchar('>', TOLOG, (struct tty *)0); ! 244: } ! 245: ! 246: void ! 247: addlog(const char *fmt, ...) ! 248: { ! 249: register s = splhigh(); ! 250: va_list ap; ! 251: ! 252: va_start(ap, fmt); ! 253: prf(fmt, ap, TOLOG, (struct tty *)0); ! 254: splx(s); ! 255: if (!log_open) ! 256: prf(fmt, ap, TOCONS, (struct tty *)0); ! 257: va_end(ap); ! 258: logwakeup(); ! 259: } ! 260: void _printf(int flags, struct tty *ttyp, const char *format, ...) ! 261: { ! 262: va_list ap; ! 263: ! 264: va_start(ap, format); ! 265: prf(format, ap, flags, ttyp); ! 266: va_end(ap); ! 267: } ! 268: ! 269: int prf(const char *fmt, va_list ap, int flags, struct tty *ttyp) ! 270: { ! 271: register int b, c, i; ! 272: char *s; ! 273: int any; ! 274: int zf = 0, fld_size; ! 275: ! 276: #if NCPUS > 1 ! 277: int cpun = cpu_number(); ! 278: ! 279: if(ttyp == 0) { ! 280: simple_lock(&printf_lock); ! 281: } else ! 282: TTY_LOCK(ttyp); ! 283: ! 284: if (cpun != master_cpu) ! 285: new_printf_cpu_number = TRUE; ! 286: ! 287: if (new_printf_cpu_number) { ! 288: putchar('{', flags, ttyp); ! 289: printn((u_long)cpun, 10, flags, ttyp, 0, 0); ! 290: putchar('}', flags, ttyp); ! 291: } ! 292: #endif /* NCPUS > 1 */ ! 293: loop: ! 294: while ((c = *fmt++) != '%') { ! 295: if (c == '\0') { ! 296: #if NCPUS > 1 ! 297: if(ttyp == 0) { ! 298: simple_unlock(&printf_lock); ! 299: } else ! 300: TTY_UNLOCK(ttyp); ! 301: #endif ! 302: return 0; ! 303: } ! 304: putchar(c, flags, ttyp); ! 305: } ! 306: again: ! 307: zf = 0; ! 308: fld_size = 0; ! 309: c = *fmt++; ! 310: if (c == '0') ! 311: zf = '0'; ! 312: fld_size = 0; ! 313: for (;c <= '9' && c >= '0'; c = *fmt++) ! 314: fld_size = fld_size * 10 + c - '0'; ! 315: ! 316: /* THIS CODE IS VAX DEPENDENT IN HANDLING %l? AND %c */ ! 317: switch (c) { ! 318: ! 319: case 'l': ! 320: goto again; ! 321: case 'x': case 'X': ! 322: b = 16; ! 323: goto number; ! 324: case 'd': case 'D': ! 325: case 'u': /* what a joke */ ! 326: b = 10; ! 327: goto number; ! 328: case 'o': case 'O': ! 329: b = 8; ! 330: number: ! 331: printn(va_arg(ap, unsigned), b, flags, ttyp, zf, fld_size); ! 332: break; ! 333: case 'c': ! 334: b = va_arg(ap, unsigned); ! 335: #if BYTE_ORDER == LITTLE_ENDIAN ! 336: for (i = 24; i >= 0; i -= 8) ! 337: if (c = (b >> i) & 0x7f) ! 338: putchar(c, flags, ttyp); ! 339: #endif ! 340: #if BYTE_ORDER == BIG_ENDIAN ! 341: if ((c = (b & 0x7f))) ! 342: putchar(c, flags, ttyp); ! 343: #endif ! 344: break; ! 345: case 'b': ! 346: b = va_arg(ap, unsigned); ! 347: s = va_arg(ap, char *); ! 348: printn((u_long)b, *s++, flags, ttyp, 0, 0); ! 349: any = 0; ! 350: if (b) { ! 351: while ((i = *s++)) { ! 352: if (*s <= 32) { ! 353: register int j; ! 354: ! 355: if (any++) ! 356: putchar(',', flags, ttyp); ! 357: j = *s++ ; ! 358: for (; (c = *s) > 32 ; s++) ! 359: putchar(c, flags, ttyp); ! 360: printn( (u_long)( (b >> (j-1)) & ! 361: ( (2 << (i-j)) -1)), ! 362: 8, flags, ttyp, 0, 0); ! 363: } else if (b & (1 << (i-1))) { ! 364: putchar(any? ',' : '<', flags, ttyp); ! 365: any = 1; ! 366: for (; (c = *s) > 32; s++) ! 367: putchar(c, flags, ttyp); ! 368: } else ! 369: for (; *s > 32; s++) ! 370: ; ! 371: } ! 372: putchar('>', flags, ttyp); ! 373: } ! 374: break; ! 375: ! 376: case 's': ! 377: s = va_arg(ap, char *); ! 378: #ifdef DEBUG ! 379: if (fld_size) { ! 380: while (fld_size-- > 0) ! 381: putchar((c = *s++)? c : '_', flags, ttyp); ! 382: } else { ! 383: while ((c = *s++)) ! 384: putchar(c, flags, ttyp); ! 385: } ! 386: #else ! 387: while (c = *s++) ! 388: putchar(c, flags, ttyp); ! 389: #endif ! 390: break; ! 391: ! 392: case '%': ! 393: putchar('%', flags, ttyp); ! 394: goto loop; ! 395: case 'C': ! 396: b = va_arg(ap, unsigned); ! 397: #if BYTE_ORDER == LITTLE_ENDIAN ! 398: for (i = 24; i >= 0; i -= 8) ! 399: if (c = (b >> i) & 0x7f) ! 400: putchar(c, flags, ttyp); ! 401: #endif ! 402: #if BYTE_ORDER == BIG_ENDIAN ! 403: if ((c = (b & 0x7f))) ! 404: putchar(c, flags, ttyp); ! 405: #endif ! 406: ! 407: case 'r': ! 408: case 'R': ! 409: b = va_arg(ap, unsigned); ! 410: s = va_arg(ap, char *); ! 411: if (c == 'R') { ! 412: puts("0x", flags, ttyp); ! 413: printn((u_long)b, 16, flags, ttyp, 0, 0); ! 414: } ! 415: any = 0; ! 416: if (c == 'r' || b) { ! 417: register struct reg_desc *rd; ! 418: register struct reg_values *rv; ! 419: unsigned field; ! 420: ! 421: putchar('<', flags, ttyp); ! 422: for (rd = (struct reg_desc *)s; rd->rd_mask; rd++) { ! 423: field = b & rd->rd_mask; ! 424: field = (rd->rd_shift > 0) ! 425: ? field << rd->rd_shift ! 426: : field >> -rd->rd_shift; ! 427: if (any && ! 428: (rd->rd_format || rd->rd_values ! 429: || (rd->rd_name && field) ! 430: ) ! 431: ) ! 432: putchar(',', flags, ttyp); ! 433: if (rd->rd_name) { ! 434: if (rd->rd_format || rd->rd_values ! 435: || field) { ! 436: puts(rd->rd_name, flags, ttyp); ! 437: any = 1; ! 438: } ! 439: if (rd->rd_format || rd->rd_values) { ! 440: putchar('=', flags, ttyp); ! 441: any = 1; ! 442: } ! 443: } ! 444: if (rd->rd_format) { ! 445: _printf(flags, ttyp, rd->rd_format, ! 446: field); ! 447: any = 1; ! 448: if (rd->rd_values) ! 449: putchar(':', flags, ttyp); ! 450: } ! 451: if (rd->rd_values) { ! 452: any = 1; ! 453: for (rv = rd->rd_values; ! 454: rv->rv_name; ! 455: rv++) { ! 456: if (field == rv->rv_value) { ! 457: puts(rv->rv_name, flags, ! 458: ttyp); ! 459: break; ! 460: } ! 461: } ! 462: if (rv->rv_name == NULL) ! 463: puts("???", flags, ttyp); ! 464: } ! 465: } ! 466: putchar('>', flags, ttyp); ! 467: } ! 468: break; ! 469: ! 470: case 'n': ! 471: case 'N': ! 472: { ! 473: register struct reg_values *rv; ! 474: ! 475: b = va_arg(ap, unsigned); ! 476: s = va_arg(ap,char *); ! 477: for (rv = (struct reg_values *)s; rv->rv_name; rv++) { ! 478: if (b == rv->rv_value) { ! 479: puts(rv->rv_name, flags, ttyp); ! 480: break; ! 481: } ! 482: } ! 483: if (rv->rv_name == NULL) ! 484: puts("???", flags, ttyp); ! 485: if (c == 'N' || rv->rv_name == NULL) { ! 486: putchar(':', flags, ttyp); ! 487: printn((u_long)b, 10, flags, ttyp, 0, 0); ! 488: } ! 489: } ! 490: break; ! 491: } ! 492: goto loop; ! 493: } ! 494: ! 495: static void puts(const char *s, int flags, struct tty *ttyp) ! 496: { ! 497: register char c; ! 498: ! 499: while ((c = *s++)) ! 500: putchar(c, flags, ttyp); ! 501: } ! 502: ! 503: /* ! 504: * Printn prints a number n in base b. ! 505: * We don't use recursion to avoid deep kernel stacks. ! 506: */ ! 507: static void printn(u_long n, int b, int flags, struct tty *ttyp, int zf, int fld_size) ! 508: { ! 509: char prbuf[11]; ! 510: register char *cp; ! 511: ! 512: if (b == 10 && (int)n < 0) { ! 513: putchar('-', flags, ttyp); ! 514: n = (unsigned)(-(int)n); ! 515: } ! 516: cp = prbuf; ! 517: do { ! 518: *cp++ = "0123456789abcdef"[n%b]; ! 519: n /= b; ! 520: } while (n); ! 521: if (fld_size) { ! 522: for (fld_size -= cp - prbuf; fld_size > 0; fld_size--) ! 523: if (zf) ! 524: putchar('0', flags, ttyp); ! 525: else ! 526: putchar(' ', flags, ttyp); ! 527: } ! 528: do ! 529: putchar(*--cp, flags, ttyp); ! 530: while (cp > prbuf); ! 531: } ! 532: ! 533: ! 534: ! 535: /* ! 536: * Warn that a system table is full. ! 537: */ ! 538: void tablefull(const char *tab) ! 539: { ! 540: log(LOG_ERR, "%s: table is full\n", tab); ! 541: } ! 542: ! 543: /* ! 544: * Print a character on console or users terminal. ! 545: * If destination is console then the last MSGBUFS characters ! 546: * are saved in msgbuf for inspection later. ! 547: */ ! 548: /*ARGSUSED*/ ! 549: int ! 550: putchar(c, flags, tp) ! 551: register int c; ! 552: struct tty *tp; ! 553: { ! 554: register struct msgbuf *mbp; ! 555: char **sp = (char**) tp; ! 556: ! 557: if (panicstr) ! 558: constty = 0; ! 559: if ((flags & TOCONS) && tp == NULL && constty) { ! 560: tp = constty; ! 561: flags |= TOTTY; ! 562: } ! 563: if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && ! 564: (flags & TOCONS) && tp == constty) ! 565: constty = 0; ! 566: if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177) ! 567: log_putc(c); ! 568: if ((flags & TOCONS) && constty == 0 && c != '\0') ! 569: (*v_putc)(c); ! 570: if (flags & TOSTR) { ! 571: **sp = c; ! 572: (*sp)++; ! 573: } ! 574: return 0; ! 575: } ! 576: ! 577: ! 578: ! 579: /* ! 580: * Scaled down version of vsprintf(3). ! 581: */ ! 582: int ! 583: vsprintf(char *buf, const char *cfmt, va_list ap) ! 584: { ! 585: int retval; ! 586: ! 587: retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); ! 588: buf[retval] = '\0'; ! 589: return retval; ! 590: } ! 591: ! 592: /* ! 593: * Scaled down version of snprintf(3). ! 594: */ ! 595: int ! 596: snprintf(char *str, size_t size, const char *format, ...) ! 597: { ! 598: int retval; ! 599: va_list ap; ! 600: ! 601: va_start(ap, format); ! 602: retval = vsnprintf(str, size, format, ap); ! 603: va_end(ap); ! 604: return(retval); ! 605: } ! 606: ! 607: /* ! 608: * Scaled down version of vsnprintf(3). ! 609: */ ! 610: int ! 611: vsnprintf(char *str, size_t size, const char *format, va_list ap) ! 612: { ! 613: struct snprintf_arg info; ! 614: int retval; ! 615: ! 616: info.str = str; ! 617: info.remain = size; ! 618: retval = kvprintf(format, snprintf_func, &info, 10, ap); ! 619: if (info.remain >= 1) ! 620: *info.str++ = '\0'; ! 621: return retval; ! 622: } ! 623: ! 624: static void ! 625: snprintf_func(int ch, void *arg) ! 626: { ! 627: struct snprintf_arg *const info = arg; ! 628: ! 629: if (info->remain >= 2) { ! 630: *info->str++ = ch; ! 631: info->remain--; ! 632: } ! 633: } ! 634: ! 635: /* ! 636: * Put a number (base <= 16) in a buffer in reverse order; return an ! 637: * optional length and a pointer to the NULL terminated (preceded?) ! 638: * buffer. ! 639: */ ! 640: static char * ! 641: ksprintn(ul, base, lenp) ! 642: register u_long ul; ! 643: register int base, *lenp; ! 644: { /* A long in base 8, plus NULL. */ ! 645: static char buf[sizeof(long) * NBBY / 3 + 2]; ! 646: register char *p; ! 647: ! 648: p = buf; ! 649: do { ! 650: *++p = hex2ascii(ul % base); ! 651: } while (ul /= base); ! 652: if (lenp) ! 653: *lenp = p - buf; ! 654: return (p); ! 655: } ! 656: ! 657: /* ! 658: * Scaled down version of printf(3). ! 659: * ! 660: * Two additional formats: ! 661: * ! 662: * The format %b is supported to decode error registers. ! 663: * Its usage is: ! 664: * ! 665: * printf("reg=%b\n", regval, "<base><arg>*"); ! 666: * ! 667: * where <base> is the output base expressed as a control character, e.g. ! 668: * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, ! 669: * the first of which gives the bit number to be inspected (origin 1), and ! 670: * the next characters (up to a control character, i.e. a character <= 32), ! 671: * give the name of the register. Thus: ! 672: * ! 673: * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); ! 674: * ! 675: * would produce output: ! 676: * ! 677: * reg=3<BITTWO,BITONE> ! 678: * ! 679: * XXX: %D -- Hexdump, takes pointer and separator string: ! 680: * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX ! 681: * ("%*D", len, ptr, " " -> XX XX XX XX ... ! 682: */ ! 683: int ! 684: kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap) ! 685: { ! 686: #define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; } ! 687: char *p, *q, *d; ! 688: u_char *up; ! 689: int ch, n; ! 690: u_long ul; ! 691: int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot; ! 692: int dwidth; ! 693: char padc; ! 694: int retval = 0; ! 695: ! 696: if (!func) ! 697: d = (char *) arg; ! 698: else ! 699: d = NULL; ! 700: ! 701: if (fmt == NULL) ! 702: fmt = "(fmt null)\n"; ! 703: ! 704: if (radix < 2 || radix > 36) ! 705: radix = 10; ! 706: ! 707: for (;;) { ! 708: padc = ' '; ! 709: width = 0; ! 710: while ((ch = (u_char)*fmt++) != '%') { ! 711: if (ch == '\0') ! 712: return retval; ! 713: PCHAR(ch); ! 714: } ! 715: lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; ! 716: sign = 0; dot = 0; dwidth = 0; ! 717: reswitch: switch (ch = (u_char)*fmt++) { ! 718: case '.': ! 719: dot = 1; ! 720: goto reswitch; ! 721: case '#': ! 722: sharpflag = 1; ! 723: goto reswitch; ! 724: case '+': ! 725: sign = 1; ! 726: goto reswitch; ! 727: case '-': ! 728: ladjust = 1; ! 729: goto reswitch; ! 730: case '%': ! 731: PCHAR(ch); ! 732: break; ! 733: case '*': ! 734: if (!dot) { ! 735: width = va_arg(ap, int); ! 736: if (width < 0) { ! 737: ladjust = !ladjust; ! 738: width = -width; ! 739: } ! 740: } else { ! 741: dwidth = va_arg(ap, int); ! 742: } ! 743: goto reswitch; ! 744: case '0': ! 745: if (!dot) { ! 746: padc = '0'; ! 747: goto reswitch; ! 748: } ! 749: case '1': case '2': case '3': case '4': ! 750: case '5': case '6': case '7': case '8': case '9': ! 751: for (n = 0;; ++fmt) { ! 752: n = n * 10 + ch - '0'; ! 753: ch = *fmt; ! 754: if (ch < '0' || ch > '9') ! 755: break; ! 756: } ! 757: if (dot) ! 758: dwidth = n; ! 759: else ! 760: width = n; ! 761: goto reswitch; ! 762: case 'b': ! 763: ul = va_arg(ap, int); ! 764: p = va_arg(ap, char *); ! 765: for (q = ksprintn(ul, *p++, NULL); *q;) ! 766: PCHAR(*q--); ! 767: ! 768: if (!ul) ! 769: break; ! 770: ! 771: for (tmp = 0; *p;) { ! 772: n = *p++; ! 773: if (ul & (1 << (n - 1))) { ! 774: PCHAR(tmp ? ',' : '<'); ! 775: for (; (n = *p) > ' '; ++p) ! 776: PCHAR(n); ! 777: tmp = 1; ! 778: } else ! 779: for (; *p > ' '; ++p) ! 780: continue; ! 781: } ! 782: if (tmp) ! 783: PCHAR('>'); ! 784: break; ! 785: case 'c': ! 786: PCHAR(va_arg(ap, int)); ! 787: break; ! 788: case 'D': ! 789: up = va_arg(ap, u_char *); ! 790: p = va_arg(ap, char *); ! 791: if (!width) ! 792: width = 16; ! 793: while(width--) { ! 794: PCHAR(hex2ascii(*up >> 4)); ! 795: PCHAR(hex2ascii(*up & 0x0f)); ! 796: up++; ! 797: if (width) ! 798: for (q=p;*q;q++) ! 799: PCHAR(*q); ! 800: } ! 801: break; ! 802: case 'd': ! 803: ul = lflag ? va_arg(ap, long) : va_arg(ap, int); ! 804: sign = 1; ! 805: base = 10; ! 806: goto number; ! 807: case 'l': ! 808: lflag = 1; ! 809: goto reswitch; ! 810: case 'o': ! 811: ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); ! 812: base = 8; ! 813: goto nosign; ! 814: case 'p': ! 815: ul = (uintptr_t)va_arg(ap, void *); ! 816: base = 16; ! 817: sharpflag = (width == 0); ! 818: goto nosign; ! 819: case 'n': ! 820: case 'r': ! 821: ul = lflag ? va_arg(ap, u_long) : ! 822: sign ? (u_long)va_arg(ap, int) : va_arg(ap, u_int); ! 823: base = radix; ! 824: goto number; ! 825: case 's': ! 826: p = va_arg(ap, char *); ! 827: if (p == NULL) ! 828: p = "(null)"; ! 829: if (!dot) ! 830: n = strlen (p); ! 831: else ! 832: for (n = 0; n < dwidth && p[n]; n++) ! 833: continue; ! 834: ! 835: width -= n; ! 836: ! 837: if (!ladjust && width > 0) ! 838: while (width--) ! 839: PCHAR(padc); ! 840: while (n--) ! 841: PCHAR(*p++); ! 842: if (ladjust && width > 0) ! 843: while (width--) ! 844: PCHAR(padc); ! 845: break; ! 846: case 'u': ! 847: ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); ! 848: base = 10; ! 849: goto nosign; ! 850: case 'x': ! 851: ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); ! 852: base = 16; ! 853: goto nosign; ! 854: case 'z': ! 855: ul = lflag ? va_arg(ap, u_long) : ! 856: sign ? (u_long)va_arg(ap, int) : va_arg(ap, u_int); ! 857: base = 16; ! 858: goto number; ! 859: nosign: sign = 0; ! 860: number: if (sign && (long)ul < 0L) { ! 861: neg = 1; ! 862: ul = -(long)ul; ! 863: } ! 864: p = ksprintn(ul, base, &tmp); ! 865: if (sharpflag && ul != 0) { ! 866: if (base == 8) ! 867: tmp++; ! 868: else if (base == 16) ! 869: tmp += 2; ! 870: } ! 871: if (neg) ! 872: tmp++; ! 873: ! 874: if (!ladjust && width && (width -= tmp) > 0) ! 875: while (width--) ! 876: PCHAR(padc); ! 877: if (neg) ! 878: PCHAR('-'); ! 879: if (sharpflag && ul != 0) { ! 880: if (base == 8) { ! 881: PCHAR('0'); ! 882: } else if (base == 16) { ! 883: PCHAR('0'); ! 884: PCHAR('x'); ! 885: } ! 886: } ! 887: ! 888: while (*p) ! 889: PCHAR(*p--); ! 890: ! 891: if (ladjust && width && (width -= tmp) > 0) ! 892: while (width--) ! 893: PCHAR(padc); ! 894: ! 895: break; ! 896: default: ! 897: PCHAR('%'); ! 898: if (lflag) ! 899: PCHAR('l'); ! 900: PCHAR(ch); ! 901: break; ! 902: } ! 903: } ! 904: #undef PCHAR ! 905: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.