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