printfcommon.h revision 187354
1187277Sdas/*- 2187277Sdas * Copyright (c) 1990, 1993 3187277Sdas * The Regents of the University of California. All rights reserved. 4187277Sdas * 5187277Sdas * This code is derived from software contributed to Berkeley by 6187277Sdas * Chris Torek. 7187277Sdas * 8187277Sdas * Redistribution and use in source and binary forms, with or without 9187277Sdas * modification, are permitted provided that the following conditions 10187277Sdas * are met: 11187277Sdas * 1. Redistributions of source code must retain the above copyright 12187277Sdas * notice, this list of conditions and the following disclaimer. 13187277Sdas * 2. Redistributions in binary form must reproduce the above copyright 14187277Sdas * notice, this list of conditions and the following disclaimer in the 15187277Sdas * documentation and/or other materials provided with the distribution. 16187277Sdas * 4. Neither the name of the University nor the names of its contributors 17187277Sdas * may be used to endorse or promote products derived from this software 18187277Sdas * without specific prior written permission. 19187277Sdas * 20187277Sdas * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21187277Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22187277Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23187277Sdas * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24187277Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25187277Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26187277Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27187277Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28187277Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29187277Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30187277Sdas * SUCH DAMAGE. 31187277Sdas * 32187277Sdas * $FreeBSD: head/lib/libc/stdio/printfcommon.h 187354 2009-01-17 05:38:14Z das $ 33187277Sdas */ 34187277Sdas 35187277Sdas/* 36187277Sdas * This file defines common routines used by both printf and wprintf. 37187277Sdas * You must define CHAR to either char or wchar_t prior to including this. 38187277Sdas */ 39187277Sdas 40187284Sdas 41187284Sdas#ifndef NO_FLOATING_POINT 42187284Sdas 43187284Sdas#define dtoa __dtoa 44187284Sdas#define freedtoa __freedtoa 45187284Sdas 46187284Sdas#include <float.h> 47187284Sdas#include <math.h> 48187284Sdas#include "floatio.h" 49187284Sdas#include "gdtoa.h" 50187284Sdas 51187284Sdas#define DEFPREC 6 52187284Sdas 53187284Sdasstatic int exponent(CHAR *, int, CHAR); 54187284Sdas 55187284Sdas#endif /* !NO_FLOATING_POINT */ 56187284Sdas 57187284Sdasstatic CHAR *__ujtoa(uintmax_t, CHAR *, int, int, const char *, int, char, 58187284Sdas const char *); 59187284Sdasstatic CHAR *__ultoa(u_long, CHAR *, int, int, const char *, int, char, 60187284Sdas const char *); 61187284Sdas 62187277Sdas#define NIOV 8 63187277Sdasstruct io_state { 64187277Sdas FILE *fp; 65187277Sdas struct __suio uio; /* output information: summary */ 66187277Sdas struct __siov iov[NIOV];/* ... and individual io vectors */ 67187277Sdas}; 68187277Sdas 69187277Sdasstatic inline void 70187277Sdasio_init(struct io_state *iop, FILE *fp) 71187277Sdas{ 72187277Sdas 73187354Sdas iop->uio.uio_iov = iop->iov; 74187277Sdas iop->uio.uio_resid = 0; 75187277Sdas iop->uio.uio_iovcnt = 0; 76187277Sdas iop->fp = fp; 77187277Sdas} 78187277Sdas 79187277Sdas/* 80187277Sdas * WARNING: The buffer passed to io_print() is not copied immediately; it must 81187277Sdas * remain valid until io_flush() is called. 82187277Sdas */ 83187277Sdasstatic inline int 84187277Sdasio_print(struct io_state *iop, const CHAR * __restrict ptr, int len) 85187277Sdas{ 86187277Sdas 87187354Sdas iop->iov[iop->uio.uio_iovcnt].iov_base = (char *)ptr; 88187354Sdas iop->iov[iop->uio.uio_iovcnt].iov_len = len; 89187277Sdas iop->uio.uio_resid += len; 90187354Sdas if (++iop->uio.uio_iovcnt >= NIOV) 91187277Sdas return (__sprint(iop->fp, &iop->uio)); 92187354Sdas else 93187354Sdas return (0); 94187277Sdas} 95187277Sdas 96187277Sdas/* 97187277Sdas * Choose PADSIZE to trade efficiency vs. size. If larger printf 98187277Sdas * fields occur frequently, increase PADSIZE and make the initialisers 99187277Sdas * below longer. 100187277Sdas */ 101187277Sdas#define PADSIZE 16 /* pad chunk size */ 102187277Sdasstatic const CHAR blanks[PADSIZE] = 103187277Sdas{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 104187277Sdasstatic const CHAR zeroes[PADSIZE] = 105187277Sdas{'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 106187277Sdas 107187277Sdas/* 108187277Sdas * Pad with blanks or zeroes. 'with' should point to either the blanks array 109187277Sdas * or the zeroes array. 110187277Sdas */ 111187277Sdasstatic inline int 112187277Sdasio_pad(struct io_state *iop, int howmany, const CHAR * __restrict with) 113187277Sdas{ 114187354Sdas int n; 115187277Sdas 116187354Sdas while (howmany > 0) { 117187354Sdas n = (howmany >= PADSIZE) ? PADSIZE : howmany; 118187354Sdas if (io_print(iop, with, n)) 119187277Sdas return (-1); 120187354Sdas howmany -= n; 121187277Sdas } 122187277Sdas return (0); 123187277Sdas} 124187277Sdas 125187277Sdas/* 126187277Sdas * Print exactly len characters of the string spanning p to ep, truncating 127187277Sdas * or padding with 'with' as necessary. 128187277Sdas */ 129187277Sdasstatic inline int 130187277Sdasio_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep, 131187277Sdas int len, const CHAR * __restrict with) 132187277Sdas{ 133187277Sdas int p_len; 134187277Sdas 135187277Sdas p_len = ep - p; 136187277Sdas if (p_len > len) 137187277Sdas p_len = len; 138187354Sdas if (p_len > 0) { 139187354Sdas if (io_print(iop, p, p_len)) 140187354Sdas return (-1); 141187354Sdas } else { 142187354Sdas p_len = 0; 143187354Sdas } 144187354Sdas return (io_pad(iop, len - p_len, with)); 145187277Sdas} 146187277Sdas 147187277Sdasstatic inline int 148187277Sdasio_flush(struct io_state *iop) 149187277Sdas{ 150187277Sdas 151187277Sdas return (__sprint(iop->fp, &iop->uio)); 152187277Sdas} 153187284Sdas 154187284Sdas/* 155187284Sdas * Convert an unsigned long to ASCII for printf purposes, returning 156187284Sdas * a pointer to the first character of the string representation. 157187284Sdas * Octal numbers can be forced to have a leading zero; hex numbers 158187284Sdas * use the given digits. 159187284Sdas */ 160187284Sdasstatic CHAR * 161187284Sdas__ultoa(u_long val, CHAR *endp, int base, int octzero, const char *xdigs, 162187284Sdas int needgrp, char thousep, const char *grp) 163187284Sdas{ 164187284Sdas CHAR *cp = endp; 165187284Sdas long sval; 166187284Sdas int ndig; 167187284Sdas 168187284Sdas /* 169187284Sdas * Handle the three cases separately, in the hope of getting 170187284Sdas * better/faster code. 171187284Sdas */ 172187284Sdas switch (base) { 173187284Sdas case 10: 174187284Sdas if (val < 10) { /* many numbers are 1 digit */ 175187284Sdas *--cp = to_char(val); 176187284Sdas return (cp); 177187284Sdas } 178187284Sdas ndig = 0; 179187284Sdas /* 180187284Sdas * On many machines, unsigned arithmetic is harder than 181187284Sdas * signed arithmetic, so we do at most one unsigned mod and 182187284Sdas * divide; this is sufficient to reduce the range of 183187284Sdas * the incoming value to where signed arithmetic works. 184187284Sdas */ 185187284Sdas if (val > LONG_MAX) { 186187284Sdas *--cp = to_char(val % 10); 187187284Sdas ndig++; 188187284Sdas sval = val / 10; 189187284Sdas } else 190187284Sdas sval = val; 191187284Sdas do { 192187284Sdas *--cp = to_char(sval % 10); 193187284Sdas ndig++; 194187284Sdas /* 195187284Sdas * If (*grp == CHAR_MAX) then no more grouping 196187284Sdas * should be performed. 197187284Sdas */ 198187284Sdas if (needgrp && ndig == *grp && *grp != CHAR_MAX 199187284Sdas && sval > 9) { 200187284Sdas *--cp = thousep; 201187284Sdas ndig = 0; 202187284Sdas /* 203187284Sdas * If (*(grp+1) == '\0') then we have to 204187284Sdas * use *grp character (last grouping rule) 205187284Sdas * for all next cases 206187284Sdas */ 207187284Sdas if (*(grp+1) != '\0') 208187284Sdas grp++; 209187284Sdas } 210187284Sdas sval /= 10; 211187284Sdas } while (sval != 0); 212187284Sdas break; 213187284Sdas 214187284Sdas case 8: 215187284Sdas do { 216187284Sdas *--cp = to_char(val & 7); 217187284Sdas val >>= 3; 218187284Sdas } while (val); 219187284Sdas if (octzero && *cp != '0') 220187284Sdas *--cp = '0'; 221187284Sdas break; 222187284Sdas 223187284Sdas case 16: 224187284Sdas do { 225187284Sdas *--cp = xdigs[val & 15]; 226187284Sdas val >>= 4; 227187284Sdas } while (val); 228187284Sdas break; 229187284Sdas 230187284Sdas default: /* oops */ 231187284Sdas abort(); 232187284Sdas } 233187284Sdas return (cp); 234187284Sdas} 235187284Sdas 236187284Sdas/* Identical to __ultoa, but for intmax_t. */ 237187284Sdasstatic CHAR * 238187284Sdas__ujtoa(uintmax_t val, CHAR *endp, int base, int octzero, const char *xdigs, 239187284Sdas int needgrp, char thousep, const char *grp) 240187284Sdas{ 241187284Sdas CHAR *cp = endp; 242187284Sdas intmax_t sval; 243187284Sdas int ndig; 244187284Sdas 245187284Sdas /* quick test for small values; __ultoa is typically much faster */ 246187284Sdas /* (perhaps instead we should run until small, then call __ultoa?) */ 247187284Sdas if (val <= ULONG_MAX) 248187284Sdas return (__ultoa((u_long)val, endp, base, octzero, xdigs, 249187284Sdas needgrp, thousep, grp)); 250187284Sdas switch (base) { 251187284Sdas case 10: 252187284Sdas if (val < 10) { 253187284Sdas *--cp = to_char(val % 10); 254187284Sdas return (cp); 255187284Sdas } 256187284Sdas ndig = 0; 257187284Sdas if (val > INTMAX_MAX) { 258187284Sdas *--cp = to_char(val % 10); 259187284Sdas ndig++; 260187284Sdas sval = val / 10; 261187284Sdas } else 262187284Sdas sval = val; 263187284Sdas do { 264187284Sdas *--cp = to_char(sval % 10); 265187284Sdas ndig++; 266187284Sdas /* 267187284Sdas * If (*grp == CHAR_MAX) then no more grouping 268187284Sdas * should be performed. 269187284Sdas */ 270187284Sdas if (needgrp && *grp != CHAR_MAX && ndig == *grp 271187284Sdas && sval > 9) { 272187284Sdas *--cp = thousep; 273187284Sdas ndig = 0; 274187284Sdas /* 275187284Sdas * If (*(grp+1) == '\0') then we have to 276187284Sdas * use *grp character (last grouping rule) 277187284Sdas * for all next cases 278187284Sdas */ 279187284Sdas if (*(grp+1) != '\0') 280187284Sdas grp++; 281187284Sdas } 282187284Sdas sval /= 10; 283187284Sdas } while (sval != 0); 284187284Sdas break; 285187284Sdas 286187284Sdas case 8: 287187284Sdas do { 288187284Sdas *--cp = to_char(val & 7); 289187284Sdas val >>= 3; 290187284Sdas } while (val); 291187284Sdas if (octzero && *cp != '0') 292187284Sdas *--cp = '0'; 293187284Sdas break; 294187284Sdas 295187284Sdas case 16: 296187284Sdas do { 297187284Sdas *--cp = xdigs[val & 15]; 298187284Sdas val >>= 4; 299187284Sdas } while (val); 300187284Sdas break; 301187284Sdas 302187284Sdas default: 303187284Sdas abort(); 304187284Sdas } 305187284Sdas return (cp); 306187284Sdas} 307187284Sdas 308187284Sdas#ifndef NO_FLOATING_POINT 309187284Sdas 310187284Sdasstatic int 311187284Sdasexponent(CHAR *p0, int exp, CHAR fmtch) 312187284Sdas{ 313187284Sdas CHAR *p, *t; 314187284Sdas CHAR expbuf[MAXEXPDIG]; 315187284Sdas 316187284Sdas p = p0; 317187284Sdas *p++ = fmtch; 318187284Sdas if (exp < 0) { 319187284Sdas exp = -exp; 320187284Sdas *p++ = '-'; 321187284Sdas } 322187284Sdas else 323187284Sdas *p++ = '+'; 324187284Sdas t = expbuf + MAXEXPDIG; 325187284Sdas if (exp > 9) { 326187284Sdas do { 327187284Sdas *--t = to_char(exp % 10); 328187284Sdas } while ((exp /= 10) > 9); 329187284Sdas *--t = to_char(exp); 330187284Sdas for (; t < expbuf + MAXEXPDIG; *p++ = *t++); 331187284Sdas } 332187284Sdas else { 333187284Sdas /* 334187284Sdas * Exponents for decimal floating point conversions 335187284Sdas * (%[eEgG]) must be at least two characters long, 336187284Sdas * whereas exponents for hexadecimal conversions can 337187284Sdas * be only one character long. 338187284Sdas */ 339187284Sdas if (fmtch == 'e' || fmtch == 'E') 340187284Sdas *p++ = '0'; 341187284Sdas *p++ = to_char(exp); 342187284Sdas } 343187284Sdas return (p - p0); 344187284Sdas} 345187284Sdas 346187284Sdas#endif /* !NO_FLOATING_POINT */ 347