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