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