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