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