Annotation of coherent/b/lib/libc/stdio/vfprintf.c, revision 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.