printf.c revision 185037
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: head/lib/libstand/printf.c 185037 2008-11-18 00:01:16Z delphij $"); 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 59156518Sjkimstatic char *ksprintn (char *buf, uintmax_t num, int base, int *len, int upper); 6038451Smsmithstatic int kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap); 6138451Smsmith 6238451Smsmithint 6338451Smsmithprintf(const char *fmt, ...) 6438451Smsmith{ 6538451Smsmith va_list ap; 6638451Smsmith int retval; 6738451Smsmith 6838451Smsmith va_start(ap, fmt); 6938451Smsmith retval = kvprintf(fmt, putchar, NULL, 10, ap); 7038451Smsmith va_end(ap); 7138451Smsmith return retval; 7238451Smsmith} 7338451Smsmith 7438451Smsmithvoid 7538451Smsmithvprintf(const char *fmt, va_list ap) 7638451Smsmith{ 7738451Smsmith 7838451Smsmith kvprintf(fmt, putchar, NULL, 10, ap); 7938451Smsmith} 8038451Smsmith 8138451Smsmithint 8238451Smsmithsprintf(char *buf, const char *cfmt, ...) 8338451Smsmith{ 8438451Smsmith int retval; 8538451Smsmith va_list ap; 8638451Smsmith 8738451Smsmith va_start(ap, cfmt); 8838451Smsmith retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 8938451Smsmith buf[retval] = '\0'; 9038451Smsmith va_end(ap); 9138451Smsmith return retval; 9238451Smsmith} 9338451Smsmith 9440805Smsmithvoid 9540805Smsmithvsprintf(char *buf, const char *cfmt, va_list ap) 9640805Smsmith{ 9740805Smsmith int retval; 9840805Smsmith 9940805Smsmith retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 10040805Smsmith buf[retval] = '\0'; 10140805Smsmith} 10240805Smsmith 10338451Smsmith/* 104113159Speter * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse 105113159Speter * order; return an optional length and a pointer to the last character 106113159Speter * written in the buffer (i.e., the first character of the string). 107113159Speter * The buffer pointed to by `nbuf' must have length >= MAXNBUF. 10838451Smsmith */ 10938451Smsmithstatic char * 110156518Sjkimksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) 111113159Speter{ 112156518Sjkim char *p, c; 11338451Smsmith 114113159Speter p = nbuf; 115113159Speter *p = '\0'; 11638451Smsmith do { 117156518Sjkim c = hex2ascii(num % base); 118156518Sjkim *++p = upper ? toupper(c) : c; 119113159Speter } while (num /= base); 12038451Smsmith if (lenp) 121113159Speter *lenp = p - nbuf; 12238451Smsmith return (p); 12338451Smsmith} 12438451Smsmith 12538451Smsmith/* 12638451Smsmith * Scaled down version of printf(3). 12738451Smsmith * 12838451Smsmith * Two additional formats: 12938451Smsmith * 13038451Smsmith * The format %b is supported to decode error registers. 13138451Smsmith * Its usage is: 13238451Smsmith * 13338451Smsmith * printf("reg=%b\n", regval, "<base><arg>*"); 13438451Smsmith * 13538451Smsmith * where <base> is the output base expressed as a control character, e.g. 13638451Smsmith * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 13738451Smsmith * the first of which gives the bit number to be inspected (origin 1), and 13838451Smsmith * the next characters (up to a control character, i.e. a character <= 32), 13938451Smsmith * give the name of the register. Thus: 14038451Smsmith * 14138451Smsmith * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 14238451Smsmith * 14338451Smsmith * would produce output: 14438451Smsmith * 14538451Smsmith * reg=3<BITTWO,BITONE> 14638451Smsmith * 14738451Smsmith * XXX: %D -- Hexdump, takes pointer and separator string: 14838451Smsmith * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX 14938451Smsmith * ("%*D", len, ptr, " " -> XX XX XX XX ... 15038451Smsmith */ 15138451Smsmithstatic int 15238451Smsmithkvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap) 15338451Smsmith{ 15438451Smsmith#define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; } 155113159Speter char nbuf[MAXNBUF]; 156113159Speter char *d; 157113159Speter const char *p, *percent, *q; 15838451Smsmith u_char *up; 15938451Smsmith int ch, n; 160113159Speter uintmax_t num; 161113159Speter int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 162113159Speter int jflag, tflag, zflag; 163156518Sjkim int dwidth, upper; 16438451Smsmith char padc; 16538451Smsmith int retval = 0; 16638451Smsmith 167113159Speter num = 0; 16838451Smsmith if (!func) 16938451Smsmith d = (char *) arg; 17038451Smsmith else 17138451Smsmith d = NULL; 17238451Smsmith 17338451Smsmith if (fmt == NULL) 17438451Smsmith fmt = "(fmt null)\n"; 17538451Smsmith 17638451Smsmith if (radix < 2 || radix > 36) 17738451Smsmith radix = 10; 17838451Smsmith 17938451Smsmith for (;;) { 18038451Smsmith padc = ' '; 18138451Smsmith width = 0; 18238451Smsmith while ((ch = (u_char)*fmt++) != '%') { 183113159Speter if (ch == '\0') 184113159Speter return (retval); 18538451Smsmith PCHAR(ch); 18638451Smsmith } 187113159Speter percent = fmt - 1; 188113159Speter qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 189156518Sjkim sign = 0; dot = 0; dwidth = 0; upper = 0; 190113159Speter jflag = 0; tflag = 0; zflag = 0; 19138451Smsmithreswitch: switch (ch = (u_char)*fmt++) { 19238451Smsmith case '.': 19338451Smsmith dot = 1; 19438451Smsmith goto reswitch; 19538451Smsmith case '#': 19638451Smsmith sharpflag = 1; 19738451Smsmith goto reswitch; 19838451Smsmith case '+': 19938451Smsmith sign = 1; 20038451Smsmith goto reswitch; 20138451Smsmith case '-': 20238451Smsmith ladjust = 1; 20338451Smsmith goto reswitch; 20438451Smsmith case '%': 20538451Smsmith PCHAR(ch); 20638451Smsmith break; 20738451Smsmith case '*': 20838451Smsmith if (!dot) { 20938451Smsmith width = va_arg(ap, int); 21038451Smsmith if (width < 0) { 21138451Smsmith ladjust = !ladjust; 21238451Smsmith width = -width; 21338451Smsmith } 21438451Smsmith } else { 21538451Smsmith dwidth = va_arg(ap, int); 21638451Smsmith } 21738451Smsmith goto reswitch; 21838451Smsmith case '0': 21938451Smsmith if (!dot) { 22038451Smsmith padc = '0'; 22138451Smsmith goto reswitch; 22238451Smsmith } 22338451Smsmith case '1': case '2': case '3': case '4': 22438451Smsmith case '5': case '6': case '7': case '8': case '9': 22538451Smsmith for (n = 0;; ++fmt) { 22638451Smsmith n = n * 10 + ch - '0'; 22738451Smsmith ch = *fmt; 22838451Smsmith if (ch < '0' || ch > '9') 22938451Smsmith break; 23038451Smsmith } 23138451Smsmith if (dot) 23238451Smsmith dwidth = n; 23338451Smsmith else 23438451Smsmith width = n; 23538451Smsmith goto reswitch; 23638451Smsmith case 'b': 237113159Speter num = va_arg(ap, int); 23838451Smsmith p = va_arg(ap, char *); 239156518Sjkim for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) 24038451Smsmith PCHAR(*q--); 24138451Smsmith 242113159Speter if (num == 0) 24338451Smsmith break; 24438451Smsmith 24538451Smsmith for (tmp = 0; *p;) { 24638451Smsmith n = *p++; 247113159Speter if (num & (1 << (n - 1))) { 24838451Smsmith PCHAR(tmp ? ',' : '<'); 24938451Smsmith for (; (n = *p) > ' '; ++p) 25038451Smsmith PCHAR(n); 25138451Smsmith tmp = 1; 25238451Smsmith } else 25338451Smsmith for (; *p > ' '; ++p) 25438451Smsmith continue; 25538451Smsmith } 25638451Smsmith if (tmp) 25738451Smsmith PCHAR('>'); 25838451Smsmith break; 25938451Smsmith case 'c': 26038451Smsmith PCHAR(va_arg(ap, int)); 26138451Smsmith break; 26238451Smsmith case 'D': 26338451Smsmith up = va_arg(ap, u_char *); 26438451Smsmith p = va_arg(ap, char *); 26538451Smsmith if (!width) 26638451Smsmith width = 16; 26738451Smsmith while(width--) { 26838451Smsmith PCHAR(hex2ascii(*up >> 4)); 26938451Smsmith PCHAR(hex2ascii(*up & 0x0f)); 27038451Smsmith up++; 27138451Smsmith if (width) 27238451Smsmith for (q=p;*q;q++) 27338451Smsmith PCHAR(*q); 27438451Smsmith } 27538451Smsmith break; 27638451Smsmith case 'd': 277113159Speter case 'i': 278113159Speter base = 10; 27938451Smsmith sign = 1; 280113159Speter goto handle_sign; 281113159Speter case 'j': 282113159Speter jflag = 1; 283113159Speter goto reswitch; 28438451Smsmith case 'l': 285113159Speter if (lflag) { 286113159Speter lflag = 0; 287113159Speter qflag = 1; 288113159Speter } else 289113159Speter lflag = 1; 29038451Smsmith goto reswitch; 29138451Smsmith case 'n': 292113159Speter if (jflag) 293113159Speter *(va_arg(ap, intmax_t *)) = retval; 294113159Speter else if (qflag) 295113159Speter *(va_arg(ap, quad_t *)) = retval; 296113159Speter else if (lflag) 297113159Speter *(va_arg(ap, long *)) = retval; 298113159Speter else if (zflag) 299113159Speter *(va_arg(ap, size_t *)) = retval; 300113159Speter else 301113159Speter *(va_arg(ap, int *)) = retval; 302113159Speter break; 30338451Smsmith case 'o': 30438451Smsmith base = 8; 305113159Speter goto handle_nosign; 30638451Smsmith case 'p': 30738451Smsmith base = 16; 308113159Speter sharpflag = (width == 0); 309113159Speter sign = 0; 310113159Speter num = (uintptr_t)va_arg(ap, void *); 31138451Smsmith goto number; 312113159Speter case 'q': 313113159Speter qflag = 1; 314113159Speter goto reswitch; 315113159Speter case 'r': 316113159Speter base = radix; 317113159Speter if (sign) 318113159Speter goto handle_sign; 319113159Speter goto handle_nosign; 32038451Smsmith case 's': 32138451Smsmith p = va_arg(ap, char *); 32238451Smsmith if (p == NULL) 32338451Smsmith p = "(null)"; 32438451Smsmith if (!dot) 32538451Smsmith n = strlen (p); 32638451Smsmith else 32738451Smsmith for (n = 0; n < dwidth && p[n]; n++) 32838451Smsmith continue; 32938451Smsmith 33038451Smsmith width -= n; 33138451Smsmith 33238451Smsmith if (!ladjust && width > 0) 33338451Smsmith while (width--) 33438451Smsmith PCHAR(padc); 33538451Smsmith while (n--) 33638451Smsmith PCHAR(*p++); 33738451Smsmith if (ladjust && width > 0) 33838451Smsmith while (width--) 33938451Smsmith PCHAR(padc); 34038451Smsmith break; 341113159Speter case 't': 342113159Speter tflag = 1; 343113159Speter goto reswitch; 34438451Smsmith case 'u': 34538451Smsmith base = 10; 346113159Speter goto handle_nosign; 347156518Sjkim case 'X': 348156518Sjkim upper = 1; 34938451Smsmith case 'x': 35038451Smsmith base = 16; 351113159Speter goto handle_nosign; 352113159Speter case 'y': 353113159Speter base = 16; 354113159Speter sign = 1; 355113159Speter goto handle_sign; 356113159Speter case 'z': 357113159Speter zflag = 1; 358113159Speter goto reswitch; 359113159Speterhandle_nosign: 360113159Speter sign = 0; 361113159Speter if (jflag) 362113159Speter num = va_arg(ap, uintmax_t); 363113159Speter else if (qflag) 364113159Speter num = va_arg(ap, u_quad_t); 365113159Speter else if (tflag) 366113159Speter num = va_arg(ap, ptrdiff_t); 367113159Speter else if (lflag) 368113159Speter num = va_arg(ap, u_long); 369113159Speter else if (zflag) 370113159Speter num = va_arg(ap, size_t); 371113159Speter else 372113159Speter num = va_arg(ap, u_int); 373113159Speter goto number; 374113159Speterhandle_sign: 375113159Speter if (jflag) 376113159Speter num = va_arg(ap, intmax_t); 377113159Speter else if (qflag) 378113159Speter num = va_arg(ap, quad_t); 379113159Speter else if (tflag) 380113159Speter num = va_arg(ap, ptrdiff_t); 381113159Speter else if (lflag) 382113159Speter num = va_arg(ap, long); 383113159Speter else if (zflag) 384185037Sdelphij num = va_arg(ap, ssize_t); 385113159Speter else 386113159Speter num = va_arg(ap, int); 387113159Speternumber: 388113159Speter if (sign && (intmax_t)num < 0) { 38938451Smsmith neg = 1; 390113159Speter num = -(intmax_t)num; 39138451Smsmith } 392156518Sjkim p = ksprintn(nbuf, num, base, &tmp, upper); 393113159Speter if (sharpflag && num != 0) { 39438451Smsmith if (base == 8) 39538451Smsmith tmp++; 39638451Smsmith else if (base == 16) 39738451Smsmith tmp += 2; 39838451Smsmith } 39938451Smsmith if (neg) 40038451Smsmith tmp++; 40138451Smsmith 40238451Smsmith if (!ladjust && width && (width -= tmp) > 0) 40338451Smsmith while (width--) 40438451Smsmith PCHAR(padc); 40538451Smsmith if (neg) 40638451Smsmith PCHAR('-'); 407113159Speter if (sharpflag && num != 0) { 40838451Smsmith if (base == 8) { 40938451Smsmith PCHAR('0'); 41038451Smsmith } else if (base == 16) { 41138451Smsmith PCHAR('0'); 41238451Smsmith PCHAR('x'); 41338451Smsmith } 41438451Smsmith } 41538451Smsmith 41638451Smsmith while (*p) 41738451Smsmith PCHAR(*p--); 41838451Smsmith 41938451Smsmith if (ladjust && width && (width -= tmp) > 0) 42038451Smsmith while (width--) 42138451Smsmith PCHAR(padc); 42238451Smsmith 42338451Smsmith break; 42438451Smsmith default: 425113159Speter while (percent < fmt) 426113159Speter PCHAR(*percent++); 42738451Smsmith break; 42838451Smsmith } 42938451Smsmith } 43038451Smsmith#undef PCHAR 43138451Smsmith} 432