printf.c revision 156518
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 * 3. All advertising materials mentioning features or use of this software 1938451Smsmith * must display the following acknowledgement: 2038451Smsmith * This product includes software developed by the University of 2138451Smsmith * California, Berkeley and its contributors. 2238451Smsmith * 4. Neither the name of the University nor the names of its contributors 2338451Smsmith * may be used to endorse or promote products derived from this software 2438451Smsmith * without specific prior written permission. 2538451Smsmith * 2638451Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2738451Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2838451Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2938451Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3038451Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3138451Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3238451Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3338451Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3438451Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3538451Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3638451Smsmith * SUCH DAMAGE. 3738451Smsmith * 3838451Smsmith * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 3938451Smsmith */ 4038451Smsmith 4184221Sdillon#include <sys/cdefs.h> 4284221Sdillon__FBSDID("$FreeBSD: head/lib/libstand/printf.c 156518 2006-03-09 22:37:34Z jkim $"); 4384221Sdillon 4438451Smsmith/* 4538451Smsmith * Standaloneified version of the FreeBSD kernel printf family. 4638451Smsmith */ 4738451Smsmith 4838451Smsmith#include <sys/types.h> 49113159Speter#include <sys/stddef.h> 50113159Speter#include <sys/stdint.h> 51103949Smike#include <limits.h> 5255137Speter#include <string.h> 5338451Smsmith#include "stand.h" 5438451Smsmith 5538451Smsmith/* 5638451Smsmith * Note that stdarg.h and the ANSI style va_start macro is used for both 5738451Smsmith * ANSI and traditional C compilers. 5838451Smsmith */ 5938451Smsmith#include <machine/stdarg.h> 6038451Smsmith 61113159Speter#define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1) 62113159Speter 63156518Sjkimstatic char *ksprintn (char *buf, uintmax_t num, int base, int *len, int upper); 6438451Smsmithstatic int kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap); 6538451Smsmith 6638451Smsmithint 6738451Smsmithprintf(const char *fmt, ...) 6838451Smsmith{ 6938451Smsmith va_list ap; 7038451Smsmith int retval; 7138451Smsmith 7238451Smsmith va_start(ap, fmt); 7338451Smsmith retval = kvprintf(fmt, putchar, NULL, 10, ap); 7438451Smsmith va_end(ap); 7538451Smsmith return retval; 7638451Smsmith} 7738451Smsmith 7838451Smsmithvoid 7938451Smsmithvprintf(const char *fmt, va_list ap) 8038451Smsmith{ 8138451Smsmith 8238451Smsmith kvprintf(fmt, putchar, NULL, 10, ap); 8338451Smsmith} 8438451Smsmith 8538451Smsmithint 8638451Smsmithsprintf(char *buf, const char *cfmt, ...) 8738451Smsmith{ 8838451Smsmith int retval; 8938451Smsmith va_list ap; 9038451Smsmith 9138451Smsmith va_start(ap, cfmt); 9238451Smsmith retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 9338451Smsmith buf[retval] = '\0'; 9438451Smsmith va_end(ap); 9538451Smsmith return retval; 9638451Smsmith} 9738451Smsmith 9840805Smsmithvoid 9940805Smsmithvsprintf(char *buf, const char *cfmt, va_list ap) 10040805Smsmith{ 10140805Smsmith int retval; 10240805Smsmith 10340805Smsmith retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 10440805Smsmith buf[retval] = '\0'; 10540805Smsmith} 10640805Smsmith 10738451Smsmith/* 108113159Speter * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse 109113159Speter * order; return an optional length and a pointer to the last character 110113159Speter * written in the buffer (i.e., the first character of the string). 111113159Speter * The buffer pointed to by `nbuf' must have length >= MAXNBUF. 11238451Smsmith */ 11338451Smsmithstatic char * 114156518Sjkimksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) 115113159Speter{ 116156518Sjkim char *p, c; 11738451Smsmith 118113159Speter p = nbuf; 119113159Speter *p = '\0'; 12038451Smsmith do { 121156518Sjkim c = hex2ascii(num % base); 122156518Sjkim *++p = upper ? toupper(c) : c; 123113159Speter } while (num /= base); 12438451Smsmith if (lenp) 125113159Speter *lenp = p - nbuf; 12638451Smsmith return (p); 12738451Smsmith} 12838451Smsmith 12938451Smsmith/* 13038451Smsmith * Scaled down version of printf(3). 13138451Smsmith * 13238451Smsmith * Two additional formats: 13338451Smsmith * 13438451Smsmith * The format %b is supported to decode error registers. 13538451Smsmith * Its usage is: 13638451Smsmith * 13738451Smsmith * printf("reg=%b\n", regval, "<base><arg>*"); 13838451Smsmith * 13938451Smsmith * where <base> is the output base expressed as a control character, e.g. 14038451Smsmith * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 14138451Smsmith * the first of which gives the bit number to be inspected (origin 1), and 14238451Smsmith * the next characters (up to a control character, i.e. a character <= 32), 14338451Smsmith * give the name of the register. Thus: 14438451Smsmith * 14538451Smsmith * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 14638451Smsmith * 14738451Smsmith * would produce output: 14838451Smsmith * 14938451Smsmith * reg=3<BITTWO,BITONE> 15038451Smsmith * 15138451Smsmith * XXX: %D -- Hexdump, takes pointer and separator string: 15238451Smsmith * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX 15338451Smsmith * ("%*D", len, ptr, " " -> XX XX XX XX ... 15438451Smsmith */ 15538451Smsmithstatic int 15638451Smsmithkvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap) 15738451Smsmith{ 15838451Smsmith#define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; } 159113159Speter char nbuf[MAXNBUF]; 160113159Speter char *d; 161113159Speter const char *p, *percent, *q; 16238451Smsmith u_char *up; 16338451Smsmith int ch, n; 164113159Speter uintmax_t num; 165113159Speter int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 166113159Speter int jflag, tflag, zflag; 167156518Sjkim int dwidth, upper; 16838451Smsmith char padc; 16938451Smsmith int retval = 0; 17038451Smsmith 171113159Speter num = 0; 17238451Smsmith if (!func) 17338451Smsmith d = (char *) arg; 17438451Smsmith else 17538451Smsmith d = NULL; 17638451Smsmith 17738451Smsmith if (fmt == NULL) 17838451Smsmith fmt = "(fmt null)\n"; 17938451Smsmith 18038451Smsmith if (radix < 2 || radix > 36) 18138451Smsmith radix = 10; 18238451Smsmith 18338451Smsmith for (;;) { 18438451Smsmith padc = ' '; 18538451Smsmith width = 0; 18638451Smsmith while ((ch = (u_char)*fmt++) != '%') { 187113159Speter if (ch == '\0') 188113159Speter return (retval); 18938451Smsmith PCHAR(ch); 19038451Smsmith } 191113159Speter percent = fmt - 1; 192113159Speter qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 193156518Sjkim sign = 0; dot = 0; dwidth = 0; upper = 0; 194113159Speter jflag = 0; tflag = 0; zflag = 0; 19538451Smsmithreswitch: switch (ch = (u_char)*fmt++) { 19638451Smsmith case '.': 19738451Smsmith dot = 1; 19838451Smsmith goto reswitch; 19938451Smsmith case '#': 20038451Smsmith sharpflag = 1; 20138451Smsmith goto reswitch; 20238451Smsmith case '+': 20338451Smsmith sign = 1; 20438451Smsmith goto reswitch; 20538451Smsmith case '-': 20638451Smsmith ladjust = 1; 20738451Smsmith goto reswitch; 20838451Smsmith case '%': 20938451Smsmith PCHAR(ch); 21038451Smsmith break; 21138451Smsmith case '*': 21238451Smsmith if (!dot) { 21338451Smsmith width = va_arg(ap, int); 21438451Smsmith if (width < 0) { 21538451Smsmith ladjust = !ladjust; 21638451Smsmith width = -width; 21738451Smsmith } 21838451Smsmith } else { 21938451Smsmith dwidth = va_arg(ap, int); 22038451Smsmith } 22138451Smsmith goto reswitch; 22238451Smsmith case '0': 22338451Smsmith if (!dot) { 22438451Smsmith padc = '0'; 22538451Smsmith goto reswitch; 22638451Smsmith } 22738451Smsmith case '1': case '2': case '3': case '4': 22838451Smsmith case '5': case '6': case '7': case '8': case '9': 22938451Smsmith for (n = 0;; ++fmt) { 23038451Smsmith n = n * 10 + ch - '0'; 23138451Smsmith ch = *fmt; 23238451Smsmith if (ch < '0' || ch > '9') 23338451Smsmith break; 23438451Smsmith } 23538451Smsmith if (dot) 23638451Smsmith dwidth = n; 23738451Smsmith else 23838451Smsmith width = n; 23938451Smsmith goto reswitch; 24038451Smsmith case 'b': 241113159Speter num = va_arg(ap, int); 24238451Smsmith p = va_arg(ap, char *); 243156518Sjkim for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) 24438451Smsmith PCHAR(*q--); 24538451Smsmith 246113159Speter if (num == 0) 24738451Smsmith break; 24838451Smsmith 24938451Smsmith for (tmp = 0; *p;) { 25038451Smsmith n = *p++; 251113159Speter if (num & (1 << (n - 1))) { 25238451Smsmith PCHAR(tmp ? ',' : '<'); 25338451Smsmith for (; (n = *p) > ' '; ++p) 25438451Smsmith PCHAR(n); 25538451Smsmith tmp = 1; 25638451Smsmith } else 25738451Smsmith for (; *p > ' '; ++p) 25838451Smsmith continue; 25938451Smsmith } 26038451Smsmith if (tmp) 26138451Smsmith PCHAR('>'); 26238451Smsmith break; 26338451Smsmith case 'c': 26438451Smsmith PCHAR(va_arg(ap, int)); 26538451Smsmith break; 26638451Smsmith case 'D': 26738451Smsmith up = va_arg(ap, u_char *); 26838451Smsmith p = va_arg(ap, char *); 26938451Smsmith if (!width) 27038451Smsmith width = 16; 27138451Smsmith while(width--) { 27238451Smsmith PCHAR(hex2ascii(*up >> 4)); 27338451Smsmith PCHAR(hex2ascii(*up & 0x0f)); 27438451Smsmith up++; 27538451Smsmith if (width) 27638451Smsmith for (q=p;*q;q++) 27738451Smsmith PCHAR(*q); 27838451Smsmith } 27938451Smsmith break; 28038451Smsmith case 'd': 281113159Speter case 'i': 282113159Speter base = 10; 28338451Smsmith sign = 1; 284113159Speter goto handle_sign; 285113159Speter case 'j': 286113159Speter jflag = 1; 287113159Speter goto reswitch; 28838451Smsmith case 'l': 289113159Speter if (lflag) { 290113159Speter lflag = 0; 291113159Speter qflag = 1; 292113159Speter } else 293113159Speter lflag = 1; 29438451Smsmith goto reswitch; 29538451Smsmith case 'n': 296113159Speter if (jflag) 297113159Speter *(va_arg(ap, intmax_t *)) = retval; 298113159Speter else if (qflag) 299113159Speter *(va_arg(ap, quad_t *)) = retval; 300113159Speter else if (lflag) 301113159Speter *(va_arg(ap, long *)) = retval; 302113159Speter else if (zflag) 303113159Speter *(va_arg(ap, size_t *)) = retval; 304113159Speter else 305113159Speter *(va_arg(ap, int *)) = retval; 306113159Speter break; 30738451Smsmith case 'o': 30838451Smsmith base = 8; 309113159Speter goto handle_nosign; 31038451Smsmith case 'p': 31138451Smsmith base = 16; 312113159Speter sharpflag = (width == 0); 313113159Speter sign = 0; 314113159Speter num = (uintptr_t)va_arg(ap, void *); 31538451Smsmith goto number; 316113159Speter case 'q': 317113159Speter qflag = 1; 318113159Speter goto reswitch; 319113159Speter case 'r': 320113159Speter base = radix; 321113159Speter if (sign) 322113159Speter goto handle_sign; 323113159Speter goto handle_nosign; 32438451Smsmith case 's': 32538451Smsmith p = va_arg(ap, char *); 32638451Smsmith if (p == NULL) 32738451Smsmith p = "(null)"; 32838451Smsmith if (!dot) 32938451Smsmith n = strlen (p); 33038451Smsmith else 33138451Smsmith for (n = 0; n < dwidth && p[n]; n++) 33238451Smsmith continue; 33338451Smsmith 33438451Smsmith width -= n; 33538451Smsmith 33638451Smsmith if (!ladjust && width > 0) 33738451Smsmith while (width--) 33838451Smsmith PCHAR(padc); 33938451Smsmith while (n--) 34038451Smsmith PCHAR(*p++); 34138451Smsmith if (ladjust && width > 0) 34238451Smsmith while (width--) 34338451Smsmith PCHAR(padc); 34438451Smsmith break; 345113159Speter case 't': 346113159Speter tflag = 1; 347113159Speter goto reswitch; 34838451Smsmith case 'u': 34938451Smsmith base = 10; 350113159Speter goto handle_nosign; 351156518Sjkim case 'X': 352156518Sjkim upper = 1; 35338451Smsmith case 'x': 35438451Smsmith base = 16; 355113159Speter goto handle_nosign; 356113159Speter case 'y': 357113159Speter base = 16; 358113159Speter sign = 1; 359113159Speter goto handle_sign; 360113159Speter case 'z': 361113159Speter zflag = 1; 362113159Speter goto reswitch; 363113159Speterhandle_nosign: 364113159Speter sign = 0; 365113159Speter if (jflag) 366113159Speter num = va_arg(ap, uintmax_t); 367113159Speter else if (qflag) 368113159Speter num = va_arg(ap, u_quad_t); 369113159Speter else if (tflag) 370113159Speter num = va_arg(ap, ptrdiff_t); 371113159Speter else if (lflag) 372113159Speter num = va_arg(ap, u_long); 373113159Speter else if (zflag) 374113159Speter num = va_arg(ap, size_t); 375113159Speter else 376113159Speter num = va_arg(ap, u_int); 377113159Speter goto number; 378113159Speterhandle_sign: 379113159Speter if (jflag) 380113159Speter num = va_arg(ap, intmax_t); 381113159Speter else if (qflag) 382113159Speter num = va_arg(ap, quad_t); 383113159Speter else if (tflag) 384113159Speter num = va_arg(ap, ptrdiff_t); 385113159Speter else if (lflag) 386113159Speter num = va_arg(ap, long); 387113159Speter else if (zflag) 388113159Speter num = va_arg(ap, size_t); 389113159Speter else 390113159Speter num = va_arg(ap, int); 391113159Speternumber: 392113159Speter if (sign && (intmax_t)num < 0) { 39338451Smsmith neg = 1; 394113159Speter num = -(intmax_t)num; 39538451Smsmith } 396156518Sjkim p = ksprintn(nbuf, num, base, &tmp, upper); 397113159Speter if (sharpflag && num != 0) { 39838451Smsmith if (base == 8) 39938451Smsmith tmp++; 40038451Smsmith else if (base == 16) 40138451Smsmith tmp += 2; 40238451Smsmith } 40338451Smsmith if (neg) 40438451Smsmith tmp++; 40538451Smsmith 40638451Smsmith if (!ladjust && width && (width -= tmp) > 0) 40738451Smsmith while (width--) 40838451Smsmith PCHAR(padc); 40938451Smsmith if (neg) 41038451Smsmith PCHAR('-'); 411113159Speter if (sharpflag && num != 0) { 41238451Smsmith if (base == 8) { 41338451Smsmith PCHAR('0'); 41438451Smsmith } else if (base == 16) { 41538451Smsmith PCHAR('0'); 41638451Smsmith PCHAR('x'); 41738451Smsmith } 41838451Smsmith } 41938451Smsmith 42038451Smsmith while (*p) 42138451Smsmith PCHAR(*p--); 42238451Smsmith 42338451Smsmith if (ladjust && width && (width -= tmp) > 0) 42438451Smsmith while (width--) 42538451Smsmith PCHAR(padc); 42638451Smsmith 42738451Smsmith break; 42838451Smsmith default: 429113159Speter while (percent < fmt) 430113159Speter PCHAR(*percent++); 43138451Smsmith break; 43238451Smsmith } 43338451Smsmith } 43438451Smsmith#undef PCHAR 43538451Smsmith} 436