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