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