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 * Copyright (c) 2011 Konstantin Belousov <kib@FreeBSD.org> 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * $FreeBSD$ 36 */ 37 38 #include <sys/param.h> 39 #include <inttypes.h> 40 #include <stdarg.h> 41 #include <stddef.h> 42 #include <string.h> 43 #include <unistd.h> 44 #include "rtld_printf.h" 45 46 #define MAXNBUF (sizeof(intmax_t) * NBBY + 1) 47 48 #define PRINT_METHOD_SNPRINTF 1 49 #define PRINT_METHOD_WRITE 2 50 51 struct snprintf_arg { 52 int method; 53 char *str; 54 char *buf; 55 size_t remain; 56 size_t buf_total; 57 int fd; 58 }; 59 60 static void 61 printf_out(struct snprintf_arg *info) 62 { 63 64 if (info->remain == info->buf_total) 65 return; 66 write(info->fd, info->buf, info->buf_total - info->remain); 67 info->str = info->buf; 68 info->remain = info->buf_total; 69 } 70 71 static void 72 snprintf_func(int ch, struct snprintf_arg *const info) 73 { 74 75 switch (info->method) { 76 case PRINT_METHOD_SNPRINTF: 77 if (info->remain >= 2) { 78 *info->str++ = ch; 79 info->remain--; 80 } 81 break; 82 case PRINT_METHOD_WRITE: 83 if (info->remain > 0) { 84 *info->str++ = ch; 85 info->remain--; 86 } else 87 printf_out(info); 88 break; 89 } 90 } 91 92 static char const hex2ascii_lower[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 93 static char const hex2ascii_upper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 94 #define hex2ascii(hex) (hex2ascii_lower[hex]) 95 #define hex2ascii_upper(hex) (hex2ascii_upper[hex]) 96 97 static __inline int 98 imax(int a, int b) 99 { 100 101 return (a > b ? a : b); 102 } 103 104 static char * 105 ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) 106 { 107 char *p, c; 108 109 p = nbuf; 110 *p = '\0'; 111 do { 112 c = upper ? hex2ascii_upper(num % base) : 113 hex2ascii(num % base); 114 *++p = c; 115 } while (num /= base); 116 if (lenp) 117 *lenp = p - nbuf; 118 return (p); 119 } 120 121 static int 122 kvprintf(char const *fmt, struct snprintf_arg *arg, int radix, va_list ap) 123 { 124 #define PCHAR(c) snprintf_func((c), arg) 125 char nbuf[MAXNBUF]; 126 const char *p, *percent, *q; 127 u_char *up; 128 int ch, n; 129 uintmax_t num; 130 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 131 int cflag, hflag, jflag, tflag, zflag; 132 int dwidth, upper; 133 char padc; 134 int stop = 0, retval = 0; 135 136 num = 0; 137 138 if (fmt == NULL) 139 fmt = "(fmt null)\n"; 140 141 if (radix < 2 || radix > 36) 142 radix = 10; 143 144 for (;;) { 145 padc = ' '; 146 width = 0; 147 while ((ch = (u_char)*fmt++) != '%' || stop) { 148 if (ch == '\0') 149 return (retval); 150 PCHAR(ch); 151 } 152 percent = fmt - 1; 153 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 154 sign = 0; dot = 0; dwidth = 0; upper = 0; 155 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; 156 reswitch: switch (ch = (u_char)*fmt++) { 157 case '.': 158 dot = 1; 159 goto reswitch; 160 case '#': 161 sharpflag = 1; 162 goto reswitch; 163 case '+': 164 sign = 1; 165 goto reswitch; 166 case '-': 167 ladjust = 1; 168 goto reswitch; 169 case '%': 170 PCHAR(ch); 171 break; 172 case '*': 173 if (!dot) { 174 width = va_arg(ap, int); 175 if (width < 0) { 176 ladjust = !ladjust; 177 width = -width; 178 } 179 } else { 180 dwidth = va_arg(ap, int); 181 } 182 goto reswitch; 183 case '0': 184 if (!dot) { 185 padc = '0'; 186 goto reswitch; 187 } 188 case '1': case '2': case '3': case '4': 189 case '5': case '6': case '7': case '8': case '9': 190 for (n = 0;; ++fmt) { 191 n = n * 10 + ch - '0'; 192 ch = *fmt; 193 if (ch < '0' || ch > '9') 194 break; 195 } 196 if (dot) 197 dwidth = n; 198 else 199 width = n; 200 goto reswitch; 201 case 'b': 202 num = (u_int)va_arg(ap, int); 203 p = va_arg(ap, char *); 204 for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) 205 PCHAR(*q--); 206 207 if (num == 0) 208 break; 209 210 for (tmp = 0; *p;) { 211 n = *p++; 212 if (num & (1 << (n - 1))) { 213 PCHAR(tmp ? ',' : '<'); 214 for (; (n = *p) > ' '; ++p) 215 PCHAR(n); 216 tmp = 1; 217 } else 218 for (; *p > ' '; ++p) 219 continue; 220 } 221 if (tmp) 222 PCHAR('>'); 223 break; 224 case 'c': 225 PCHAR(va_arg(ap, int)); 226 break; 227 case 'D': 228 up = va_arg(ap, u_char *); 229 p = va_arg(ap, char *); 230 if (!width) 231 width = 16; 232 while(width--) { 233 PCHAR(hex2ascii(*up >> 4)); 234 PCHAR(hex2ascii(*up & 0x0f)); 235 up++; 236 if (width) 237 for (q=p;*q;q++) 238 PCHAR(*q); 239 } 240 break; 241 case 'd': 242 case 'i': 243 base = 10; 244 sign = 1; 245 goto handle_sign; 246 case 'h': 247 if (hflag) { 248 hflag = 0; 249 cflag = 1; 250 } else 251 hflag = 1; 252 goto reswitch; 253 case 'j': 254 jflag = 1; 255 goto reswitch; 256 case 'l': 257 if (lflag) { 258 lflag = 0; 259 qflag = 1; 260 } else 261 lflag = 1; 262 goto reswitch; 263 case 'n': 264 if (jflag) 265 *(va_arg(ap, intmax_t *)) = retval; 266 else if (qflag) 267 *(va_arg(ap, quad_t *)) = retval; 268 else if (lflag) 269 *(va_arg(ap, long *)) = retval; 270 else if (zflag) 271 *(va_arg(ap, size_t *)) = retval; 272 else if (hflag) 273 *(va_arg(ap, short *)) = retval; 274 else if (cflag) 275 *(va_arg(ap, char *)) = retval; 276 else 277 *(va_arg(ap, int *)) = retval; 278 break; 279 case 'o': 280 base = 8; 281 goto handle_nosign; 282 case 'p': 283 base = 16; 284 sharpflag = (width == 0); 285 sign = 0; 286 num = (uintptr_t)va_arg(ap, void *); 287 goto number; 288 case 'q': 289 qflag = 1; 290 goto reswitch; 291 case 'r': 292 base = radix; 293 if (sign) 294 goto handle_sign; 295 goto handle_nosign; 296 case 's': 297 p = va_arg(ap, char *); 298 if (p == NULL) 299 p = "(null)"; 300 if (!dot) 301 n = strlen (p); 302 else 303 for (n = 0; n < dwidth && p[n]; n++) 304 continue; 305 306 width -= n; 307 308 if (!ladjust && width > 0) 309 while (width--) 310 PCHAR(padc); 311 while (n--) 312 PCHAR(*p++); 313 if (ladjust && width > 0) 314 while (width--) 315 PCHAR(padc); 316 break; 317 case 't': 318 tflag = 1; 319 goto reswitch; 320 case 'u': 321 base = 10; 322 goto handle_nosign; 323 case 'X': 324 upper = 1; 325 case 'x': 326 base = 16; 327 goto handle_nosign; 328 case 'y': 329 base = 16; 330 sign = 1; 331 goto handle_sign; 332 case 'z': 333 zflag = 1; 334 goto reswitch; 335 handle_nosign: 336 sign = 0; 337 if (jflag) 338 num = va_arg(ap, uintmax_t); 339 else if (qflag) 340 num = va_arg(ap, u_quad_t); 341 else if (tflag) 342 num = va_arg(ap, ptrdiff_t); 343 else if (lflag) 344 num = va_arg(ap, u_long); 345 else if (zflag) 346 num = va_arg(ap, size_t); 347 else if (hflag) 348 num = (u_short)va_arg(ap, int); 349 else if (cflag) 350 num = (u_char)va_arg(ap, int); 351 else 352 num = va_arg(ap, u_int); 353 goto number; 354 handle_sign: 355 if (jflag) 356 num = va_arg(ap, intmax_t); 357 else if (qflag) 358 num = va_arg(ap, quad_t); 359 else if (tflag) 360 num = va_arg(ap, ptrdiff_t); 361 else if (lflag) 362 num = va_arg(ap, long); 363 else if (zflag) 364 num = va_arg(ap, ssize_t); 365 else if (hflag) 366 num = (short)va_arg(ap, int); 367 else if (cflag) 368 num = (char)va_arg(ap, int); 369 else 370 num = va_arg(ap, int); 371 number: 372 if (sign && (intmax_t)num < 0) { 373 neg = 1; 374 num = -(intmax_t)num; 375 } 376 p = ksprintn(nbuf, num, base, &n, upper); 377 tmp = 0; 378 if (sharpflag && num != 0) { 379 if (base == 8) 380 tmp++; 381 else if (base == 16) 382 tmp += 2; 383 } 384 if (neg) 385 tmp++; 386 387 if (!ladjust && padc == '0') 388 dwidth = width - tmp; 389 width -= tmp + imax(dwidth, n); 390 dwidth -= n; 391 if (!ladjust) 392 while (width-- > 0) 393 PCHAR(' '); 394 if (neg) 395 PCHAR('-'); 396 if (sharpflag && num != 0) { 397 if (base == 8) { 398 PCHAR('0'); 399 } else if (base == 16) { 400 PCHAR('0'); 401 PCHAR('x'); 402 } 403 } 404 while (dwidth-- > 0) 405 PCHAR('0'); 406 407 while (*p) 408 PCHAR(*p--); 409 410 if (ladjust) 411 while (width-- > 0) 412 PCHAR(' '); 413 414 break; 415 default: 416 while (percent < fmt) 417 PCHAR(*percent++); 418 /* 419 * Since we ignore an formatting argument it is no 420 * longer safe to obey the remaining formatting 421 * arguments as the arguments will no longer match 422 * the format specs. 423 */ 424 stop = 1; 425 break; 426 } 427 } 428 #undef PCHAR 429 } 430 431 int 432 rtld_snprintf(char *buf, size_t bufsize, const char *fmt, ...) 433 { 434 va_list ap; 435 int retval; 436 437 va_start(ap, fmt); 438 retval = rtld_vsnprintf(buf, bufsize, fmt, ap); 439 va_end(ap); 440 return (retval); 441 } 442 443 int 444 rtld_vsnprintf(char *buf, size_t bufsize, const char *fmt, va_list ap) 445 { 446 struct snprintf_arg info; 447 int retval; 448 449 info.method = PRINT_METHOD_SNPRINTF; 450 info.buf = info.str = buf; 451 info.buf_total = info.remain = bufsize; 452 info.fd = -1; 453 retval = kvprintf(fmt, &info, 10, ap); 454 if (info.remain >= 1) 455 *info.str++ = '\0'; 456 return (retval); 457 } 458 459 int 460 rtld_vfdprintf(int fd, const char *fmt, va_list ap) 461 { 462 char buf[512]; 463 struct snprintf_arg info; 464 int retval; 465 466 info.method = PRINT_METHOD_WRITE; 467 info.buf = info.str = buf; 468 info.buf_total = info.remain = sizeof(buf); 469 info.fd = fd; 470 retval = kvprintf(fmt, &info, 10, ap); 471 printf_out(&info); 472 return (retval); 473 } 474 475 int 476 rtld_fdprintf(int fd, const char *fmt, ...) 477 { 478 va_list ap; 479 int retval; 480 481 va_start(ap, fmt); 482 retval = rtld_vfdprintf(fd, fmt, ap); 483 va_end(ap); 484 return (retval); 485 } 486 487 void 488 rtld_fdputstr(int fd, const char *str) 489 { 490 491 write(fd, str, strlen(str)); 492 } 493 494 void 495 rtld_fdputchar(int fd, int c) 496 { 497 char c1; 498 499 c1 = c; 500 write(fd, &c1, 1); 501 } 502