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