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 * 4. 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 <ctype.h> 40 #include <inttypes.h> 41 #include <stdarg.h> 42 #include <stddef.h> 43 #include <string.h> 44 #include <unistd.h> 45 #include "rtld_printf.h" 46 47 #define MAXNBUF (sizeof(intmax_t) * NBBY + 1) 48 49 #define PRINT_METHOD_SNPRINTF 1 50 #define PRINT_METHOD_WRITE 2 51 52 struct snprintf_arg { 53 int method; 54 char *str; 55 char *buf; 56 size_t remain; 57 size_t buf_total; 58 int fd; 59 }; 60 61 static void 62 printf_out(struct snprintf_arg *info) 63 { 64 65 if (info->remain == info->buf_total) 66 return; 67 write(info->fd, info->buf, info->buf_total - info->remain); 68 info->str = info->buf; 69 info->remain = info->buf_total; 70 } 71 72 static void 73 snprintf_func(int ch, struct snprintf_arg *const info) 74 { 75 76 switch (info->method) { 77 case PRINT_METHOD_SNPRINTF: 78 if (info->remain >= 2) { 79 *info->str++ = ch; 80 info->remain--; 81 } 82 break; 83 case PRINT_METHOD_WRITE: 84 if (info->remain > 0) { 85 *info->str++ = ch; 86 info->remain--; 87 } else 88 printf_out(info); 89 break; 90 } 91 } 92 93 static char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 94 #define hex2ascii(hex) (hex2ascii_data[hex]) 95 96 static __inline int 97 imax(int a, int b) 98 { 99 100 return (a > b ? a : b); 101 } 102 103 static char * 104 ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) 105 { 106 char *p, c; 107 108 p = nbuf; 109 *p = '\0'; 110 do { 111 c = hex2ascii(num % base); 112 *++p = upper ? toupper(c) : c; 113 } while (num /= base); 114 if (lenp) 115 *lenp = p - nbuf; 116 return (p); 117 } 118 119 static int 120 kvprintf(char const *fmt, struct snprintf_arg *arg, int radix, va_list ap) 121 { 122 #define PCHAR(c) snprintf_func((c), arg) 123 char nbuf[MAXNBUF]; 124 const char *p, *percent, *q; 125 u_char *up; 126 int ch, n; 127 uintmax_t num; 128 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 129 int cflag, hflag, jflag, tflag, zflag; 130 int dwidth, upper; 131 char padc; 132 int stop = 0, retval = 0; 133 134 num = 0; 135 136 if (fmt == NULL) 137 fmt = "(fmt null)\n"; 138 139 if (radix < 2 || radix > 36) 140 radix = 10; 141 142 for (;;) { 143 padc = ' '; 144 width = 0; 145 while ((ch = (u_char)*fmt++) != '%' || stop) { 146 if (ch == '\0') 147 return (retval); 148 PCHAR(ch); 149 } 150 percent = fmt - 1; 151 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 152 sign = 0; dot = 0; dwidth = 0; upper = 0; 153 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; 154 reswitch: switch (ch = (u_char)*fmt++) { 155 case '.': 156 dot = 1; 157 goto reswitch; 158 case '#': 159 sharpflag = 1; 160 goto reswitch; 161 case '+': 162 sign = 1; 163 goto reswitch; 164 case '-': 165 ladjust = 1; 166 goto reswitch; 167 case '%': 168 PCHAR(ch); 169 break; 170 case '*': 171 if (!dot) { 172 width = va_arg(ap, int); 173 if (width < 0) { 174 ladjust = !ladjust; 175 width = -width; 176 } 177 } else { 178 dwidth = va_arg(ap, int); 179 } 180 goto reswitch; 181 case '0': 182 if (!dot) { 183 padc = '0'; 184 goto reswitch; 185 } 186 case '1': case '2': case '3': case '4': 187 case '5': case '6': case '7': case '8': case '9': 188 for (n = 0;; ++fmt) { 189 n = n * 10 + ch - '0'; 190 ch = *fmt; 191 if (ch < '0' || ch > '9') 192 break; 193 } 194 if (dot) 195 dwidth = n; 196 else 197 width = n; 198 goto reswitch; 199 case 'b': 200 num = (u_int)va_arg(ap, int); 201 p = va_arg(ap, char *); 202 for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) 203 PCHAR(*q--); 204 205 if (num == 0) 206 break; 207 208 for (tmp = 0; *p;) { 209 n = *p++; 210 if (num & (1 << (n - 1))) { 211 PCHAR(tmp ? ',' : '<'); 212 for (; (n = *p) > ' '; ++p) 213 PCHAR(n); 214 tmp = 1; 215 } else 216 for (; *p > ' '; ++p) 217 continue; 218 } 219 if (tmp) 220 PCHAR('>'); 221 break; 222 case 'c': 223 PCHAR(va_arg(ap, int)); 224 break; 225 case 'D': 226 up = va_arg(ap, u_char *); 227 p = va_arg(ap, char *); 228 if (!width) 229 width = 16; 230 while(width--) { 231 PCHAR(hex2ascii(*up >> 4)); 232 PCHAR(hex2ascii(*up & 0x0f)); 233 up++; 234 if (width) 235 for (q=p;*q;q++) 236 PCHAR(*q); 237 } 238 break; 239 case 'd': 240 case 'i': 241 base = 10; 242 sign = 1; 243 goto handle_sign; 244 case 'h': 245 if (hflag) { 246 hflag = 0; 247 cflag = 1; 248 } else 249 hflag = 1; 250 goto reswitch; 251 case 'j': 252 jflag = 1; 253 goto reswitch; 254 case 'l': 255 if (lflag) { 256 lflag = 0; 257 qflag = 1; 258 } else 259 lflag = 1; 260 goto reswitch; 261 case 'n': 262 if (jflag) 263 *(va_arg(ap, intmax_t *)) = retval; 264 else if (qflag) 265 *(va_arg(ap, quad_t *)) = retval; 266 else if (lflag) 267 *(va_arg(ap, long *)) = retval; 268 else if (zflag) 269 *(va_arg(ap, size_t *)) = retval; 270 else if (hflag) 271 *(va_arg(ap, short *)) = retval; 272 else if (cflag) 273 *(va_arg(ap, char *)) = retval; 274 else 275 *(va_arg(ap, int *)) = retval; 276 break; 277 case 'o': 278 base = 8; 279 goto handle_nosign; 280 case 'p': 281 base = 16; 282 sharpflag = (width == 0); 283 sign = 0; 284 num = (uintptr_t)va_arg(ap, void *); 285 goto number; 286 case 'q': 287 qflag = 1; 288 goto reswitch; 289 case 'r': 290 base = radix; 291 if (sign) 292 goto handle_sign; 293 goto handle_nosign; 294 case 's': 295 p = va_arg(ap, char *); 296 if (p == NULL) 297 p = "(null)"; 298 if (!dot) 299 n = strlen (p); 300 else 301 for (n = 0; n < dwidth && p[n]; n++) 302 continue; 303 304 width -= n; 305 306 if (!ladjust && width > 0) 307 while (width--) 308 PCHAR(padc); 309 while (n--) 310 PCHAR(*p++); 311 if (ladjust && width > 0) 312 while (width--) 313 PCHAR(padc); 314 break; 315 case 't': 316 tflag = 1; 317 goto reswitch; 318 case 'u': 319 base = 10; 320 goto handle_nosign; 321 case 'X': 322 upper = 1; 323 case 'x': 324 base = 16; 325 goto handle_nosign; 326 case 'y': 327 base = 16; 328 sign = 1; 329 goto handle_sign; 330 case 'z': 331 zflag = 1; 332 goto reswitch; 333 handle_nosign: 334 sign = 0; 335 if (jflag) 336 num = va_arg(ap, uintmax_t); 337 else if (qflag) 338 num = va_arg(ap, u_quad_t); 339 else if (tflag) 340 num = va_arg(ap, ptrdiff_t); 341 else if (lflag) 342 num = va_arg(ap, u_long); 343 else if (zflag) 344 num = va_arg(ap, size_t); 345 else if (hflag) 346 num = (u_short)va_arg(ap, int); 347 else if (cflag) 348 num = (u_char)va_arg(ap, int); 349 else 350 num = va_arg(ap, u_int); 351 goto number; 352 handle_sign: 353 if (jflag) 354 num = va_arg(ap, intmax_t); 355 else if (qflag) 356 num = va_arg(ap, quad_t); 357 else if (tflag) 358 num = va_arg(ap, ptrdiff_t); 359 else if (lflag) 360 num = va_arg(ap, long); 361 else if (zflag) 362 num = va_arg(ap, ssize_t); 363 else if (hflag) 364 num = (short)va_arg(ap, int); 365 else if (cflag) 366 num = (char)va_arg(ap, int); 367 else 368 num = va_arg(ap, int); 369 number: 370 if (sign && (intmax_t)num < 0) { 371 neg = 1; 372 num = -(intmax_t)num; 373 } 374 p = ksprintn(nbuf, num, base, &n, upper); 375 tmp = 0; 376 if (sharpflag && num != 0) { 377 if (base == 8) 378 tmp++; 379 else if (base == 16) 380 tmp += 2; 381 } 382 if (neg) 383 tmp++; 384 385 if (!ladjust && padc == '0') 386 dwidth = width - tmp; 387 width -= tmp + imax(dwidth, n); 388 dwidth -= n; 389 if (!ladjust) 390 while (width-- > 0) 391 PCHAR(' '); 392 if (neg) 393 PCHAR('-'); 394 if (sharpflag && num != 0) { 395 if (base == 8) { 396 PCHAR('0'); 397 } else if (base == 16) { 398 PCHAR('0'); 399 PCHAR('x'); 400 } 401 } 402 while (dwidth-- > 0) 403 PCHAR('0'); 404 405 while (*p) 406 PCHAR(*p--); 407 408 if (ladjust) 409 while (width-- > 0) 410 PCHAR(' '); 411 412 break; 413 default: 414 while (percent < fmt) 415 PCHAR(*percent++); 416 /* 417 * Since we ignore an formatting argument it is no 418 * longer safe to obey the remaining formatting 419 * arguments as the arguments will no longer match 420 * the format specs. 421 */ 422 stop = 1; 423 break; 424 } 425 } 426 #undef PCHAR 427 } 428 429 int 430 rtld_vsnprintf(char *buf, size_t bufsize, const char *fmt, va_list ap) 431 { 432 struct snprintf_arg info; 433 int retval; 434 435 info.method = PRINT_METHOD_SNPRINTF; 436 info.buf = info.str = buf; 437 info.buf_total = info.remain = bufsize; 438 info.fd = -1; 439 retval = kvprintf(fmt, &info, 10, ap); 440 if (info.remain >= 1) 441 *info.str++ = '\0'; 442 return (retval); 443 } 444 445 int 446 rtld_vfdprintf(int fd, const char *fmt, va_list ap) 447 { 448 char buf[512]; 449 struct snprintf_arg info; 450 int retval; 451 452 info.method = PRINT_METHOD_WRITE; 453 info.buf = info.str = buf; 454 info.buf_total = info.remain = sizeof(buf); 455 info.fd = fd; 456 retval = kvprintf(fmt, &info, 10, ap); 457 printf_out(&info); 458 return (retval); 459 } 460 461 int 462 rtld_fdprintf(int fd, const char *fmt, ...) 463 { 464 va_list ap; 465 int retval; 466 467 va_start(ap, fmt); 468 retval = rtld_vfdprintf(fd, fmt, ap); 469 va_end(ap); 470 return (retval); 471 } 472 473 void 474 rtld_fdputstr(int fd, const char *str) 475 { 476 477 write(fd, str, strlen(str)); 478 } 479 480 void 481 rtld_fdputchar(int fd, int c) 482 { 483 char c1; 484 485 c1 = c; 486 write(fd, &c1, 1); 487 } 488