printf.c revision 334935
138451Smsmith/*- 238451Smsmith * Copyright (c) 1986, 1988, 1991, 1993 338451Smsmith * The Regents of the University of California. All rights reserved. 438451Smsmith * (c) UNIX System Laboratories, Inc. 538451Smsmith * All or some portions of this file are derived from material licensed 638451Smsmith * to the University of California by American Telephone and Telegraph 738451Smsmith * Co. or Unix System Laboratories, Inc. and are reproduced herein with 838451Smsmith * the permission of UNIX System Laboratories, Inc. 938451Smsmith * 1038451Smsmith * Redistribution and use in source and binary forms, with or without 1138451Smsmith * modification, are permitted provided that the following conditions 1238451Smsmith * are met: 1338451Smsmith * 1. Redistributions of source code must retain the above copyright 1438451Smsmith * notice, this list of conditions and the following disclaimer. 1538451Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1638451Smsmith * notice, this list of conditions and the following disclaimer in the 1738451Smsmith * documentation and/or other materials provided with the distribution. 1838451Smsmith * 4. Neither the name of the University nor the names of its contributors 1938451Smsmith * may be used to endorse or promote products derived from this software 2038451Smsmith * without specific prior written permission. 2138451Smsmith * 2238451Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2338451Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2438451Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2538451Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2638451Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2738451Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2838451Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2938451Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3038451Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3138451Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3238451Smsmith * SUCH DAMAGE. 3338451Smsmith * 3438451Smsmith * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 3538451Smsmith */ 3638451Smsmith 3784221Sdillon#include <sys/cdefs.h> 3884221Sdillon__FBSDID("$FreeBSD: stable/11/stand/libsa/printf.c 334935 2018-06-10 22:26:15Z ian $"); 3984221Sdillon 4038451Smsmith/* 4138451Smsmith * Standaloneified version of the FreeBSD kernel printf family. 4238451Smsmith */ 4338451Smsmith 4438451Smsmith#include <sys/types.h> 45113159Speter#include <sys/stddef.h> 46113159Speter#include <sys/stdint.h> 47103949Smike#include <limits.h> 4855137Speter#include <string.h> 4938451Smsmith#include "stand.h" 5038451Smsmith 5138451Smsmith/* 5238451Smsmith * Note that stdarg.h and the ANSI style va_start macro is used for both 5338451Smsmith * ANSI and traditional C compilers. 5438451Smsmith */ 5538451Smsmith#include <machine/stdarg.h> 5638451Smsmith 57113159Speter#define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1) 58113159Speter 59266878Shselaskytypedef void (kvprintf_fn_t)(int, void *); 60266878Shselasky 61156518Sjkimstatic char *ksprintn (char *buf, uintmax_t num, int base, int *len, int upper); 62266878Shselaskystatic int kvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap); 6338451Smsmith 64266878Shselaskystatic void 65266878Shselaskyputchar_wrapper(int cc, void *arg) 66266878Shselasky{ 67266879Shselasky 68266878Shselasky putchar(cc); 69266878Shselasky} 70266878Shselasky 7138451Smsmithint 7238451Smsmithprintf(const char *fmt, ...) 7338451Smsmith{ 7438451Smsmith va_list ap; 7538451Smsmith int retval; 7638451Smsmith 7738451Smsmith va_start(ap, fmt); 78266878Shselasky retval = kvprintf(fmt, putchar_wrapper, NULL, 10, ap); 7938451Smsmith va_end(ap); 8038451Smsmith return retval; 8138451Smsmith} 8238451Smsmith 83334935Sianint 8438451Smsmithvprintf(const char *fmt, va_list ap) 8538451Smsmith{ 86266879Shselasky 87334935Sian return (kvprintf(fmt, putchar_wrapper, NULL, 10, ap)); 8838451Smsmith} 8938451Smsmith 9038451Smsmithint 9138451Smsmithsprintf(char *buf, const char *cfmt, ...) 9238451Smsmith{ 9338451Smsmith int retval; 9438451Smsmith va_list ap; 9538451Smsmith 9638451Smsmith va_start(ap, cfmt); 9738451Smsmith retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 9838451Smsmith buf[retval] = '\0'; 9938451Smsmith va_end(ap); 10038451Smsmith return retval; 10138451Smsmith} 10238451Smsmith 103266878Shselaskystruct print_buf { 104266878Shselasky char *buf; 105266878Shselasky size_t size; 106266878Shselasky}; 107266878Shselasky 108266878Shselaskystatic void 109266878Shselaskysnprint_func(int ch, void *arg) 110266878Shselasky{ 111266878Shselasky struct print_buf *pbuf = arg; 112266878Shselasky 113266878Shselasky if (pbuf->size < 2) { 114266878Shselasky /* 115266878Shselasky * Reserve last buffer position for the terminating 116266878Shselasky * character: 117266878Shselasky */ 118266878Shselasky return; 119266878Shselasky } 120266878Shselasky *(pbuf->buf)++ = ch; 121266878Shselasky pbuf->size--; 122266878Shselasky} 123266878Shselasky 124266878Shselaskyint 125266878Shselaskysnprintf(char *buf, size_t size, const char *cfmt, ...) 126266878Shselasky{ 127266878Shselasky int retval; 128266878Shselasky va_list ap; 129266878Shselasky struct print_buf arg; 130266878Shselasky 131266878Shselasky arg.buf = buf; 132266878Shselasky arg.size = size; 133266878Shselasky 134266878Shselasky va_start(ap, cfmt); 135266878Shselasky retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap); 136266878Shselasky va_end(ap); 137266878Shselasky 138266878Shselasky if (arg.size >= 1) 139266878Shselasky *(arg.buf)++ = 0; 140266878Shselasky return retval; 141266878Shselasky} 142266878Shselasky 143334935Sianint 144334935Sianvsnprintf(char *buf, size_t size, const char *cfmt, va_list ap) 145334935Sian{ 146334935Sian struct print_buf arg; 147334935Sian int retval; 148334935Sian 149334935Sian arg.buf = buf; 150334935Sian arg.size = size; 151334935Sian 152334935Sian retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap); 153334935Sian 154334935Sian if (arg.size >= 1) 155334935Sian *(arg.buf)++ = 0; 156334935Sian 157334935Sian return (retval); 158334935Sian} 159334935Sian 160334935Sianint 16140805Smsmithvsprintf(char *buf, const char *cfmt, va_list ap) 16240805Smsmith{ 16340805Smsmith int retval; 16440805Smsmith 16540805Smsmith retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 16640805Smsmith buf[retval] = '\0'; 167334935Sian 168334935Sian return (retval); 16940805Smsmith} 17040805Smsmith 17138451Smsmith/* 172113159Speter * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse 173113159Speter * order; return an optional length and a pointer to the last character 174113159Speter * written in the buffer (i.e., the first character of the string). 175113159Speter * The buffer pointed to by `nbuf' must have length >= MAXNBUF. 17638451Smsmith */ 17738451Smsmithstatic char * 178156518Sjkimksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) 179113159Speter{ 180156518Sjkim char *p, c; 18138451Smsmith 182113159Speter p = nbuf; 183113159Speter *p = '\0'; 18438451Smsmith do { 185156518Sjkim c = hex2ascii(num % base); 186156518Sjkim *++p = upper ? toupper(c) : c; 187113159Speter } while (num /= base); 18838451Smsmith if (lenp) 189113159Speter *lenp = p - nbuf; 19038451Smsmith return (p); 19138451Smsmith} 19238451Smsmith 19338451Smsmith/* 19438451Smsmith * Scaled down version of printf(3). 19538451Smsmith * 19638451Smsmith * Two additional formats: 19738451Smsmith * 19838451Smsmith * The format %b is supported to decode error registers. 19938451Smsmith * Its usage is: 20038451Smsmith * 20138451Smsmith * printf("reg=%b\n", regval, "<base><arg>*"); 20238451Smsmith * 20338451Smsmith * where <base> is the output base expressed as a control character, e.g. 20438451Smsmith * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 20538451Smsmith * the first of which gives the bit number to be inspected (origin 1), and 20638451Smsmith * the next characters (up to a control character, i.e. a character <= 32), 20738451Smsmith * give the name of the register. Thus: 20838451Smsmith * 209277560Sdanfe * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE"); 21038451Smsmith * 21138451Smsmith * would produce output: 21238451Smsmith * 21338451Smsmith * reg=3<BITTWO,BITONE> 21438451Smsmith * 21538451Smsmith * XXX: %D -- Hexdump, takes pointer and separator string: 21638451Smsmith * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX 21738451Smsmith * ("%*D", len, ptr, " " -> XX XX XX XX ... 21838451Smsmith */ 21938451Smsmithstatic int 220266878Shselaskykvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap) 22138451Smsmith{ 222266878Shselasky#define PCHAR(c) {int cc=(c); if (func) (*func)(cc, arg); else *d++ = cc; retval++; } 223113159Speter char nbuf[MAXNBUF]; 224113159Speter char *d; 225113159Speter const char *p, *percent, *q; 226300078Simp uint16_t *S; 22738451Smsmith u_char *up; 22838451Smsmith int ch, n; 229113159Speter uintmax_t num; 230113159Speter int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 231209837Sjkim int cflag, hflag, jflag, tflag, zflag; 232156518Sjkim int dwidth, upper; 23338451Smsmith char padc; 234209837Sjkim int stop = 0, retval = 0; 23538451Smsmith 236113159Speter num = 0; 23738451Smsmith if (!func) 23838451Smsmith d = (char *) arg; 23938451Smsmith else 24038451Smsmith d = NULL; 24138451Smsmith 24238451Smsmith if (fmt == NULL) 24338451Smsmith fmt = "(fmt null)\n"; 24438451Smsmith 24538451Smsmith if (radix < 2 || radix > 36) 24638451Smsmith radix = 10; 24738451Smsmith 24838451Smsmith for (;;) { 24938451Smsmith padc = ' '; 25038451Smsmith width = 0; 251209837Sjkim while ((ch = (u_char)*fmt++) != '%' || stop) { 252113159Speter if (ch == '\0') 253113159Speter return (retval); 25438451Smsmith PCHAR(ch); 25538451Smsmith } 256113159Speter percent = fmt - 1; 257113159Speter qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 258156518Sjkim sign = 0; dot = 0; dwidth = 0; upper = 0; 259209837Sjkim cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; 26038451Smsmithreswitch: switch (ch = (u_char)*fmt++) { 26138451Smsmith case '.': 26238451Smsmith dot = 1; 26338451Smsmith goto reswitch; 26438451Smsmith case '#': 26538451Smsmith sharpflag = 1; 26638451Smsmith goto reswitch; 26738451Smsmith case '+': 26838451Smsmith sign = 1; 26938451Smsmith goto reswitch; 27038451Smsmith case '-': 27138451Smsmith ladjust = 1; 27238451Smsmith goto reswitch; 27338451Smsmith case '%': 27438451Smsmith PCHAR(ch); 27538451Smsmith break; 27638451Smsmith case '*': 27738451Smsmith if (!dot) { 27838451Smsmith width = va_arg(ap, int); 27938451Smsmith if (width < 0) { 28038451Smsmith ladjust = !ladjust; 28138451Smsmith width = -width; 28238451Smsmith } 28338451Smsmith } else { 28438451Smsmith dwidth = va_arg(ap, int); 28538451Smsmith } 28638451Smsmith goto reswitch; 28738451Smsmith case '0': 28838451Smsmith if (!dot) { 28938451Smsmith padc = '0'; 29038451Smsmith goto reswitch; 29138451Smsmith } 29238451Smsmith case '1': case '2': case '3': case '4': 29338451Smsmith case '5': case '6': case '7': case '8': case '9': 29438451Smsmith for (n = 0;; ++fmt) { 29538451Smsmith n = n * 10 + ch - '0'; 29638451Smsmith ch = *fmt; 29738451Smsmith if (ch < '0' || ch > '9') 29838451Smsmith break; 29938451Smsmith } 30038451Smsmith if (dot) 30138451Smsmith dwidth = n; 30238451Smsmith else 30338451Smsmith width = n; 30438451Smsmith goto reswitch; 30538451Smsmith case 'b': 306209837Sjkim num = (u_int)va_arg(ap, int); 30738451Smsmith p = va_arg(ap, char *); 308156518Sjkim for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) 30938451Smsmith PCHAR(*q--); 31038451Smsmith 311113159Speter if (num == 0) 31238451Smsmith break; 31338451Smsmith 31438451Smsmith for (tmp = 0; *p;) { 31538451Smsmith n = *p++; 316113159Speter if (num & (1 << (n - 1))) { 31738451Smsmith PCHAR(tmp ? ',' : '<'); 31838451Smsmith for (; (n = *p) > ' '; ++p) 31938451Smsmith PCHAR(n); 32038451Smsmith tmp = 1; 32138451Smsmith } else 32238451Smsmith for (; *p > ' '; ++p) 32338451Smsmith continue; 32438451Smsmith } 32538451Smsmith if (tmp) 32638451Smsmith PCHAR('>'); 32738451Smsmith break; 32838451Smsmith case 'c': 32938451Smsmith PCHAR(va_arg(ap, int)); 33038451Smsmith break; 33138451Smsmith case 'D': 33238451Smsmith up = va_arg(ap, u_char *); 33338451Smsmith p = va_arg(ap, char *); 33438451Smsmith if (!width) 33538451Smsmith width = 16; 33638451Smsmith while(width--) { 33738451Smsmith PCHAR(hex2ascii(*up >> 4)); 33838451Smsmith PCHAR(hex2ascii(*up & 0x0f)); 33938451Smsmith up++; 34038451Smsmith if (width) 34138451Smsmith for (q=p;*q;q++) 34238451Smsmith PCHAR(*q); 34338451Smsmith } 34438451Smsmith break; 34538451Smsmith case 'd': 346113159Speter case 'i': 347113159Speter base = 10; 34838451Smsmith sign = 1; 349113159Speter goto handle_sign; 350209837Sjkim case 'h': 351209837Sjkim if (hflag) { 352209837Sjkim hflag = 0; 353209837Sjkim cflag = 1; 354209837Sjkim } else 355209837Sjkim hflag = 1; 356209837Sjkim goto reswitch; 357113159Speter case 'j': 358113159Speter jflag = 1; 359113159Speter goto reswitch; 36038451Smsmith case 'l': 361113159Speter if (lflag) { 362113159Speter lflag = 0; 363113159Speter qflag = 1; 364113159Speter } else 365113159Speter lflag = 1; 36638451Smsmith goto reswitch; 36738451Smsmith case 'n': 368113159Speter if (jflag) 369113159Speter *(va_arg(ap, intmax_t *)) = retval; 370113159Speter else if (qflag) 371113159Speter *(va_arg(ap, quad_t *)) = retval; 372113159Speter else if (lflag) 373113159Speter *(va_arg(ap, long *)) = retval; 374113159Speter else if (zflag) 375113159Speter *(va_arg(ap, size_t *)) = retval; 376209837Sjkim else if (hflag) 377209837Sjkim *(va_arg(ap, short *)) = retval; 378209837Sjkim else if (cflag) 379209837Sjkim *(va_arg(ap, char *)) = retval; 380113159Speter else 381113159Speter *(va_arg(ap, int *)) = retval; 382113159Speter break; 38338451Smsmith case 'o': 38438451Smsmith base = 8; 385113159Speter goto handle_nosign; 38638451Smsmith case 'p': 38738451Smsmith base = 16; 388113159Speter sharpflag = (width == 0); 389113159Speter sign = 0; 390113159Speter num = (uintptr_t)va_arg(ap, void *); 39138451Smsmith goto number; 392113159Speter case 'q': 393113159Speter qflag = 1; 394113159Speter goto reswitch; 395113159Speter case 'r': 396113159Speter base = radix; 397113159Speter if (sign) 398113159Speter goto handle_sign; 399113159Speter goto handle_nosign; 40038451Smsmith case 's': 40138451Smsmith p = va_arg(ap, char *); 40238451Smsmith if (p == NULL) 40338451Smsmith p = "(null)"; 40438451Smsmith if (!dot) 40538451Smsmith n = strlen (p); 40638451Smsmith else 40738451Smsmith for (n = 0; n < dwidth && p[n]; n++) 40838451Smsmith continue; 40938451Smsmith 41038451Smsmith width -= n; 41138451Smsmith 41238451Smsmith if (!ladjust && width > 0) 41338451Smsmith while (width--) 41438451Smsmith PCHAR(padc); 41538451Smsmith while (n--) 41638451Smsmith PCHAR(*p++); 41738451Smsmith if (ladjust && width > 0) 41838451Smsmith while (width--) 41938451Smsmith PCHAR(padc); 42038451Smsmith break; 421300078Simp case 'S': /* Assume console can cope with wide chars */ 422300078Simp for (S = va_arg(ap, uint16_t *); *S != 0; S++) 423300078Simp PCHAR(*S); 424300078Simp break; 425113159Speter case 't': 426113159Speter tflag = 1; 427113159Speter goto reswitch; 42838451Smsmith case 'u': 42938451Smsmith base = 10; 430113159Speter goto handle_nosign; 431156518Sjkim case 'X': 432156518Sjkim upper = 1; 43338451Smsmith case 'x': 43438451Smsmith base = 16; 435113159Speter goto handle_nosign; 436113159Speter case 'y': 437113159Speter base = 16; 438113159Speter sign = 1; 439113159Speter goto handle_sign; 440113159Speter case 'z': 441113159Speter zflag = 1; 442113159Speter goto reswitch; 443113159Speterhandle_nosign: 444113159Speter sign = 0; 445113159Speter if (jflag) 446113159Speter num = va_arg(ap, uintmax_t); 447113159Speter else if (qflag) 448113159Speter num = va_arg(ap, u_quad_t); 449113159Speter else if (tflag) 450113159Speter num = va_arg(ap, ptrdiff_t); 451113159Speter else if (lflag) 452113159Speter num = va_arg(ap, u_long); 453113159Speter else if (zflag) 454113159Speter num = va_arg(ap, size_t); 455209837Sjkim else if (hflag) 456209837Sjkim num = (u_short)va_arg(ap, int); 457209837Sjkim else if (cflag) 458209837Sjkim num = (u_char)va_arg(ap, int); 459113159Speter else 460113159Speter num = va_arg(ap, u_int); 461113159Speter goto number; 462113159Speterhandle_sign: 463113159Speter if (jflag) 464113159Speter num = va_arg(ap, intmax_t); 465113159Speter else if (qflag) 466113159Speter num = va_arg(ap, quad_t); 467113159Speter else if (tflag) 468113159Speter num = va_arg(ap, ptrdiff_t); 469113159Speter else if (lflag) 470113159Speter num = va_arg(ap, long); 471113159Speter else if (zflag) 472185037Sdelphij num = va_arg(ap, ssize_t); 473209837Sjkim else if (hflag) 474209837Sjkim num = (short)va_arg(ap, int); 475209837Sjkim else if (cflag) 476209837Sjkim num = (char)va_arg(ap, int); 477113159Speter else 478113159Speter num = va_arg(ap, int); 479113159Speternumber: 480113159Speter if (sign && (intmax_t)num < 0) { 48138451Smsmith neg = 1; 482113159Speter num = -(intmax_t)num; 48338451Smsmith } 484209837Sjkim p = ksprintn(nbuf, num, base, &n, upper); 485209837Sjkim tmp = 0; 486113159Speter if (sharpflag && num != 0) { 48738451Smsmith if (base == 8) 48838451Smsmith tmp++; 48938451Smsmith else if (base == 16) 49038451Smsmith tmp += 2; 49138451Smsmith } 49238451Smsmith if (neg) 49338451Smsmith tmp++; 49438451Smsmith 495209837Sjkim if (!ladjust && padc == '0') 496209837Sjkim dwidth = width - tmp; 497209949Sjkim width -= tmp + imax(dwidth, n); 498209837Sjkim dwidth -= n; 499209837Sjkim if (!ladjust) 500209837Sjkim while (width-- > 0) 501209837Sjkim PCHAR(' '); 50238451Smsmith if (neg) 50338451Smsmith PCHAR('-'); 504113159Speter if (sharpflag && num != 0) { 50538451Smsmith if (base == 8) { 50638451Smsmith PCHAR('0'); 50738451Smsmith } else if (base == 16) { 50838451Smsmith PCHAR('0'); 50938451Smsmith PCHAR('x'); 51038451Smsmith } 51138451Smsmith } 512209837Sjkim while (dwidth-- > 0) 513209837Sjkim PCHAR('0'); 51438451Smsmith 51538451Smsmith while (*p) 51638451Smsmith PCHAR(*p--); 51738451Smsmith 518209837Sjkim if (ladjust) 519209837Sjkim while (width-- > 0) 520209837Sjkim PCHAR(' '); 52138451Smsmith 52238451Smsmith break; 52338451Smsmith default: 524113159Speter while (percent < fmt) 525113159Speter PCHAR(*percent++); 526209837Sjkim /* 527277560Sdanfe * Since we ignore a formatting argument it is no 528209837Sjkim * longer safe to obey the remaining formatting 529209837Sjkim * arguments as the arguments will no longer match 530209837Sjkim * the format specs. 531209837Sjkim */ 532209837Sjkim stop = 1; 53338451Smsmith break; 53438451Smsmith } 53538451Smsmith } 53638451Smsmith#undef PCHAR 53738451Smsmith} 538