1 /*- 2 * Copyright (c) 1986, 1988, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 35 */ 36 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 /* 41 * Standaloneified version of the FreeBSD kernel printf family. 42 */ 43 44 #include <sys/types.h> 45 #include <sys/stddef.h> 46 #include <sys/stdint.h> 47 #include <limits.h> 48 #include <string.h> 49 #include "stand.h" 50 51 /* 52 * Note that stdarg.h and the ANSI style va_start macro is used for both 53 * ANSI and traditional C compilers. 54 */ 55 #include <machine/stdarg.h> 56 57 #define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1) 58 59 typedef void (kvprintf_fn_t)(int, void *); 60 61 static char *ksprintn (char *buf, uintmax_t num, int base, int *len, int upper); 62 static int kvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap); 63 64 static void 65 putchar_wrapper(int cc, void *arg) 66 { 67 68 putchar(cc); 69 } 70 71 int 72 printf(const char *fmt, ...) 73 { 74 va_list ap; 75 int retval; 76 77 va_start(ap, fmt); 78 retval = kvprintf(fmt, putchar_wrapper, NULL, 10, ap); 79 va_end(ap); 80 return retval; 81 } 82 83 int 84 vprintf(const char *fmt, va_list ap) 85 { 86 87 return (kvprintf(fmt, putchar_wrapper, NULL, 10, ap)); 88 } 89 90 int 91 sprintf(char *buf, const char *cfmt, ...) 92 { 93 int retval; 94 va_list ap; 95 96 va_start(ap, cfmt); 97 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 98 buf[retval] = '\0'; 99 va_end(ap); 100 return retval; 101 } 102 103 struct print_buf { 104 char *buf; 105 size_t size; 106 }; 107 108 static void 109 snprint_func(int ch, void *arg) 110 { 111 struct print_buf *pbuf = arg; 112 113 if (pbuf->size < 2) { 114 /* 115 * Reserve last buffer position for the terminating 116 * character: 117 */ 118 return; 119 } 120 *(pbuf->buf)++ = ch; 121 pbuf->size--; 122 } 123 124 int 125 asprintf(char **buf, const char *cfmt, ...) 126 { 127 int retval; 128 struct print_buf arg; 129 va_list ap; 130 131 *buf = NULL; 132 va_start(ap, cfmt); 133 retval = kvprintf(cfmt, NULL, NULL, 10, ap); 134 va_end(ap); 135 if (retval <= 0) 136 return (-1); 137 138 arg.size = retval + 1; 139 arg.buf = *buf = malloc(arg.size); 140 if (*buf == NULL) 141 return (-1); 142 143 va_start(ap, cfmt); 144 retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap); 145 va_end(ap); 146 147 if (arg.size >= 1) 148 *(arg.buf)++ = 0; 149 return (retval); 150 } 151 152 int 153 snprintf(char *buf, size_t size, const char *cfmt, ...) 154 { 155 int retval; 156 va_list ap; 157 struct print_buf arg; 158 159 arg.buf = buf; 160 arg.size = size; 161 162 va_start(ap, cfmt); 163 retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap); 164 va_end(ap); 165 166 if (arg.size >= 1) 167 *(arg.buf)++ = 0; 168 return retval; 169 } 170 171 int 172 vsnprintf(char *buf, size_t size, const char *cfmt, va_list ap) 173 { 174 struct print_buf arg; 175 int retval; 176 177 arg.buf = buf; 178 arg.size = size; 179 180 retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap); 181 182 if (arg.size >= 1) 183 *(arg.buf)++ = 0; 184 185 return (retval); 186 } 187 188 int 189 vsprintf(char *buf, const char *cfmt, va_list ap) 190 { 191 int retval; 192 193 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 194 buf[retval] = '\0'; 195 196 return (retval); 197 } 198 199 /* 200 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse 201 * order; return an optional length and a pointer to the last character 202 * written in the buffer (i.e., the first character of the string). 203 * The buffer pointed to by `nbuf' must have length >= MAXNBUF. 204 */ 205 static char * 206 ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) 207 { 208 char *p, c; 209 210 p = nbuf; 211 *p = '\0'; 212 do { 213 c = hex2ascii(num % base); 214 *++p = upper ? toupper(c) : c; 215 } while (num /= base); 216 if (lenp) 217 *lenp = p - nbuf; 218 return (p); 219 } 220 221 /* 222 * Scaled down version of printf(3). 223 * 224 * Two additional formats: 225 * 226 * The format %b is supported to decode error registers. 227 * Its usage is: 228 * 229 * printf("reg=%b\n", regval, "<base><arg>*"); 230 * 231 * where <base> is the output base expressed as a control character, e.g. 232 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 233 * the first of which gives the bit number to be inspected (origin 1), and 234 * the next characters (up to a control character, i.e. a character <= 32), 235 * give the name of the register. Thus: 236 * 237 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE"); 238 * 239 * would produce output: 240 * 241 * reg=3<BITTWO,BITONE> 242 * 243 * XXX: %D -- Hexdump, takes pointer and separator string: 244 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX 245 * ("%*D", len, ptr, " " -> XX XX XX XX ... 246 */ 247 static int 248 kvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap) 249 { 250 #define PCHAR(c) { \ 251 int cc = (c); \ 252 \ 253 if (func) { \ 254 (*func)(cc, arg); \ 255 } else if (d != NULL) { \ 256 *d++ = cc; \ 257 } \ 258 retval++; \ 259 } 260 261 char nbuf[MAXNBUF]; 262 char *d; 263 const char *p, *percent, *q; 264 uint16_t *S; 265 u_char *up; 266 int ch, n; 267 uintmax_t num; 268 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 269 int cflag, hflag, jflag, tflag, zflag; 270 int dwidth, upper; 271 char padc; 272 int stop = 0, retval = 0; 273 274 TSENTER(); 275 num = 0; 276 if (!func) 277 d = (char *) arg; 278 else 279 d = NULL; 280 281 if (fmt == NULL) 282 fmt = "(fmt null)\n"; 283 284 if (radix < 2 || radix > 36) 285 radix = 10; 286 287 for (;;) { 288 padc = ' '; 289 width = 0; 290 while ((ch = (u_char)*fmt++) != '%' || stop) { 291 if (ch == '\0') { 292 TSEXIT(); 293 return (retval); 294 } 295 PCHAR(ch); 296 } 297 percent = fmt - 1; 298 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 299 sign = 0; dot = 0; dwidth = 0; upper = 0; 300 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; 301 reswitch: switch (ch = (u_char)*fmt++) { 302 case '.': 303 dot = 1; 304 goto reswitch; 305 case '#': 306 sharpflag = 1; 307 goto reswitch; 308 case '+': 309 sign = 1; 310 goto reswitch; 311 case '-': 312 ladjust = 1; 313 goto reswitch; 314 case '%': 315 PCHAR(ch); 316 break; 317 case '*': 318 if (!dot) { 319 width = va_arg(ap, int); 320 if (width < 0) { 321 ladjust = !ladjust; 322 width = -width; 323 } 324 } else { 325 dwidth = va_arg(ap, int); 326 } 327 goto reswitch; 328 case '0': 329 if (!dot) { 330 padc = '0'; 331 goto reswitch; 332 } 333 case '1': case '2': case '3': case '4': 334 case '5': case '6': case '7': case '8': case '9': 335 for (n = 0;; ++fmt) { 336 n = n * 10 + ch - '0'; 337 ch = *fmt; 338 if (ch < '0' || ch > '9') 339 break; 340 } 341 if (dot) 342 dwidth = n; 343 else 344 width = n; 345 goto reswitch; 346 case 'b': 347 num = (u_int)va_arg(ap, int); 348 p = va_arg(ap, char *); 349 for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) 350 PCHAR(*q--); 351 352 if (num == 0) 353 break; 354 355 for (tmp = 0; *p;) { 356 n = *p++; 357 if (num & (1 << (n - 1))) { 358 PCHAR(tmp ? ',' : '<'); 359 for (; (n = *p) > ' '; ++p) 360 PCHAR(n); 361 tmp = 1; 362 } else 363 for (; *p > ' '; ++p) 364 continue; 365 } 366 if (tmp) 367 PCHAR('>'); 368 break; 369 case 'c': 370 PCHAR(va_arg(ap, int)); 371 break; 372 case 'D': 373 up = va_arg(ap, u_char *); 374 p = va_arg(ap, char *); 375 if (!width) 376 width = 16; 377 while(width--) { 378 PCHAR(hex2ascii(*up >> 4)); 379 PCHAR(hex2ascii(*up & 0x0f)); 380 up++; 381 if (width) 382 for (q=p;*q;q++) 383 PCHAR(*q); 384 } 385 break; 386 case 'd': 387 case 'i': 388 base = 10; 389 sign = 1; 390 goto handle_sign; 391 case 'h': 392 if (hflag) { 393 hflag = 0; 394 cflag = 1; 395 } else 396 hflag = 1; 397 goto reswitch; 398 case 'j': 399 jflag = 1; 400 goto reswitch; 401 case 'l': 402 if (lflag) { 403 lflag = 0; 404 qflag = 1; 405 } else 406 lflag = 1; 407 goto reswitch; 408 case 'n': 409 if (jflag) 410 *(va_arg(ap, intmax_t *)) = retval; 411 else if (qflag) 412 *(va_arg(ap, quad_t *)) = retval; 413 else if (lflag) 414 *(va_arg(ap, long *)) = retval; 415 else if (zflag) 416 *(va_arg(ap, size_t *)) = retval; 417 else if (hflag) 418 *(va_arg(ap, short *)) = retval; 419 else if (cflag) 420 *(va_arg(ap, char *)) = retval; 421 else 422 *(va_arg(ap, int *)) = retval; 423 break; 424 case 'o': 425 base = 8; 426 goto handle_nosign; 427 case 'p': 428 base = 16; 429 sharpflag = (width == 0); 430 sign = 0; 431 num = (uintptr_t)va_arg(ap, void *); 432 goto number; 433 case 'q': 434 qflag = 1; 435 goto reswitch; 436 case 'r': 437 base = radix; 438 if (sign) 439 goto handle_sign; 440 goto handle_nosign; 441 case 's': 442 p = va_arg(ap, char *); 443 if (p == NULL) 444 p = "(null)"; 445 if (!dot) 446 n = strlen (p); 447 else 448 for (n = 0; n < dwidth && p[n]; n++) 449 continue; 450 451 width -= n; 452 453 if (!ladjust && width > 0) 454 while (width--) 455 PCHAR(padc); 456 while (n--) 457 PCHAR(*p++); 458 if (ladjust && width > 0) 459 while (width--) 460 PCHAR(padc); 461 break; 462 case 'S': /* Assume console can cope with wide chars */ 463 for (S = va_arg(ap, uint16_t *); *S != 0; S++) 464 PCHAR(*S); 465 break; 466 case 't': 467 tflag = 1; 468 goto reswitch; 469 case 'u': 470 base = 10; 471 goto handle_nosign; 472 case 'X': 473 upper = 1; 474 case 'x': 475 base = 16; 476 goto handle_nosign; 477 case 'y': 478 base = 16; 479 sign = 1; 480 goto handle_sign; 481 case 'z': 482 zflag = 1; 483 goto reswitch; 484 handle_nosign: 485 sign = 0; 486 if (jflag) 487 num = va_arg(ap, uintmax_t); 488 else if (qflag) 489 num = va_arg(ap, u_quad_t); 490 else if (tflag) 491 num = va_arg(ap, ptrdiff_t); 492 else if (lflag) 493 num = va_arg(ap, u_long); 494 else if (zflag) 495 num = va_arg(ap, size_t); 496 else if (hflag) 497 num = (u_short)va_arg(ap, int); 498 else if (cflag) 499 num = (u_char)va_arg(ap, int); 500 else 501 num = va_arg(ap, u_int); 502 goto number; 503 handle_sign: 504 if (jflag) 505 num = va_arg(ap, intmax_t); 506 else if (qflag) 507 num = va_arg(ap, quad_t); 508 else if (tflag) 509 num = va_arg(ap, ptrdiff_t); 510 else if (lflag) 511 num = va_arg(ap, long); 512 else if (zflag) 513 num = va_arg(ap, ssize_t); 514 else if (hflag) 515 num = (short)va_arg(ap, int); 516 else if (cflag) 517 num = (char)va_arg(ap, int); 518 else 519 num = va_arg(ap, int); 520 number: 521 if (sign && (intmax_t)num < 0) { 522 neg = 1; 523 num = -(intmax_t)num; 524 } 525 p = ksprintn(nbuf, num, base, &n, upper); 526 tmp = 0; 527 if (sharpflag && num != 0) { 528 if (base == 8) 529 tmp++; 530 else if (base == 16) 531 tmp += 2; 532 } 533 if (neg) 534 tmp++; 535 536 if (!ladjust && padc == '0') 537 dwidth = width - tmp; 538 width -= tmp + imax(dwidth, n); 539 dwidth -= n; 540 if (!ladjust) 541 while (width-- > 0) 542 PCHAR(' '); 543 if (neg) 544 PCHAR('-'); 545 if (sharpflag && num != 0) { 546 if (base == 8) { 547 PCHAR('0'); 548 } else if (base == 16) { 549 PCHAR('0'); 550 PCHAR('x'); 551 } 552 } 553 while (dwidth-- > 0) 554 PCHAR('0'); 555 556 while (*p) 557 PCHAR(*p--); 558 559 if (ladjust) 560 while (width-- > 0) 561 PCHAR(' '); 562 563 break; 564 default: 565 while (percent < fmt) 566 PCHAR(*percent++); 567 /* 568 * Since we ignore a formatting argument it is no 569 * longer safe to obey the remaining formatting 570 * arguments as the arguments will no longer match 571 * the format specs. 572 */ 573 stop = 1; 574 break; 575 } 576 } 577 #undef PCHAR 578 } 579