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