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