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 /* 154 * kprintf: scaled down version of printf(3). 155 * 156 * this version based on vfprintf() from libc which was derived from 157 * software contributed to Berkeley by Chris Torek. 158 * 159 */ 160 161 /* 162 * macros for converting digits to letters and vice versa 163 */ 164 #define to_digit(c) ((c) - '0') 165 #define is_digit(c) ((unsigned)to_digit(c) <= 9) 166 #define to_char(n) ((n) + '0') 167 168 /* 169 * flags used during conversion. 170 */ 171 #define ALT 0x001 /* alternate form */ 172 #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ 173 #define LADJUST 0x004 /* left adjustment */ 174 #define LONGDBL 0x008 /* long double; unimplemented */ 175 #define LONGINT 0x010 /* long integer */ 176 #define QUADINT 0x020 /* quad integer */ 177 #define SHORTINT 0x040 /* short integer */ 178 #define MAXINT 0x080 /* intmax_t */ 179 #define PTRINT 0x100 /* intptr_t */ 180 #define SIZEINT 0x200 /* size_t */ 181 #define ZEROPAD 0x400 /* zero (as opposed to blank) pad */ 182 #define FPT 0x800 /* Floating point number */ 183 184 /* 185 * To extend shorts properly, we need both signed and unsigned 186 * argument extraction methods. 187 */ 188 #define SARG() \ 189 (flags&MAXINT ? va_arg(ap, intmax_t) : \ 190 flags&PTRINT ? va_arg(ap, intptr_t) : \ 191 flags&SIZEINT ? va_arg(ap, ssize_t) : /* XXX */ \ 192 flags&QUADINT ? va_arg(ap, int64_t) : \ 193 flags&LONGINT ? va_arg(ap, long) : \ 194 flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ 195 (long)va_arg(ap, int)) 196 #define UARG() \ 197 (flags&MAXINT ? va_arg(ap, uintmax_t) : \ 198 flags&PTRINT ? va_arg(ap, uintptr_t) : \ 199 flags&SIZEINT ? va_arg(ap, size_t) : \ 200 flags&QUADINT ? va_arg(ap, uint64_t) : \ 201 flags&LONGINT ? va_arg(ap, unsigned long) : \ 202 flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \ 203 (unsigned long)va_arg(ap, unsigned int)) 204 205 #define KPRINTF_PUTCHAR(C) { \ 206 if (oflags == TOBUFONLY) { \ 207 if (sbuf && ((vp == NULL) || (sbuf < tailp))) \ 208 *sbuf++ = (C); \ 209 } else { \ 210 putchar((C), oflags, vp); \ 211 } \ 212 } 213 214 static int uuid2str(char *dst, size_t size, void *ptr) 215 { 216 struct { 217 uint32_t lo; 218 uint16_t mid; 219 uint16_t hi_ver; 220 uint8_t seq_n[8]; 221 } *uuid = ptr; 222 223 return snprintk(dst, size, 224 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 225 uuid->lo, uuid->mid, uuid->hi_ver, 226 uuid->seq_n[0], uuid->seq_n[1], 227 uuid->seq_n[2], uuid->seq_n[3], 228 uuid->seq_n[4], uuid->seq_n[5], 229 uuid->seq_n[6], uuid->seq_n[7]); 230 } 231 232 /* 233 * Guts of kernel printf. Note, we already expect to be in a mutex! 234 */ 235 static int 236 kprintf(const char *fmt0, int oflags, void *vp, char *sbuf, va_list ap, 237 bool ext) 238 { 239 const char *fmt; /* format string */ 240 int ch; /* character from fmt */ 241 int n; /* handy integer (short term usage) */ 242 char *cp; /* handy char pointer (short term usage) */ 243 int flags; /* flags as above */ 244 int ret; /* return value accumulator */ 245 int width; /* width from format (%8d), or 0 */ 246 int prec; /* precision from format (%.3d), or -1 */ 247 char sign; /* sign prefix (' ', '+', '-', or \0) */ 248 249 uint64_t _uquad; /* integer arguments %[diouxX] */ 250 enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ 251 int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 252 int realsz; /* field size expanded by dprec */ 253 int size; /* size of converted field or string */ 254 const char *xdigs; /* digits for [xX] conversion */ 255 char bf[KPRINTF_BUFSIZE]; /* space for %c, %[diouxX], possibly %pUl */ 256 char *tailp; /* tail pointer for snprintk */ 257 258 if (oflags == TOBUFONLY && (vp != NULL)) 259 tailp = *(char **)vp; 260 else 261 tailp = NULL; 262 263 cp = NULL; /* XXX: shutup gcc */ 264 size = 0; /* XXX: shutup gcc */ 265 266 fmt = fmt0; 267 ret = 0; 268 269 xdigs = NULL; /* XXX: shut up gcc warning */ 270 271 /* 272 * Scan the format for conversions (`%' character). 273 */ 274 for (;;) { 275 for (; *fmt != '%' && *fmt; fmt++) { 276 ret++; 277 KPRINTF_PUTCHAR(*fmt); 278 } 279 if (*fmt == 0) 280 goto done; 281 282 fmt++; /* skip over '%' */ 283 284 flags = 0; 285 dprec = 0; 286 width = 0; 287 prec = -1; 288 sign = '\0'; 289 290 rflag: ch = *fmt++; 291 reswitch: switch (ch) { 292 case ' ': 293 /* 294 * ``If the space and + flags both appear, the space 295 * flag will be ignored.'' 296 * -- ANSI X3J11 297 */ 298 if (!sign) 299 sign = ' '; 300 goto rflag; 301 case '#': 302 flags |= ALT; 303 goto rflag; 304 case '*': 305 /* 306 * ``A negative field width argument is taken as a 307 * - flag followed by a positive field width.'' 308 * -- ANSI X3J11 309 * They don't exclude field widths read from args. 310 */ 311 if ((width = va_arg(ap, int)) >= 0) 312 goto rflag; 313 width = -width; 314 /* FALLTHROUGH */ 315 case '-': 316 flags |= LADJUST; 317 goto rflag; 318 case '+': 319 sign = '+'; 320 goto rflag; 321 case '.': 322 if ((ch = *fmt++) == '*') { 323 n = va_arg(ap, int); 324 prec = n < 0 ? -1 : n; 325 goto rflag; 326 } 327 n = 0; 328 while (is_digit(ch)) { 329 n = 10 * n + to_digit(ch); 330 ch = *fmt++; 331 } 332 prec = n < 0 ? -1 : n; 333 goto reswitch; 334 case '0': 335 /* 336 * ``Note that 0 is taken as a flag, not as the 337 * beginning of a field width.'' 338 * -- ANSI X3J11 339 */ 340 flags |= ZEROPAD; 341 goto rflag; 342 case '1': case '2': case '3': case '4': 343 case '5': case '6': case '7': case '8': case '9': 344 n = 0; 345 do { 346 n = 10 * n + to_digit(ch); 347 ch = *fmt++; 348 } while (is_digit(ch)); 349 width = n; 350 goto reswitch; 351 case 'h': 352 flags |= SHORTINT; 353 goto rflag; 354 case 'j': 355 flags |= MAXINT; 356 goto rflag; 357 case 'l': 358 if (*fmt == 'l') { 359 fmt++; 360 flags |= QUADINT; 361 } else { 362 flags |= LONGINT; 363 } 364 goto rflag; 365 case 'q': 366 flags |= QUADINT; 367 goto rflag; 368 case 't': 369 flags |= PTRINT; 370 goto rflag; 371 case 'z': 372 flags |= SIZEINT; 373 goto rflag; 374 case 'c': 375 *(cp = bf) = va_arg(ap, int); 376 size = 1; 377 sign = '\0'; 378 break; 379 case 'D': 380 flags |= LONGINT; 381 /*FALLTHROUGH*/ 382 case 'd': 383 case 'i': 384 _uquad = SARG(); 385 if ((int64_t)_uquad < 0) { 386 _uquad = -_uquad; 387 sign = '-'; 388 } 389 base = DEC; 390 goto number; 391 case 'n': 392 if (flags & MAXINT) 393 *va_arg(ap, intmax_t *) = ret; 394 else if (flags & PTRINT) 395 *va_arg(ap, intptr_t *) = ret; 396 else if (flags & SIZEINT) 397 *va_arg(ap, ssize_t *) = ret; 398 else if (flags & QUADINT) 399 *va_arg(ap, int64_t *) = ret; 400 else if (flags & LONGINT) 401 *va_arg(ap, long *) = ret; 402 else if (flags & SHORTINT) 403 *va_arg(ap, short *) = ret; 404 else 405 *va_arg(ap, int *) = ret; 406 continue; /* no output */ 407 case 'O': 408 flags |= LONGINT; 409 /*FALLTHROUGH*/ 410 case 'o': 411 _uquad = UARG(); 412 base = OCT; 413 goto nosign; 414 case 'p': 415 if (ext && *fmt == 'U' && *(fmt+1) == 'l') { 416 /* 417 * Non-standard format available in [v]snprintk 418 * only 419 */ 420 fmt += 2; 421 size = uuid2str(bf, sizeof(bf), 422 va_arg(ap, void *)); 423 cp = bf; 424 sign = '\0'; 425 break; 426 } 427 /* 428 * ``The argument shall be a pointer to void. The 429 * value of the pointer is converted to a sequence 430 * of printable characters, in an implementation- 431 * defined manner.'' 432 * -- ANSI X3J11 433 */ 434 /* NOSTRICT */ 435 _uquad = (unsigned long)va_arg(ap, void *); 436 base = HEX; 437 xdigs = hexdigits; 438 flags |= HEXPREFIX; 439 ch = 'x'; 440 goto nosign; 441 case 's': 442 if ((cp = va_arg(ap, char *)) == NULL) 443 /*XXXUNCONST*/ 444 cp = __UNCONST("(null)"); 445 if (prec >= 0) { 446 /* 447 * can't use strlen; can only look for the 448 * NUL in the first `prec' characters, and 449 * strlen() will go further. 450 */ 451 char *p = memchr(cp, 0, prec); 452 453 if (p != NULL) { 454 size = p - cp; 455 if (size > prec) 456 size = prec; 457 } else 458 size = prec; 459 } else 460 size = strlen(cp); 461 sign = '\0'; 462 break; 463 case 'U': 464 flags |= LONGINT; 465 /*FALLTHROUGH*/ 466 case 'u': 467 _uquad = UARG(); 468 base = DEC; 469 goto nosign; 470 case 'X': 471 xdigs = HEXDIGITS; 472 goto hex; 473 case 'x': 474 xdigs = hexdigits; 475 hex: _uquad = UARG(); 476 base = HEX; 477 /* leading 0x/X only if non-zero */ 478 if (flags & ALT && _uquad != 0) 479 flags |= HEXPREFIX; 480 481 /* unsigned conversions */ 482 nosign: sign = '\0'; 483 /* 484 * ``... diouXx conversions ... if a precision is 485 * specified, the 0 flag will be ignored.'' 486 * -- ANSI X3J11 487 */ 488 number: if ((dprec = prec) >= 0) 489 flags &= ~ZEROPAD; 490 491 /* 492 * ``The result of converting a zero value with an 493 * explicit precision of zero is no characters.'' 494 * -- ANSI X3J11 495 */ 496 cp = bf + KPRINTF_BUFSIZE; 497 if (_uquad != 0 || prec != 0) { 498 /* 499 * Unsigned mod is hard, and unsigned mod 500 * by a constant is easier than that by 501 * a variable; hence this switch. 502 */ 503 switch (base) { 504 case OCT: 505 do { 506 *--cp = to_char(_uquad & 7); 507 _uquad >>= 3; 508 } while (_uquad); 509 /* handle octal leading 0 */ 510 if (flags & ALT && *cp != '0') 511 *--cp = '0'; 512 break; 513 514 case DEC: 515 /* many numbers are 1 digit */ 516 while (_uquad >= 10) { 517 *--cp = to_char(_uquad % 10); 518 _uquad /= 10; 519 } 520 *--cp = to_char(_uquad); 521 break; 522 523 case HEX: 524 do { 525 *--cp = xdigs[_uquad & 15]; 526 _uquad >>= 4; 527 } while (_uquad); 528 break; 529 530 default: 531 /*XXXUNCONST*/ 532 cp = __UNCONST("bug in kprintf: bad base"); 533 size = strlen(cp); 534 goto skipsize; 535 } 536 } 537 size = bf + KPRINTF_BUFSIZE - cp; 538 skipsize: 539 break; 540 default: /* "%?" prints ?, unless ? is NUL */ 541 if (ch == '\0') 542 goto done; 543 /* pretend it was %c with argument ch */ 544 cp = bf; 545 *cp = ch; 546 size = 1; 547 sign = '\0'; 548 break; 549 } 550 551 /* 552 * All reasonable formats wind up here. At this point, `cp' 553 * points to a string which (if not flags&LADJUST) should be 554 * padded out to `width' places. If flags&ZEROPAD, it should 555 * first be prefixed by any sign or other prefix; otherwise, 556 * it should be blank padded before the prefix is emitted. 557 * After any left-hand padding and prefixing, emit zeroes 558 * required by a decimal [diouxX] precision, then print the 559 * string proper, then emit zeroes required by any leftover 560 * floating precision; finally, if LADJUST, pad with blanks. 561 * 562 * Compute actual size, so we know how much to pad. 563 * size excludes decimal prec; realsz includes it. 564 */ 565 realsz = dprec > size ? dprec : size; 566 if (sign) 567 realsz++; 568 else if (flags & HEXPREFIX) 569 realsz+= 2; 570 571 /* adjust ret */ 572 ret += width > realsz ? width : realsz; 573 574 /* right-adjusting blank padding */ 575 if ((flags & (LADJUST|ZEROPAD)) == 0) { 576 n = width - realsz; 577 while (n-- > 0) 578 KPRINTF_PUTCHAR(' '); 579 } 580 581 /* prefix */ 582 if (sign) { 583 KPRINTF_PUTCHAR(sign); 584 } else if (flags & HEXPREFIX) { 585 KPRINTF_PUTCHAR('0'); 586 KPRINTF_PUTCHAR(ch); 587 } 588 589 /* right-adjusting zero padding */ 590 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) { 591 n = width - realsz; 592 while (n-- > 0) 593 KPRINTF_PUTCHAR('0'); 594 } 595 596 /* leading zeroes from decimal precision */ 597 n = dprec - size; 598 while (n-- > 0) 599 KPRINTF_PUTCHAR('0'); 600 601 /* the string or number proper */ 602 for (; size--; cp++) 603 KPRINTF_PUTCHAR(*cp); 604 /* left-adjusting padding (always blank) */ 605 if (flags & LADJUST) { 606 n = width - realsz; 607 while (n-- > 0) 608 KPRINTF_PUTCHAR(' '); 609 } 610 } 611 612 done: 613 if ((oflags == TOBUFONLY) && (vp != NULL)) 614 *(char **)vp = sbuf; 615 return ret; 616 } 617