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