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