1225152Skib/*- 2225152Skib * Copyright (c) 1986, 1988, 1991, 1993 3225152Skib * The Regents of the University of California. All rights reserved. 4225152Skib * (c) UNIX System Laboratories, Inc. 5225152Skib * All or some portions of this file are derived from material licensed 6225152Skib * to the University of California by American Telephone and Telegraph 7225152Skib * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8225152Skib * the permission of UNIX System Laboratories, Inc. 9225152Skib * Copyright (c) 2011 Konstantin Belousov <kib@FreeBSD.org> 10225152Skib * 11225152Skib * Redistribution and use in source and binary forms, with or without 12225152Skib * modification, are permitted provided that the following conditions 13225152Skib * are met: 14225152Skib * 1. Redistributions of source code must retain the above copyright 15225152Skib * notice, this list of conditions and the following disclaimer. 16225152Skib * 2. Redistributions in binary form must reproduce the above copyright 17225152Skib * notice, this list of conditions and the following disclaimer in the 18225152Skib * documentation and/or other materials provided with the distribution. 19225152Skib * 4. Neither the name of the University nor the names of its contributors 20225152Skib * may be used to endorse or promote products derived from this software 21225152Skib * without specific prior written permission. 22225152Skib * 23225152Skib * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24225152Skib * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25225152Skib * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26225152Skib * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27225152Skib * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28225152Skib * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29225152Skib * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30225152Skib * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31225152Skib * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32225152Skib * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33225152Skib * SUCH DAMAGE. 34225152Skib * 35225152Skib * $FreeBSD$ 36225152Skib */ 37225152Skib 38225152Skib#include <sys/param.h> 39225152Skib#include <inttypes.h> 40225152Skib#include <stdarg.h> 41225152Skib#include <stddef.h> 42225152Skib#include <string.h> 43225152Skib#include <unistd.h> 44225152Skib#include "rtld_printf.h" 45225152Skib 46225152Skib#define MAXNBUF (sizeof(intmax_t) * NBBY + 1) 47225152Skib 48225417Skib#define PRINT_METHOD_SNPRINTF 1 49225417Skib#define PRINT_METHOD_WRITE 2 50225417Skib 51225152Skibstruct snprintf_arg { 52225417Skib int method; 53225152Skib char *str; 54225152Skib char *buf; 55225152Skib size_t remain; 56225152Skib size_t buf_total; 57225152Skib int fd; 58225152Skib}; 59225152Skib 60225152Skibstatic void 61225152Skibprintf_out(struct snprintf_arg *info) 62225152Skib{ 63225152Skib 64225152Skib if (info->remain == info->buf_total) 65225152Skib return; 66225152Skib write(info->fd, info->buf, info->buf_total - info->remain); 67225152Skib info->str = info->buf; 68225152Skib info->remain = info->buf_total; 69225152Skib} 70225152Skib 71225152Skibstatic void 72225417Skibsnprintf_func(int ch, struct snprintf_arg *const info) 73225152Skib{ 74225152Skib 75225417Skib switch (info->method) { 76225417Skib case PRINT_METHOD_SNPRINTF: 77225417Skib if (info->remain >= 2) { 78225417Skib *info->str++ = ch; 79225417Skib info->remain--; 80225417Skib } 81225417Skib break; 82225417Skib case PRINT_METHOD_WRITE: 83225417Skib if (info->remain > 0) { 84225417Skib *info->str++ = ch; 85225417Skib info->remain--; 86225417Skib } else 87225417Skib printf_out(info); 88225417Skib break; 89225417Skib } 90225152Skib} 91225152Skib 92232729Skibstatic char const hex2ascii_lower[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 93232729Skibstatic char const hex2ascii_upper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 94232729Skib#define hex2ascii(hex) (hex2ascii_lower[hex]) 95232729Skib#define hex2ascii_upper(hex) (hex2ascii_upper[hex]) 96225152Skib 97225152Skibstatic __inline int 98225152Skibimax(int a, int b) 99225152Skib{ 100225152Skib 101225152Skib return (a > b ? a : b); 102225152Skib} 103225152Skib 104225152Skibstatic char * 105225152Skibksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) 106225152Skib{ 107225152Skib char *p, c; 108225152Skib 109225152Skib p = nbuf; 110225152Skib *p = '\0'; 111225152Skib do { 112232729Skib c = upper ? hex2ascii_upper(num % base) : 113232729Skib hex2ascii(num % base); 114232729Skib *++p = c; 115225152Skib } while (num /= base); 116225152Skib if (lenp) 117225152Skib *lenp = p - nbuf; 118225152Skib return (p); 119225152Skib} 120225152Skib 121225152Skibstatic int 122225417Skibkvprintf(char const *fmt, struct snprintf_arg *arg, int radix, va_list ap) 123225152Skib{ 124225417Skib#define PCHAR(c) snprintf_func((c), arg) 125225152Skib char nbuf[MAXNBUF]; 126225152Skib const char *p, *percent, *q; 127225152Skib u_char *up; 128225152Skib int ch, n; 129225152Skib uintmax_t num; 130225152Skib int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 131225152Skib int cflag, hflag, jflag, tflag, zflag; 132225152Skib int dwidth, upper; 133225152Skib char padc; 134225152Skib int stop = 0, retval = 0; 135225152Skib 136225152Skib num = 0; 137225152Skib 138225152Skib if (fmt == NULL) 139225152Skib fmt = "(fmt null)\n"; 140225152Skib 141225152Skib if (radix < 2 || radix > 36) 142225152Skib radix = 10; 143225152Skib 144225152Skib for (;;) { 145225152Skib padc = ' '; 146225152Skib width = 0; 147225152Skib while ((ch = (u_char)*fmt++) != '%' || stop) { 148225152Skib if (ch == '\0') 149225152Skib return (retval); 150225152Skib PCHAR(ch); 151225152Skib } 152225152Skib percent = fmt - 1; 153225152Skib qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 154225152Skib sign = 0; dot = 0; dwidth = 0; upper = 0; 155225152Skib cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; 156225152Skibreswitch: switch (ch = (u_char)*fmt++) { 157225152Skib case '.': 158225152Skib dot = 1; 159225152Skib goto reswitch; 160225152Skib case '#': 161225152Skib sharpflag = 1; 162225152Skib goto reswitch; 163225152Skib case '+': 164225152Skib sign = 1; 165225152Skib goto reswitch; 166225152Skib case '-': 167225152Skib ladjust = 1; 168225152Skib goto reswitch; 169225152Skib case '%': 170225152Skib PCHAR(ch); 171225152Skib break; 172225152Skib case '*': 173225152Skib if (!dot) { 174225152Skib width = va_arg(ap, int); 175225152Skib if (width < 0) { 176225152Skib ladjust = !ladjust; 177225152Skib width = -width; 178225152Skib } 179225152Skib } else { 180225152Skib dwidth = va_arg(ap, int); 181225152Skib } 182225152Skib goto reswitch; 183225152Skib case '0': 184225152Skib if (!dot) { 185225152Skib padc = '0'; 186225152Skib goto reswitch; 187225152Skib } 188225152Skib case '1': case '2': case '3': case '4': 189225152Skib case '5': case '6': case '7': case '8': case '9': 190225152Skib for (n = 0;; ++fmt) { 191225152Skib n = n * 10 + ch - '0'; 192225152Skib ch = *fmt; 193225152Skib if (ch < '0' || ch > '9') 194225152Skib break; 195225152Skib } 196225152Skib if (dot) 197225152Skib dwidth = n; 198225152Skib else 199225152Skib width = n; 200225152Skib goto reswitch; 201225152Skib case 'b': 202225152Skib num = (u_int)va_arg(ap, int); 203225152Skib p = va_arg(ap, char *); 204225152Skib for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) 205225152Skib PCHAR(*q--); 206225152Skib 207225152Skib if (num == 0) 208225152Skib break; 209225152Skib 210225152Skib for (tmp = 0; *p;) { 211225152Skib n = *p++; 212225152Skib if (num & (1 << (n - 1))) { 213225152Skib PCHAR(tmp ? ',' : '<'); 214225152Skib for (; (n = *p) > ' '; ++p) 215225152Skib PCHAR(n); 216225152Skib tmp = 1; 217225152Skib } else 218225152Skib for (; *p > ' '; ++p) 219225152Skib continue; 220225152Skib } 221225152Skib if (tmp) 222225152Skib PCHAR('>'); 223225152Skib break; 224225152Skib case 'c': 225225152Skib PCHAR(va_arg(ap, int)); 226225152Skib break; 227225152Skib case 'D': 228225152Skib up = va_arg(ap, u_char *); 229225152Skib p = va_arg(ap, char *); 230225152Skib if (!width) 231225152Skib width = 16; 232225152Skib while(width--) { 233225152Skib PCHAR(hex2ascii(*up >> 4)); 234225152Skib PCHAR(hex2ascii(*up & 0x0f)); 235225152Skib up++; 236225152Skib if (width) 237225152Skib for (q=p;*q;q++) 238225152Skib PCHAR(*q); 239225152Skib } 240225152Skib break; 241225152Skib case 'd': 242225152Skib case 'i': 243225152Skib base = 10; 244225152Skib sign = 1; 245225152Skib goto handle_sign; 246225152Skib case 'h': 247225152Skib if (hflag) { 248225152Skib hflag = 0; 249225152Skib cflag = 1; 250225152Skib } else 251225152Skib hflag = 1; 252225152Skib goto reswitch; 253225152Skib case 'j': 254225152Skib jflag = 1; 255225152Skib goto reswitch; 256225152Skib case 'l': 257225152Skib if (lflag) { 258225152Skib lflag = 0; 259225152Skib qflag = 1; 260225152Skib } else 261225152Skib lflag = 1; 262225152Skib goto reswitch; 263225152Skib case 'n': 264225152Skib if (jflag) 265225152Skib *(va_arg(ap, intmax_t *)) = retval; 266225152Skib else if (qflag) 267225152Skib *(va_arg(ap, quad_t *)) = retval; 268225152Skib else if (lflag) 269225152Skib *(va_arg(ap, long *)) = retval; 270225152Skib else if (zflag) 271225152Skib *(va_arg(ap, size_t *)) = retval; 272225152Skib else if (hflag) 273225152Skib *(va_arg(ap, short *)) = retval; 274225152Skib else if (cflag) 275225152Skib *(va_arg(ap, char *)) = retval; 276225152Skib else 277225152Skib *(va_arg(ap, int *)) = retval; 278225152Skib break; 279225152Skib case 'o': 280225152Skib base = 8; 281225152Skib goto handle_nosign; 282225152Skib case 'p': 283225152Skib base = 16; 284225152Skib sharpflag = (width == 0); 285225152Skib sign = 0; 286225152Skib num = (uintptr_t)va_arg(ap, void *); 287225152Skib goto number; 288225152Skib case 'q': 289225152Skib qflag = 1; 290225152Skib goto reswitch; 291225152Skib case 'r': 292225152Skib base = radix; 293225152Skib if (sign) 294225152Skib goto handle_sign; 295225152Skib goto handle_nosign; 296225152Skib case 's': 297225152Skib p = va_arg(ap, char *); 298225152Skib if (p == NULL) 299225152Skib p = "(null)"; 300225152Skib if (!dot) 301225152Skib n = strlen (p); 302225152Skib else 303225152Skib for (n = 0; n < dwidth && p[n]; n++) 304225152Skib continue; 305225152Skib 306225152Skib width -= n; 307225152Skib 308225152Skib if (!ladjust && width > 0) 309225152Skib while (width--) 310225152Skib PCHAR(padc); 311225152Skib while (n--) 312225152Skib PCHAR(*p++); 313225152Skib if (ladjust && width > 0) 314225152Skib while (width--) 315225152Skib PCHAR(padc); 316225152Skib break; 317225152Skib case 't': 318225152Skib tflag = 1; 319225152Skib goto reswitch; 320225152Skib case 'u': 321225152Skib base = 10; 322225152Skib goto handle_nosign; 323225152Skib case 'X': 324225152Skib upper = 1; 325225152Skib case 'x': 326225152Skib base = 16; 327225152Skib goto handle_nosign; 328225152Skib case 'y': 329225152Skib base = 16; 330225152Skib sign = 1; 331225152Skib goto handle_sign; 332225152Skib case 'z': 333225152Skib zflag = 1; 334225152Skib goto reswitch; 335225152Skibhandle_nosign: 336225152Skib sign = 0; 337225152Skib if (jflag) 338225152Skib num = va_arg(ap, uintmax_t); 339225152Skib else if (qflag) 340225152Skib num = va_arg(ap, u_quad_t); 341225152Skib else if (tflag) 342225152Skib num = va_arg(ap, ptrdiff_t); 343225152Skib else if (lflag) 344225152Skib num = va_arg(ap, u_long); 345225152Skib else if (zflag) 346225152Skib num = va_arg(ap, size_t); 347225152Skib else if (hflag) 348225152Skib num = (u_short)va_arg(ap, int); 349225152Skib else if (cflag) 350225152Skib num = (u_char)va_arg(ap, int); 351225152Skib else 352225152Skib num = va_arg(ap, u_int); 353225152Skib goto number; 354225152Skibhandle_sign: 355225152Skib if (jflag) 356225152Skib num = va_arg(ap, intmax_t); 357225152Skib else if (qflag) 358225152Skib num = va_arg(ap, quad_t); 359225152Skib else if (tflag) 360225152Skib num = va_arg(ap, ptrdiff_t); 361225152Skib else if (lflag) 362225152Skib num = va_arg(ap, long); 363225152Skib else if (zflag) 364225152Skib num = va_arg(ap, ssize_t); 365225152Skib else if (hflag) 366225152Skib num = (short)va_arg(ap, int); 367225152Skib else if (cflag) 368225152Skib num = (char)va_arg(ap, int); 369225152Skib else 370225152Skib num = va_arg(ap, int); 371225152Skibnumber: 372225152Skib if (sign && (intmax_t)num < 0) { 373225152Skib neg = 1; 374225152Skib num = -(intmax_t)num; 375225152Skib } 376225152Skib p = ksprintn(nbuf, num, base, &n, upper); 377225152Skib tmp = 0; 378225152Skib if (sharpflag && num != 0) { 379225152Skib if (base == 8) 380225152Skib tmp++; 381225152Skib else if (base == 16) 382225152Skib tmp += 2; 383225152Skib } 384225152Skib if (neg) 385225152Skib tmp++; 386225152Skib 387225152Skib if (!ladjust && padc == '0') 388225152Skib dwidth = width - tmp; 389225152Skib width -= tmp + imax(dwidth, n); 390225152Skib dwidth -= n; 391225152Skib if (!ladjust) 392225152Skib while (width-- > 0) 393225152Skib PCHAR(' '); 394225152Skib if (neg) 395225152Skib PCHAR('-'); 396225152Skib if (sharpflag && num != 0) { 397225152Skib if (base == 8) { 398225152Skib PCHAR('0'); 399225152Skib } else if (base == 16) { 400225152Skib PCHAR('0'); 401225152Skib PCHAR('x'); 402225152Skib } 403225152Skib } 404225152Skib while (dwidth-- > 0) 405225152Skib PCHAR('0'); 406225152Skib 407225152Skib while (*p) 408225152Skib PCHAR(*p--); 409225152Skib 410225152Skib if (ladjust) 411225152Skib while (width-- > 0) 412225152Skib PCHAR(' '); 413225152Skib 414225152Skib break; 415225152Skib default: 416225152Skib while (percent < fmt) 417225152Skib PCHAR(*percent++); 418225152Skib /* 419225152Skib * Since we ignore an formatting argument it is no 420225152Skib * longer safe to obey the remaining formatting 421225152Skib * arguments as the arguments will no longer match 422225152Skib * the format specs. 423225152Skib */ 424225152Skib stop = 1; 425225152Skib break; 426225152Skib } 427225152Skib } 428225152Skib#undef PCHAR 429225152Skib} 430225152Skib 431225152Skibint 432225152Skibrtld_vsnprintf(char *buf, size_t bufsize, const char *fmt, va_list ap) 433225152Skib{ 434225152Skib struct snprintf_arg info; 435225152Skib int retval; 436225152Skib 437225417Skib info.method = PRINT_METHOD_SNPRINTF; 438225152Skib info.buf = info.str = buf; 439225152Skib info.buf_total = info.remain = bufsize; 440225152Skib info.fd = -1; 441225417Skib retval = kvprintf(fmt, &info, 10, ap); 442225152Skib if (info.remain >= 1) 443225152Skib *info.str++ = '\0'; 444225152Skib return (retval); 445225152Skib} 446225152Skib 447225152Skibint 448225152Skibrtld_vfdprintf(int fd, const char *fmt, va_list ap) 449225152Skib{ 450225152Skib char buf[512]; 451225152Skib struct snprintf_arg info; 452225152Skib int retval; 453225152Skib 454225417Skib info.method = PRINT_METHOD_WRITE; 455225152Skib info.buf = info.str = buf; 456225152Skib info.buf_total = info.remain = sizeof(buf); 457225152Skib info.fd = fd; 458225417Skib retval = kvprintf(fmt, &info, 10, ap); 459225152Skib printf_out(&info); 460225152Skib return (retval); 461225152Skib} 462225152Skib 463225152Skibint 464225152Skibrtld_fdprintf(int fd, const char *fmt, ...) 465225152Skib{ 466225152Skib va_list ap; 467225152Skib int retval; 468225152Skib 469225152Skib va_start(ap, fmt); 470225152Skib retval = rtld_vfdprintf(fd, fmt, ap); 471225152Skib va_end(ap); 472225152Skib return (retval); 473225152Skib} 474225152Skib 475225152Skibvoid 476225152Skibrtld_fdputstr(int fd, const char *str) 477225152Skib{ 478225152Skib 479225152Skib write(fd, str, strlen(str)); 480225152Skib} 481225152Skib 482225152Skibvoid 483225152Skibrtld_fdputchar(int fd, int c) 484225152Skib{ 485225152Skib char c1; 486225152Skib 487225152Skib c1 = c; 488225152Skib write(fd, &c1, 1); 489225152Skib} 490