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