1/* $NetBSD: subr_prf.c,v 1.157 2015/02/04 07:10:47 msaitoh Exp $ */ 2 3/*- 4 * Copyright (c) 1986, 1988, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * (c) UNIX System Laboratories, Inc. 7 * All or some portions of this file are derived from material licensed 8 * to the University of California by American Telephone and Telegraph 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 * the permission of UNIX System Laboratories, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)subr_prf.c 8.4 (Berkeley) 5/4/95 37 */ 38 39/* 40 * This is the NetBSD kernel printf code heavily stripped. Format support 41 * is the same, but the wrappers for calling printf have been reduced 42 * down to: 43 * + printf 44 * + snprintf 45 * + vnsprintf 46 */ 47 48#define _BMK_PRINTF_VA 49#include <bmk-core/null.h> 50#include <bmk-core/printf.h> 51#include <bmk-core/string.h> 52 53#define TOBUFONLY 0x01 54#define TOCONS 0x02 55 56#define __UNCONST(x) ((void *)(unsigned long)(x)) 57#define KPRINTF_BUFSIZE (sizeof(long long)*8/3 + 2) 58 59/* 60 * local prototypes 61 */ 62 63static void cons_putchar(int, int); 64static int kprintf(const char *, int, void *, char *, va_list); 65 66/* 67 * globals 68 */ 69 70static void 71nullfun(void) 72{ 73 74 return; 75} 76 77static void (*v_flush)(void); 78static void (*v_putc)(int); 79 80void 81bmk_printf_init(void (*putc)(int), void (*flush)(void)) 82{ 83 84 if (putc == NULL) 85 putc = (void *)nullfun; 86 v_putc = putc; 87 if (flush == NULL) 88 flush = nullfun; 89 v_flush = flush; 90} 91 92static const char hexdigits[] = "0123456789abcdef"; 93static const char HEXDIGITS[] = "0123456789ABCDEF"; 94 95/* 96 * functions 97 */ 98 99/* dmesg ring buffer */ 100#ifndef BMK_DMESG_SIZE 101#define BMK_DMESG_SIZE (16*1024) 102#endif 103char bmk_dmesg[BMK_DMESG_SIZE]; 104static int bmk_dmesgoff; 105 106/* 107 * putchar: print a single character on console or user terminal. 108 * 109 * => if console, then the last MSGBUFS chars are saved in msgbuf 110 * for inspection later (e.g. dmesg/syslog) 111 * => we must already be in the mutex! 112 */ 113static void 114cons_putchar(int c, int flags) 115{ 116 117 bmk_dmesg[bmk_dmesgoff] = c; 118 if (++bmk_dmesgoff == sizeof(bmk_dmesg)-1) 119 bmk_dmesgoff = 0; 120 (*v_putc)(c); 121} 122 123static void 124kprintf_lock(void) 125{ 126 127 /* XXX */ 128} 129 130static void 131kprintf_unlock(void) 132{ 133 134 /* XXX */ 135} 136 137/* 138 * bmk_printf: print a message to the console 139 */ 140void 141bmk_printf(const char *fmt, ...) 142{ 143 va_list ap; 144 145 kprintf_lock(); 146 147 va_start(ap, fmt); 148 kprintf(fmt, TOCONS, NULL, NULL, ap); 149 va_end(ap); 150 151 kprintf_unlock(); 152} 153 154/* 155 * bmk_vprintf: print a message to the console [already have 156 * va_list] 157 */ 158void 159bmk_vprintf(const char *fmt, va_list ap) 160{ 161 kprintf_lock(); 162 163 kprintf(fmt, TOCONS, NULL, NULL, ap); 164 165 kprintf_unlock(); 166} 167 168/* 169 * bmk_snprintf: print a message to a buffer 170 */ 171int 172bmk_snprintf(char *bf, unsigned long size, const char *fmt, ...) 173{ 174 int retval; 175 va_list ap; 176 177 va_start(ap, fmt); 178 retval = bmk_vsnprintf(bf, size, fmt, ap); 179 va_end(ap); 180 181 return retval; 182} 183 184void bmk_putchar(char c) { 185 cons_putchar(c, 0); 186} 187 188/* 189 * bmk_vsnprintf: print a message to a buffer [already have va_list] 190 */ 191int 192bmk_vsnprintf(char *bf, unsigned long size, const char *fmt, va_list ap) 193{ 194 int retval; 195 char *p; 196 197 p = bf + size; 198 retval = kprintf(fmt, TOBUFONLY, &p, bf, ap); 199 if (bf && size > 0) { 200 /* nul terminate */ 201 if (size <= (unsigned long)retval) 202 bf[size - 1] = '\0'; 203 else 204 bf[retval] = '\0'; 205 } 206 return retval; 207} 208 209/* 210 * kprintf: scaled down version of printf(3). 211 * 212 * this version based on vfprintf() from libc which was derived from 213 * software contributed to Berkeley by Chris Torek. 214 * 215 * NOTE: The kprintf mutex must be held if we're going TOBUF or TOCONS! 216 */ 217 218/* 219 * macros for converting digits to letters and vice versa 220 */ 221#define to_digit(c) ((c) - '0') 222#define is_digit(c) ((unsigned)to_digit(c) <= 9) 223#define to_char(n) ((n) + '0') 224 225/* 226 * flags used during conversion. 227 */ 228#define ALT 0x001 /* alternate form */ 229#define HEXPREFIX 0x002 /* add 0x or 0X prefix */ 230#define LADJUST 0x004 /* left adjustment */ 231#define LONGDBL 0x008 /* long double; unimplemented */ 232#define LONGINT 0x010 /* long integer */ 233#define QUADINT 0x020 /* quad integer */ 234#define SHORTINT 0x040 /* short integer */ 235#define MAXINT 0x080 /* intmax_t */ 236#define PTRINT 0x100 /* intptr_t */ 237#define SIZEINT 0x200 /* size_t */ 238#define ZEROPAD 0x400 /* zero (as opposed to blank) pad */ 239#define FPT 0x800 /* Floating point number */ 240 241 /* 242 * To extend shorts properly, we need both signed and unsigned 243 * argument extraction methods. 244 */ 245#define SARG() \ 246 (flags&MAXINT ? va_arg(ap, long long) : \ 247 flags&PTRINT ? va_arg(ap, long) : \ 248 flags&SIZEINT ? va_arg(ap, long) : /* XXX */ \ 249 flags&QUADINT ? va_arg(ap, long long) : \ 250 flags&LONGINT ? va_arg(ap, long) : \ 251 flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ 252 (long)va_arg(ap, int)) 253#define UARG() \ 254 (flags&MAXINT ? va_arg(ap, unsigned long long) : \ 255 flags&PTRINT ? va_arg(ap, unsigned long) : \ 256 flags&SIZEINT ? va_arg(ap, unsigned long) : \ 257 flags&QUADINT ? va_arg(ap, unsigned long long) : \ 258 flags&LONGINT ? va_arg(ap, unsigned long) : \ 259 flags&SHORTINT ? (unsigned long)(unsigned long)va_arg(ap, int) : \ 260 (unsigned long)va_arg(ap, unsigned int)) 261 262#define KPRINTF_PUTCHAR(C) { \ 263 if (oflags == TOBUFONLY) { \ 264 if (sbuf && ((vp == NULL) || (sbuf < tailp))) \ 265 *sbuf++ = (C); \ 266 } else { \ 267 cons_putchar((C), oflags); \ 268 } \ 269} 270 271/* 272 * Guts of kernel printf. Note, we already expect to be in a mutex! 273 */ 274static int 275kprintf(const char *fmt0, int oflags, void *vp, char *sbuf, va_list ap) 276{ 277 int ret = 0; /* return value accumulator */ 278 const char *fmt; /* format string */ 279 int ch; /* character from fmt */ 280 int n; /* handy integer (short term usage) */ 281 char *cp; /* handy char pointer (short term usage) */ 282 int flags; /* flags as above */ 283 int width; /* width from format (%8d), or 0 */ 284 int prec; /* precision from format (%.3d), or -1 */ 285 char sign; /* sign prefix (' ', '+', '-', or \0) */ 286 287 unsigned long long _uquad; /* integer arguments %[diouxX] */ 288 enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ 289 int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 290 int realsz; /* field size expanded by dprec */ 291 int size; /* size of converted field or string */ 292 const char *xdigs; /* digits for [xX] conversion */ 293 char bf[KPRINTF_BUFSIZE]; /* space for %c, %[diouxX] */ 294 char *tailp; /* tail pointer for snprintf */ 295 296 if (oflags == TOBUFONLY && (vp != NULL)) 297 tailp = *(char **)vp; 298 else 299 tailp = NULL; 300 301 cp = NULL; /* XXX: shutup gcc */ 302 size = 0; /* XXX: shutup gcc */ 303 304 fmt = fmt0; 305 ret = 0; 306 307 xdigs = NULL; /* XXX: shut up gcc warning */ 308 309 /* 310 * Scan the format for conversions (`%' character). 311 */ 312 for (;;) { 313 for (; *fmt != '%' && *fmt; fmt++) { 314 ret++; 315 KPRINTF_PUTCHAR(*fmt); 316 } 317 if (*fmt == 0) 318 goto done; 319 320 fmt++; /* skip over '%' */ 321 322 flags = 0; 323 dprec = 0; 324 width = 0; 325 prec = -1; 326 sign = '\0'; 327 328rflag: ch = *fmt++; 329reswitch: switch (ch) { 330 case ' ': 331 /* 332 * ``If the space and + flags both appear, the space 333 * flag will be ignored.'' 334 * -- ANSI X3J11 335 */ 336 if (!sign) 337 sign = ' '; 338 goto rflag; 339 case '#': 340 flags |= ALT; 341 goto rflag; 342 case '*': 343 /* 344 * ``A negative field width argument is taken as a 345 * - flag followed by a positive field width.'' 346 * -- ANSI X3J11 347 * They don't exclude field widths read from args. 348 */ 349 if ((width = va_arg(ap, int)) >= 0) 350 goto rflag; 351 width = -width; 352 /* FALLTHROUGH */ 353 case '-': 354 flags |= LADJUST; 355 goto rflag; 356 case '+': 357 sign = '+'; 358 goto rflag; 359 case '.': 360 if ((ch = *fmt++) == '*') { 361 n = va_arg(ap, int); 362 prec = n < 0 ? -1 : n; 363 goto rflag; 364 } 365 n = 0; 366 while (is_digit(ch)) { 367 n = 10 * n + to_digit(ch); 368 ch = *fmt++; 369 } 370 prec = n < 0 ? -1 : n; 371 goto reswitch; 372 case '0': 373 /* 374 * ``Note that 0 is taken as a flag, not as the 375 * beginning of a field width.'' 376 * -- ANSI X3J11 377 */ 378 flags |= ZEROPAD; 379 goto rflag; 380 case '1': case '2': case '3': case '4': 381 case '5': case '6': case '7': case '8': case '9': 382 n = 0; 383 do { 384 n = 10 * n + to_digit(ch); 385 ch = *fmt++; 386 } while (is_digit(ch)); 387 width = n; 388 goto reswitch; 389 case 'h': 390 flags |= SHORTINT; 391 goto rflag; 392 case 'j': 393 flags |= MAXINT; 394 goto rflag; 395 case 'l': 396 if (*fmt == 'l') { 397 fmt++; 398 flags |= QUADINT; 399 } else { 400 flags |= LONGINT; 401 } 402 goto rflag; 403 case 'q': 404 flags |= QUADINT; 405 goto rflag; 406 case 't': 407 flags |= PTRINT; 408 goto rflag; 409 case 'z': 410 flags |= SIZEINT; 411 goto rflag; 412 case 'c': 413 *(cp = bf) = va_arg(ap, int); 414 size = 1; 415 sign = '\0'; 416 break; 417 case 'D': 418 flags |= LONGINT; 419 /*FALLTHROUGH*/ 420 case 'd': 421 case 'i': 422 _uquad = SARG(); 423 if ((long long)_uquad < 0) { 424 _uquad = -_uquad; 425 sign = '-'; 426 } 427 base = DEC; 428 goto number; 429 case 'n': 430 if (flags & MAXINT) 431 *va_arg(ap, long long *) = ret; 432 else if (flags & PTRINT) 433 *va_arg(ap, long *) = ret; 434 else if (flags & SIZEINT) 435 *va_arg(ap, long *) = ret; 436 else if (flags & QUADINT) 437 *va_arg(ap, long long *) = ret; 438 else if (flags & LONGINT) 439 *va_arg(ap, long *) = ret; 440 else if (flags & SHORTINT) 441 *va_arg(ap, short *) = ret; 442 else 443 *va_arg(ap, int *) = ret; 444 continue; /* no output */ 445 case 'O': 446 flags |= LONGINT; 447 /*FALLTHROUGH*/ 448 case 'o': 449 _uquad = UARG(); 450 base = OCT; 451 goto nosign; 452 case 'p': 453 /* 454 * ``The argument shall be a pointer to void. The 455 * value of the pointer is converted to a sequence 456 * of printable characters, in an implementation- 457 * defined manner.'' 458 * -- ANSI X3J11 459 */ 460 /* NOSTRICT */ 461 _uquad = (unsigned long)va_arg(ap, void *); 462 base = HEX; 463 xdigs = hexdigits; 464 flags |= HEXPREFIX; 465 ch = 'x'; 466 goto nosign; 467 case 's': 468 if ((cp = va_arg(ap, char *)) == NULL) 469 /*XXXUNCONST*/ 470 cp = __UNCONST("(null)"); 471 if (prec >= 0) { 472 /* 473 * can't use strlen; can only look for the 474 * NUL in the first `prec' characters, and 475 * strlen() will go further. 476 */ 477 char *p = bmk_memchr(cp, 0, prec); 478 479 if (p != NULL) { 480 size = p - cp; 481 if (size > prec) 482 size = prec; 483 } else 484 size = prec; 485 } else 486 size = bmk_strlen(cp); 487 sign = '\0'; 488 break; 489 case 'U': 490 flags |= LONGINT; 491 /*FALLTHROUGH*/ 492 case 'u': 493 _uquad = UARG(); 494 base = DEC; 495 goto nosign; 496 case 'X': 497 xdigs = HEXDIGITS; 498 goto hex; 499 case 'x': 500 xdigs = hexdigits; 501hex: _uquad = UARG(); 502 base = HEX; 503 /* leading 0x/X only if non-zero */ 504 if (flags & ALT && _uquad != 0) 505 flags |= HEXPREFIX; 506 507 /* unsigned conversions */ 508nosign: sign = '\0'; 509 /* 510 * ``... diouXx conversions ... if a precision is 511 * specified, the 0 flag will be ignored.'' 512 * -- ANSI X3J11 513 */ 514number: if ((dprec = prec) >= 0) 515 flags &= ~ZEROPAD; 516 517 /* 518 * ``The result of converting a zero value with an 519 * explicit precision of zero is no characters.'' 520 * -- ANSI X3J11 521 */ 522 cp = bf + KPRINTF_BUFSIZE; 523 if (_uquad != 0 || prec != 0) { 524 /* 525 * Unsigned mod is hard, and unsigned mod 526 * by a constant is easier than that by 527 * a variable; hence this switch. 528 */ 529 switch (base) { 530 case OCT: 531 do { 532 *--cp = to_char(_uquad & 7); 533 _uquad >>= 3; 534 } while (_uquad); 535 /* handle octal leading 0 */ 536 if (flags & ALT && *cp != '0') 537 *--cp = '0'; 538 break; 539 540 case DEC: 541 /* many numbers are 1 digit */ 542 while (_uquad >= 10) { 543 *--cp = to_char(_uquad % 10); 544 _uquad /= 10; 545 } 546 *--cp = to_char(_uquad); 547 break; 548 549 case HEX: 550 do { 551 *--cp = xdigs[_uquad & 15]; 552 _uquad >>= 4; 553 } while (_uquad); 554 break; 555 556 default: 557 /*XXXUNCONST*/ 558 cp = __UNCONST("bug in kprintf: bad base"); 559 size = bmk_strlen(cp); 560 goto skipsize; 561 } 562 } 563 size = bf + KPRINTF_BUFSIZE - cp; 564 skipsize: 565 break; 566 default: /* "%?" prints ?, unless ? is NUL */ 567 if (ch == '\0') 568 goto done; 569 /* pretend it was %c with argument ch */ 570 cp = bf; 571 *cp = ch; 572 size = 1; 573 sign = '\0'; 574 break; 575 } 576 577 /* 578 * All reasonable formats wind up here. At this point, `cp' 579 * points to a string which (if not flags&LADJUST) should be 580 * padded out to `width' places. If flags&ZEROPAD, it should 581 * first be prefixed by any sign or other prefix; otherwise, 582 * it should be blank padded before the prefix is emitted. 583 * After any left-hand padding and prefixing, emit zeroes 584 * required by a decimal [diouxX] precision, then print the 585 * string proper, then emit zeroes required by any leftover 586 * floating precision; finally, if LADJUST, pad with blanks. 587 * 588 * Compute actual size, so we know how much to pad. 589 * size excludes decimal prec; realsz includes it. 590 */ 591 realsz = dprec > size ? dprec : size; 592 if (sign) 593 realsz++; 594 else if (flags & HEXPREFIX) 595 realsz+= 2; 596 597 /* adjust ret */ 598 ret += width > realsz ? width : realsz; 599 600 /* right-adjusting blank padding */ 601 if ((flags & (LADJUST|ZEROPAD)) == 0) { 602 n = width - realsz; 603 while (n-- > 0) 604 KPRINTF_PUTCHAR(' '); 605 } 606 607 /* prefix */ 608 if (sign) { 609 KPRINTF_PUTCHAR(sign); 610 } else if (flags & HEXPREFIX) { 611 KPRINTF_PUTCHAR('0'); 612 KPRINTF_PUTCHAR(ch); 613 } 614 615 /* right-adjusting zero padding */ 616 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) { 617 n = width - realsz; 618 while (n-- > 0) 619 KPRINTF_PUTCHAR('0'); 620 } 621 622 /* leading zeroes from decimal precision */ 623 n = dprec - size; 624 while (n-- > 0) 625 KPRINTF_PUTCHAR('0'); 626 627 /* the string or number proper */ 628 for (; size--; cp++) 629 KPRINTF_PUTCHAR(*cp); 630 /* left-adjusting padding (always blank) */ 631 if (flags & LADJUST) { 632 n = width - realsz; 633 while (n-- > 0) 634 KPRINTF_PUTCHAR(' '); 635 } 636 } 637 638done: 639 if ((oflags == TOBUFONLY) && (vp != NULL)) 640 *(char **)vp = sbuf; 641 (*v_flush)(); 642 643 return ret; 644} 645