Annotation of coherent/b/lib/libc/stdio/vfprintf.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * libc/stdio/vfprintf.c
                      3:  * ANSI-compliant C standard i/o library.
                      4:  * vfprintf()
                      5:  * ANSI 4.9.6.7, 4.9.6.1.
                      6:  * Do the work for fprintf(), printf(), sprintf(), vprintf(), vsprintf().
                      7:  * Thanks to the ANSI committee for all the complication.
                      8:  *
                      9:  * Implementation-defined behavior:
                     10:  *     "%p" format is same as "%#.<PPREC>X" or "%#.<PPREC>lX"
                     11:  */
                     12: 
                     13: #include <stdio.h>
                     14: #include <stdlib.h>
                     15: #include <stdarg.h>
                     16: #include <limits.h>
                     17: 
                     18: /* Compile-time options. */
                     19: #if    _I386
                     20: #define        PPREC           8       /* precision for %p format */
                     21: #else
                     22: #define        PPREC           4       /* precision for %p format */
                     23: #endif
                     24: #define        LONGDOUBLE      0       /* iff sizeof(double) != sizeof(long double) */
                     25: #define        VA_PURE 0               /* iff va_list treated purely for doubles */
                     26: 
                     27: static char    *convert();
                     28: 
                     29: /* Manifest constants. */
                     30: /* ANSI says any conversion item can be up to 509 characters. The only */
                     31: /* case where cbuf needs to be big is for floating point (%f).         */
                     32: #define        CBUFMAX         512             /* conversion buffer size       */
                     33: #define        NDIGITS         12              /* ASCII digits in octal long   */
                     34:                                        /* i.e. "37777777777\0"         */
                     35: #define        PRINTNULL       "{NULL}"        /* for %s with NULL arg         */
                     36: 
                     37: int
                     38: vfprintf(fp, format, args) FILE *fp; register char *format; va_list args;
                     39: {
                     40:        char            cbuf[CBUFMAX];
                     41:        register char * cbp;
                     42:        char *          cbs;
                     43:        char *          s;
                     44:        register int    count, c;
                     45:        long            l;
                     46:        int             fwidth, prec, base, len;
                     47:        int             leftjustify, plusflag, spaceflag, altflag, longflag;
                     48:        int             padchar, padwidth, issigned, prefix, ispfx, nzeros;
                     49:        va_list         rargs;
                     50: #if    VA_PURE
                     51:        double          d;
                     52: #if    LONGDOUBLE
                     53:        long double     ld;
                     54: #endif
                     55: #endif
                     56: 
                     57:        count = 0;                      /* characters printed */
                     58:        for (;;) {
                     59: 
                     60:                /* Nonconversion characters. */
                     61:                while ((c = *format++) != '%') {
                     62:                        if (c == '\0')
                     63:                                return count;
                     64:                        ++count;
                     65:                        putc(c, fp);
                     66:                }
                     67: 
                     68:                /* Optional flags "-+ #0". */
                     69:                leftjustify = plusflag = spaceflag = altflag = 0;
                     70:                padchar = ' ';
                     71:                for (;;) {
                     72:                        switch(c = *format++) {
                     73:                        case '-':       ++leftjustify;  continue;
                     74:                        case '+':       ++plusflag;     continue;
                     75:                        case ' ':       ++spaceflag;    continue;
                     76:                        case '#':       ++altflag;      continue;
                     77:                        case '0':       padchar = '0';  continue;
                     78:                        default:        break;
                     79:                        }
                     80:                        break;
                     81:                }
                     82: 
                     83:                /* Optional field width ('*' or decimal integer). */
                     84:                if (c == '*') {
                     85:                        if ((fwidth = va_arg(args, int)) < 0) {
                     86:                                leftjustify = 1;
                     87:                                fwidth = -fwidth;
                     88:                        }
                     89:                        c = *format++;
                     90:                } else
                     91:                        for (fwidth = 0; c>='0' && c<='9'; c = *format++)
                     92:                                fwidth = fwidth*10 + c-'0';
                     93: 
                     94:                /* Optional precision ('.' followed by '*' or decimal integer). */
                     95:                if (c == '.') {
                     96:                        c = *format++;
                     97:                        if (c == '*') {
                     98:                                prec = va_arg(args, int);
                     99:                                if (prec < 0)
                    100:                                        prec = -1;
                    101:                                c = *format++;
                    102:                        } else
                    103:                                for (prec=0; c>='0' && c<='9'; c = *format++)
                    104:                                        prec = prec*10 + c-'0';
                    105:                } else
                    106:                        prec = -1;
                    107: 
                    108:                /* Optional 'h', 'l' or 'L' flag. */
                    109:                if (c == 'l' || c == 'h' || c == 'L') {
                    110:                        longflag = c;
                    111:                        c = *format++;
                    112:                } else
                    113:                        longflag = 0;
                    114: 
                    115:                /* Convert an item. */
                    116:                cbp = cbs = cbuf;
                    117:                issigned = nzeros = prefix = ispfx = 0;
                    118:                switch (c) {
                    119: 
                    120:                case 'd':
                    121:                case 'i':
                    122:                        base = 10;
                    123:                        if (longflag=='l')
                    124:                                l = va_arg(args, long);
                    125:                        else
                    126:                                l = (long) va_arg(args, int);
                    127:                        if (longflag == 'h')
                    128:                                l = (short) l;
                    129:                        if (l < 0L) {
                    130:                                l = -l;
                    131:                                --issigned;             /* -1 for negative */
                    132:                        } else
                    133:                                ++issigned;             /* +1 for positive */
                    134:                        goto conv;
                    135: 
                    136:                case 'o':
                    137:                        base = 8;
                    138:                        goto unsconv;
                    139: 
                    140:                case 'u':
                    141:                        base = 10;
                    142:                        goto unsconv;
                    143:        
                    144:                case 'x':
                    145:                case 'X':
                    146:                        base = 16;
                    147: unsconv:
                    148:                        if (longflag=='l')
                    149:                                l = va_arg(args, long);
                    150:                        else
                    151: #if    _I386
                    152:                                /* The i8086 compiler sign-extends this. */
                    153:                                l = (unsigned long) va_arg(args, int);
                    154: #else
                    155:                                /* Kludge. */
                    156:                                l = va_arg(args, int) & 0x0000FFFFL;
                    157: #endif
                    158:                        if (longflag == 'h')
                    159:                                l = (unsigned short) l;
                    160:                        if (altflag && ((l != 0L && base == 8) || base == 16))
                    161:                                prefix = c;             /* 'o', 'x' or 'X' */
                    162: conv:
                    163:                        if (prec == 0 && l == 0L)
                    164:                                break;                  /* ANSI says so */
                    165:                        if (prec != -1)
                    166:                                padchar = ' ';          /* ignore 0 flag */
                    167:                        cbp = convert(cbp, l, base, c);
                    168:                        if ((nzeros = prec - (cbp - cbs)) < 0)  /* number of leading '0's */
                    169:                                nzeros = 0;
                    170:                        break;
                    171: 
                    172:                /*
                    173:                 * Floating point output.
                    174:                 * A simple floating point operation may have considerable
                    175:                 * overhead in some environments (e.g. MSDOS, where a large
                    176:                 * 8087 emulator gets linked into executables which require
                    177:                 * software floating point).  But there is only one
                    178:                 * ideologically pure way to get the fp arg from the arg list,
                    179:                 * namely with va_arg(), and that requires a fp fetch.
                    180:                 * The code below is conditionalized to do it the pure way
                    181:                 * (generating a fp fetch) or with a pointer to double (no fp).
                    182:                 */
                    183:                case 'f':
                    184:                case 'e':
                    185:                case 'E':
                    186:                case 'g':
                    187:                case 'G':
                    188: #if    VA_PURE
                    189: #if    LONGDOUBLE
                    190:                        if (longflag == 'L') {
                    191:                                ld = va_arg(args, long double);
                    192:                                cbp = _ldtefg(cbp, &ld, c, prec, altflag, &issigned);
                    193:                                break;
                    194:                        }
                    195: #endif
                    196:                        d = va_arg(args, double);
                    197:                        cbp = _dtefg(cbp, &d, c, prec, altflag, &issigned);
                    198:                        break;
                    199: #else
                    200: #if    LONGDOUBLE
                    201:                        if (longflag == 'L') {
                    202:                                cbp = _ldtefg(cbp, (long double *)args, c,
                    203:                                                 prec, altflag, &issigned);
                    204:                                args = ((char *)args) + sizeof(long double);
                    205:                                break;
                    206:                        }
                    207: #endif
                    208:                        cbp = _dtefg(cbp, (double *)args, c, prec, altflag, &issigned);
                    209:                        args = ((char *)args) + sizeof(double);
                    210:                        break;
                    211: #endif
                    212:                case 'c':
                    213:                        *cbp++ = (unsigned char) va_arg(args, int);
                    214:                        break;
                    215:        
                    216:                case 's':
                    217:                        if ((s = va_arg(args, char *)) == NULL)
                    218:                                s = PRINTNULL;          /* not strictly ANSI */
                    219:                        cbp = cbs = s;
                    220:                        while (*cbp++ != '\0')
                    221:                                if (prec>=0 && cbp-s>prec)
                    222:                                        break;
                    223:                        cbp--;
                    224:                        break;
                    225: 
                    226:                /* Implementation-defined '%p' format: %#.<PPREC>X or %#.<PPREC>lX */
                    227:                case 'p':
                    228: #if    _LARGE
                    229:                        longflag = 'l';
                    230: #else
                    231:                        longflag = 0;
                    232: #endif
                    233:                        prec = PPREC;
                    234:                        ++altflag;
                    235:                        c = 'X';
                    236:                        base = 16;
                    237:                        goto unsconv;
                    238: 
                    239:                case 'n':
                    240:                        if (longflag == 'h')
                    241:                                *(va_arg(args, short *)) = (short)count;
                    242:                        else if (longflag == 'l')
                    243:                                *(va_arg(args, long *)) = (long)count;
                    244:                        else
                    245:                                *(va_arg(args, int *)) = count;
                    246:                        break;
                    247: 
                    248:                /*
                    249:                 * The '%r' recursive printf conversion is non-ANSI.
                    250:                 * The item is a va_list; its first member is the format.
                    251:                 */
                    252:                case 'r':
                    253:                        rargs = va_arg(args, va_list);
                    254:                        s = va_arg(rargs, char *);
                    255:                        count += vfprintf(fp, s, rargs);
                    256:                        break;
                    257:        
                    258:                default:
                    259:                        ++count;
                    260:                        putc(c, fp);
                    261:                        continue;
                    262:                }
                    263: 
                    264:                /* Output an item. */
                    265:                len = cbp - cbs;                /* length of converted item */
                    266:                if (issigned && (issigned == -1 || plusflag || spaceflag)) {
                    267:                        ++len;                  /* for '-', '+', ' ' */
                    268:                        ++ispfx;
                    269:                }
                    270:                if (prefix) {
                    271:                        ++len;                  /* for '0' */
                    272:                        ++ispfx;
                    273:                        if (prefix != 'o')
                    274:                                ++len;          /* for 'x', 'X' */
                    275:                }
                    276:                if ((padwidth = fwidth - nzeros - len) < 0)
                    277:                        padwidth = 0;           /* length of padding required */
                    278:                count += len + padwidth + nzeros;
                    279:                if (!leftjustify && padwidth > 0) {
                    280:                        if (ispfx && padchar == '0')
                    281:                                nzeros += padwidth;     /* prefix before 0-padding */
                    282:                        else
                    283:                                while (padwidth-- > 0)  /* pad on the left */
                    284:                                        putc(padchar, fp);
                    285:                }
                    286:                if (issigned) {
                    287:                        if (issigned == -1)
                    288:                                putc('-', fp);
                    289:                        else if (plusflag)
                    290:                                putc('+', fp);
                    291:                        else if (spaceflag)
                    292:                                putc(' ', fp);
                    293:                }
                    294:                if (prefix) {
                    295:                        putc('0', fp);
                    296:                        if (prefix != 'o')
                    297:                                putc(prefix, fp);
                    298:                }
                    299:                while (nzeros-- > 0)
                    300:                        putc('0', fp);          /* leading '0's */
                    301:                len = cbp - cbs;
                    302:                while (len-- > 0)
                    303:                        putc(*cbs++, fp);       /* converted item */
                    304:                if (leftjustify)
                    305:                        while (padwidth-- > 0)
                    306:                                putc(' ', fp);  /* pad on the right */
                    307:        }
                    308: }
                    309: 
                    310: static const char digits[] = {
                    311:        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                    312:        'A', 'B', 'C', 'D', 'E', 'F'
                    313: };
                    314: static const char ldigits[] = {
                    315:        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                    316:        'a', 'b', 'c', 'd', 'e', 'f'
                    317: };
                    318: 
                    319: /*
                    320:  * Convert unsigned long 'n' to ASCII in base 'b' for conversion 'c'.
                    321:  * Store the result through 'cp' and return a pointer past the end.
                    322:  */
                    323: static
                    324: char *
                    325: convert(cp, n, b, c) register char *cp; unsigned long n; unsigned int b; int c;
                    326: {
                    327:        register char * ep;
                    328:        char *          dp;
                    329:        unsigned int    u;
                    330:        char            pbuf[NDIGITS];
                    331: 
                    332:        dp = (c == 'x') ? &ldigits[0] : &digits[0];
                    333:        ep = &pbuf[NDIGITS-1];
                    334:        *ep = '\0';                     /* NUL-terminate */
                    335:        if (n <= UINT_MAX) {
                    336:                u = n;                  /* Use int arithmetic for efficiency */
                    337:                do {                    /* Store next digit */
                    338:                        *--ep = dp[u%b];
                    339:                } while ((u /= b) != 0);
                    340:        } else {
                    341:                do {                    /* Store next digit */
                    342:                        *--ep = dp[n%b];
                    343:                } while ((n /= b) != 0);
                    344:        }
                    345:        while (*ep)
                    346:                *cp++ = *ep++;          /* Copy result */
                    347:        return cp;
                    348: }
                    349: 
                    350: 
                    351: /* end of libc/stdio/vfprintf.c */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.