Prex Home / Browse Source - Prex Version: 0.9.0

root/usr/lib/libc/stdio/vfprintf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __sprint
  2. __sbprintf
  3. __ultoa
  4. vfprintf

   1 /*-
   2  * Copyright (c) 1990, 1993
   3  *      The Regents of the University of California.  All rights reserved.
   4  *
   5  * This code is derived from software contributed to Berkeley by
   6  * Chris Torek.
   7  *
   8  * Redistribution and use in source and binary forms, with or without
   9  * modification, are permitted provided that the following conditions
  10  * are met:
  11  * 1. Redistributions of source code must retain the above copyright
  12  *    notice, this list of conditions and the following disclaimer.
  13  * 2. Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in the
  15  *    documentation and/or other materials provided with the distribution.
  16  * 3. Neither the name of the University nor the names of its contributors
  17  *    may be used to endorse or promote products derived from this software
  18  *    without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30  * SUCH DAMAGE.
  31  */
  32 
  33 /*
  34  * Actual printf innards.
  35  *
  36  * This code is large and complicated...
  37  */
  38 
  39 #include <sys/types.h>
  40 
  41 #include <limits.h>
  42 #include <stdio.h>
  43 #include <stdlib.h>
  44 #include <string.h>
  45 #include <stdarg.h>
  46 
  47 #include "local.h"
  48 #include "fvwrite.h"
  49 
  50 /*
  51  * Flush out all the vectors defined by the given uio,
  52  * then reset it so that it can be reused.
  53  */
  54 static int
  55 __sprint(FILE *fp, struct __suio *uio)
  56 {
  57         int error;
  58 
  59         if (uio->uio_resid == 0) {
  60                 uio->uio_iovcnt = 0;
  61                 return (0);
  62         }
  63         error = __sfvwrite(fp, uio);
  64         uio->uio_resid = 0;
  65         uio->uio_iovcnt = 0;
  66         return (error);
  67 }
  68 
  69 /*
  70  * Helper function for `fprintf to unbuffered unix file': creates a
  71  * temporary buffer.  We only work on write-only files; this avoids
  72  * worries about ungetc buffers and so forth.
  73  */
  74 static int
  75 __sbprintf(FILE *fp, const char *fmt, va_list ap)
  76 {
  77         int ret;
  78         FILE fake;
  79         unsigned char buf[BUFSIZ];
  80 
  81         /* copy the important variables */
  82         fake._flags = fp->_flags & ~__SNBF;
  83         fake._file = fp->_file;
  84 
  85         /* set up the buffer */
  86         fake._bf._base = fake._p = buf;
  87         fake._bf._size = fake._w = sizeof(buf);
  88 
  89         /* do the work, then copy any error status */
  90         ret = vfprintf(&fake, fmt, ap);
  91         if (ret >= 0 && fflush(&fake))
  92                 ret = EOF;
  93         if (fake._flags & __SERR)
  94                 fp->_flags |= __SERR;
  95         return (ret);
  96 }
  97 
  98 /*
  99  * Macros for converting digits to letters and vice versa
 100  */
 101 #define to_digit(c)     ((c) - '0')
 102 #define is_digit(c)     ((unsigned)to_digit(c) <= 9)
 103 #define to_char(n)      ((n) + '0')
 104 
 105 /*
 106  * Convert an unsigned long to ASCII for printf purposes, returning
 107  * a pointer to the first character of the string representation.
 108  * Octal numbers can be forced to have a leading zero; hex numbers
 109  * use the given digits.
 110  */
 111 static char *
 112 __ultoa(u_long val, char *endp, int base, int octzero, char *xdigs)
 113 {
 114         char *cp = endp;
 115         long sval;
 116 
 117         /*
 118          * Handle the three cases separately, in the hope of getting
 119          * better/faster code.
 120          */
 121         switch (base) {
 122         case 10:
 123                 if (val < 10) { /* many numbers are 1 digit */
 124                         *--cp = to_char(val);
 125                         return (cp);
 126                 }
 127                 /*
 128                  * On many machines, unsigned arithmetic is harder than
 129                  * signed arithmetic, so we do at most one unsigned mod and
 130                  * divide; this is sufficient to reduce the range of
 131                  * the incoming value to where signed arithmetic works.
 132                  */
 133                 if (val > LONG_MAX) {
 134                         *--cp = to_char(val % 10);
 135                         sval = val / 10;
 136                 } else
 137                         sval = val;
 138                 do {
 139                         *--cp = to_char(sval % 10);
 140                         sval /= 10;
 141                 } while (sval != 0);
 142                 break;
 143 
 144         case 8:
 145                 do {
 146                         *--cp = to_char(val & 7);
 147                         val >>= 3;
 148                 } while (val);
 149                 if (octzero && *cp != '0')
 150                         *--cp = '0';
 151                 break;
 152 
 153         case 16:
 154                 do {
 155                         *--cp = xdigs[val & 15];
 156                         val >>= 4;
 157                 } while (val);
 158                 break;
 159 
 160         default:                        /* oops */
 161                 exit(1);
 162         }
 163         return (cp);
 164 }
 165 
 166 
 167 #define BUF             32
 168 
 169 
 170 /*
 171  * Flags used during conversion.
 172  */
 173 #define ALT             0x001           /* alternate form */
 174 #define HEXPREFIX       0x002           /* add 0x or 0X prefix */
 175 #define LADJUST         0x004           /* left adjustment */
 176 #define LONGDBL         0x008           /* long double; unimplemented */
 177 #define LONGINT         0x010           /* long integer */
 178 #define SHORTINT        0x040           /* short integer */
 179 #define ZEROPAD         0x080           /* zero (as opposed to blank) pad */
 180 int
 181 vfprintf(fp, fmt0, ap)
 182         FILE *fp;
 183         const char *fmt0;
 184         va_list ap;
 185 {
 186         char *fmt;              /* format string */
 187         int ch;                 /* character from fmt */
 188         int n;                  /* handy integer (short term usage) */
 189         char *cp;               /* handy char pointer (short term usage) */
 190         struct __siov *iovp;    /* for PRINT macro */
 191         int flags;              /* flags as above */
 192         int ret;                /* return value accumulator */
 193         int width;              /* width from format (%8d), or 0 */
 194         int prec;               /* precision from format (%.3d), or -1 */
 195         char sign;              /* sign prefix (' ', '+', '-', or \0) */
 196         u_long  ulval;          /* integer arguments %[diouxX] */
 197         int base;               /* base for [diouxX] conversion */
 198         int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
 199         int fieldsz;            /* field size expanded by sign, etc */
 200         int realsz;             /* field size expanded by dprec */
 201         int size;               /* size of converted field or string */
 202         char *xdigs = NULL;     /* digits for [xX] conversion */
 203 #define NIOV 8
 204         struct __suio uio;      /* output information: summary */
 205         struct __siov iov[NIOV];/* ... and individual io vectors */
 206         char buf[BUF];          /* space for %c, %[diouxX], %[eEfgG] */
 207         char ox[2];             /* space for 0x hex-prefix */
 208 
 209         /*
 210          * Choose PADSIZE to trade efficiency vs. size.  If larger printf
 211          * fields occur frequently, increase PADSIZE and make the initialisers
 212          * below longer.
 213          */
 214 #define PADSIZE 16              /* pad chunk size */
 215         static char blanks[PADSIZE] =
 216          {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
 217         static char zeroes[PADSIZE] =
 218          {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
 219 
 220         /*
 221          * BEWARE, these `goto error' on error, and PAD uses `n'.
 222          */
 223 #define PRINT(ptr, len) { \
 224         iovp->iov_base = (ptr); \
 225         iovp->iov_len = (len); \
 226         uio.uio_resid += (len); \
 227         iovp++; \
 228         if (++uio.uio_iovcnt >= NIOV) { \
 229                 if (__sprint(fp, &uio)) \
 230                         goto error; \
 231                 iovp = iov; \
 232         } \
 233 }
 234 #define PAD(howmany, with) { \
 235         if ((n = (howmany)) > 0) { \
 236                 while (n > PADSIZE) { \
 237                         PRINT(with, PADSIZE); \
 238                         n -= PADSIZE; \
 239                 } \
 240                 PRINT(with, n); \
 241         } \
 242 }
 243 #define FLUSH() { \
 244         if (uio.uio_resid && __sprint(fp, &uio)) \
 245                 goto error; \
 246         uio.uio_iovcnt = 0; \
 247         iovp = iov; \
 248 }
 249 
 250         /*
 251          * To extend shorts properly, we need both signed and unsigned
 252          * argument extraction methods.
 253          */
 254 #define SARG() \
 255         (flags&LONGINT ? va_arg(ap, long) : \
 256             flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
 257             (long)va_arg(ap, int))
 258 #define UARG() \
 259         (flags&LONGINT ? va_arg(ap, u_long) : \
 260             flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
 261             (u_long)va_arg(ap, u_int))
 262 
 263         /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
 264         if (cantwrite(fp))
 265                 return (EOF);
 266 
 267         /* optimise fprintf(stderr) (and other unbuffered Unix files) */
 268         if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
 269             fp->_file >= 0)
 270                 return (__sbprintf(fp, fmt0, ap));
 271 
 272         fmt = (char *)fmt0;
 273         uio.uio_iov = iovp = iov;
 274         uio.uio_resid = 0;
 275         uio.uio_iovcnt = 0;
 276         ret = 0;
 277 
 278         /*
 279          * Scan the format for conversions (`%' character).
 280          */
 281         for (;;) {
 282                 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
 283                         /* void */;
 284                 if ((n = fmt - cp) != 0) {
 285                         PRINT(cp, n);
 286                         ret += n;
 287                 }
 288                 if (ch == '\0')
 289                         goto done;
 290                 fmt++;          /* skip over '%' */
 291 
 292                 flags = 0;
 293                 dprec = 0;
 294                 width = 0;
 295                 prec = -1;
 296                 sign = '\0';
 297 
 298 rflag:          ch = *fmt++;
 299 reswitch:       switch (ch) {
 300                 case ' ':
 301                         /*
 302                          * ``If the space and + flags both appear, the space
 303                          * flag will be ignored.''
 304                          *      -- ANSI X3J11
 305                          */
 306                         if (!sign)
 307                                 sign = ' ';
 308                         goto rflag;
 309                 case '#':
 310                         flags |= ALT;
 311                         goto rflag;
 312                 case '*':
 313                         /*
 314                          * ``A negative field width argument is taken as a
 315                          * - flag followed by a positive field width.''
 316                          *      -- ANSI X3J11
 317                          * They don't exclude field widths read from args.
 318                          */
 319                         if ((width = va_arg(ap, int)) >= 0)
 320                                 goto rflag;
 321                         width = -width;
 322                         /* FALLTHROUGH */
 323                 case '-':
 324                         flags |= LADJUST;
 325                         goto rflag;
 326                 case '+':
 327                         sign = '+';
 328                         goto rflag;
 329                 case '.':
 330                         if ((ch = *fmt++) == '*') {
 331                                 n = va_arg(ap, int);
 332                                 prec = n < 0 ? -1 : n;
 333                                 goto rflag;
 334                         }
 335                         n = 0;
 336                         while (is_digit(ch)) {
 337                                 n = 10 * n + to_digit(ch);
 338                                 ch = *fmt++;
 339                         }
 340                         prec = n < 0 ? -1 : n;
 341                         goto reswitch;
 342                 case '0':
 343                         /*
 344                          * ``Note that 0 is taken as a flag, not as the
 345                          * beginning of a field width.''
 346                          *      -- ANSI X3J11
 347                          */
 348                         flags |= ZEROPAD;
 349                         goto rflag;
 350                 case '1': case '2': case '3': case '4':
 351                 case '5': case '6': case '7': case '8': case '9':
 352                         n = 0;
 353                         do {
 354                                 n = 10 * n + to_digit(ch);
 355                                 ch = *fmt++;
 356                         } while (is_digit(ch));
 357                         width = n;
 358                         goto reswitch;
 359                 case 'h':
 360                         flags |= SHORTINT;
 361                         goto rflag;
 362                 case 'l':
 363                         flags |= LONGINT;
 364                         goto rflag;
 365                 case 'c':
 366                         *(cp = buf) = va_arg(ap, int);
 367                         size = 1;
 368                         sign = '\0';
 369                         break;
 370                 case 'D':
 371                         flags |= LONGINT;
 372                         /*FALLTHROUGH*/
 373                 case 'd':
 374                 case 'i':
 375                         ulval = SARG();
 376                         if ((long)ulval < 0) {
 377                                 ulval = -ulval;
 378                                 sign = '-';
 379                         }
 380                         base = 10;
 381                         goto number;
 382                 case 'n':
 383                         if (flags & LONGINT)
 384                                 *va_arg(ap, long *) = ret;
 385                         else if (flags & SHORTINT)
 386                                 *va_arg(ap, short *) = ret;
 387                         else
 388                                 *va_arg(ap, int *) = ret;
 389                         continue;       /* no output */
 390                 case 'O':
 391                         flags |= LONGINT;
 392                         /*FALLTHROUGH*/
 393                 case 'o':
 394                         ulval = UARG();
 395                         base = 8;
 396                         goto nosign;
 397                 case 'p':
 398                         /*
 399                          * ``The argument shall be a pointer to void.  The
 400                          * value of the pointer is converted to a sequence
 401                          * of printable characters, in an implementation-
 402                          * defined manner.''
 403                          *      -- ANSI X3J11
 404                          */
 405                         ulval = (u_long)va_arg(ap, void *);
 406                         base = 16;
 407                         xdigs = "0123456789abcdef";
 408                         flags |= HEXPREFIX;
 409                         ch = 'x';
 410                         goto nosign;
 411                 case 's':
 412                         if ((cp = va_arg(ap, char *)) == NULL)
 413                                 cp = "(null)";
 414                         if (prec >= 0) {
 415                                 /*
 416                                  * can't use strlen; can only look for the
 417                                  * NUL in the first `prec' characters, and
 418                                  * strlen() will go further.
 419                                  */
 420                                 char *p = memchr(cp, 0, prec);
 421 
 422                                 if (p != NULL) {
 423                                         size = p - cp;
 424                                         if (size > prec)
 425                                                 size = prec;
 426                                 } else
 427                                         size = prec;
 428                         } else
 429                                 size = strlen(cp);
 430                         sign = '\0';
 431                         break;
 432                 case 'U':
 433                         flags |= LONGINT;
 434                         /*FALLTHROUGH*/
 435                 case 'u':
 436                         ulval = UARG();
 437                         base = 10;
 438                         goto nosign;
 439                 case 'X':
 440                         xdigs = "0123456789ABCDEF";
 441                         goto hex;
 442                 case 'x':
 443                         xdigs = "0123456789abcdef";
 444 hex:
 445                         ulval = UARG();
 446                         base = 16;
 447                         /* leading 0x/X only if non-zero */
 448                         if (flags & ALT && ulval != 0)
 449                                 flags |= HEXPREFIX;
 450 
 451                         /* unsigned conversions */
 452 nosign:                 sign = '\0';
 453                         /*
 454                          * ``... diouXx conversions ... if a precision is
 455                          * specified, the 0 flag will be ignored.''
 456                          *      -- ANSI X3J11
 457                          */
 458 number:                 if ((dprec = prec) >= 0)
 459                                 flags &= ~ZEROPAD;
 460 
 461                         /*
 462                          * ``The result of converting a zero value with an
 463                          * explicit precision of zero is no characters.''
 464                          *      -- ANSI X3J11
 465                          */
 466                         cp = buf + BUF;
 467                         if (ulval != 0 || prec != 0)
 468                                 cp = __ultoa(ulval, cp, base,
 469                                              flags & ALT, xdigs);
 470                         size = buf + BUF - cp;
 471                         break;
 472                 default:        /* "%?" prints ?, unless ? is NUL */
 473                         if (ch == '\0')
 474                                 goto done;
 475                         /* pretend it was %c with argument ch */
 476                         cp = buf;
 477                         *cp = ch;
 478                         size = 1;
 479                         sign = '\0';
 480                         break;
 481                 }
 482 
 483                 /*
 484                  * All reasonable formats wind up here.  At this point, `cp'
 485                  * points to a string which (if not flags&LADJUST) should be
 486                  * padded out to `width' places.  If flags&ZEROPAD, it should
 487                  * first be prefixed by any sign or other prefix; otherwise,
 488                  * it should be blank padded before the prefix is emitted.
 489                  * After any left-hand padding and prefixing, emit zeroes
 490                  * required by a decimal [diouxX] precision, then print the
 491                  * string proper, then emit zeroes required by any leftover
 492                  * floating precision; finally, if LADJUST, pad with blanks.
 493                  *
 494                  * Compute actual size, so we know how much to pad.
 495                  * fieldsz excludes decimal prec; realsz includes it.
 496                  */
 497                 fieldsz = size;
 498                 if (sign)
 499                         fieldsz++;
 500                 else if (flags & HEXPREFIX)
 501                         fieldsz += 2;
 502                 realsz = dprec > fieldsz ? dprec : fieldsz;
 503 
 504                 /* right-adjusting blank padding */
 505                 if ((flags & (LADJUST|ZEROPAD)) == 0)
 506                         PAD(width - realsz, blanks);
 507 
 508                 /* prefix */
 509                 if (sign) {
 510                         PRINT(&sign, 1);
 511                 } else if (flags & HEXPREFIX) {
 512                         ox[0] = '0';
 513                         ox[1] = ch;
 514                         PRINT(ox, 2);
 515                 }
 516 
 517                 /* right-adjusting zero padding */
 518                 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
 519                         PAD(width - realsz, zeroes);
 520 
 521                 /* leading zeroes from decimal precision */
 522                 PAD(dprec - fieldsz, zeroes);
 523 
 524                 /* the string or number proper */
 525                 PRINT(cp, size);
 526 
 527                 /* left-adjusting padding (always blank) */
 528                 if (flags & LADJUST)
 529                         PAD(width - realsz, blanks);
 530 
 531                 /* finally, adjust ret */
 532                 ret += width > realsz ? width : realsz;
 533 
 534                 FLUSH();        /* copy out the I/O vectors */
 535         }
 536 done:
 537         FLUSH();
 538 error:
 539         return (__sferror(fp) ? EOF : ret);
 540         /* NOTREACHED */
 541 }

/* [<][>][^][v][top][bottom][index][help] */