size_t tfp_format()

in libc/baselibc/src/tinyprintf.c [244:425]


size_t tfp_format(FILE *putp, const char *fmt, va_list va)
{
    size_t written = 0;
    struct param p;
    char bf[23];
    char ch;
    char lng;
    void *v;
#if MYNEWT_VAL(FLOAT_USER)
    double d;
    int n;
#endif
    int i;

    p.bf = bf;

    while ((ch = *(fmt++))) {
        if (ch != '%') {
            written += putf(putp, ch);
        } else {
            /* Init parameter struct */
            p.lz = 0;
            p.alt = 0;
            p.width = 0;
            p.sign = 0;
            p.left = 0;
            p.uc = 0;
            p.hh = 0;
            lng = 0;

            /* Flags */
            while ((ch = *(fmt++))) {
                switch (ch) {
                case '0':
                    if (!p.left) {
                        p.lz = 1;
                    }
                    continue;
                case '#':
                    p.alt = 1;
                    continue;
                case '-':
                    p.left = 1;
                    p.lz = 0;
                    continue;
                default:
                    break;
                }
                break;
            }

            /* Width */
            if (ch == '*') {
                i = intarg(0, 1, &va);
                if (i > UCHAR_MAX) {
                    p.width = UCHAR_MAX;
                } else if (i > 0) {
                    p.width = i;
                }
                ch = *(fmt++);
            } else if (ch >= '0' && ch <= '9') {
                ch = a2i(ch, &fmt, 10, &(p.width));
            }
            if (ch == 'l') {
                ch = *(fmt++);
                lng = 1;

                if (ch == 'l') {
                    ch = *(fmt++);
                    lng = 2;
                }
            } else if (ch == 'h') {
                ch = *(fmt++);
                p.hh = 1;

                if (ch == 'h') {
                    ch = *(fmt++);
                    p.hh = 2;
                }
            }

            if (ch == 'z') {
                ch = *(fmt++);
            }

            switch (ch) {
            case 0:
                goto abort;
            case 'u':
                p.base = 10;
                ui2a(intarg(lng, 0, &va), &p);
                written += putchw(putp, &p);
                break;
            case 'd':
            case 'i':
                p.base = 10;
                i2a(intarg(lng, 1, &va), &p);
                written += putchw(putp, &p);
                break;
            case 'x':
            case 'X':
                p.base = 16;
                p.uc = (ch == 'X');
                ui2a(intarg(lng, 0, &va), &p);
                written += putchw(putp, &p);
                break;
            case 'o':
                p.base = 8;
                ui2a(intarg(lng, 0, &va), &p);
                written += putchw(putp, &p);
                break;
            case 'p':
                v = va_arg(va, void *);
                p.base = 16;
                ui2a((uintptr_t)v, &p);
                p.width = 2 * sizeof(void*);
                p.lz = 1;
                written += putf(putp, '0');
                written += putf(putp, 'x');
                written += putchw(putp, &p);
                break;
            case 'c':
                written += putf(putp, (char)(va_arg(va, int)));
                break;
            case 's':
                p.bf = va_arg(va, char *);
                written += putchw(putp, &p);
                p.bf = bf;
                break;
#if MYNEWT_VAL(FLOAT_USER)
            case 'f':
                p.base = 10;
                d = va_arg(va, double);
                /* Convert to an int to get the integer part of the number. */
                n = d;
                /* Convert to ascii */
                i2a(n, &p);
                /* When the double was converted to an int it was truncated
                 * towards 0.  If the number is in the range (-1, 0), the
                 * negative sign was lost.  Preserve the sign in this case.
                 */
                if (d < 0.0) {
                    p.sign = 1;
                }
                /* Ignore left align for integer part */
                p.left = 0;
                /* Subtract width for decimal part and decimal point */
                if (p.width >= 4) {
                    p.width -= 4;
                } else {
                    p.width = 0;
                }
                /* Write integer part to console */
                written += putchw(putp, &p);
                /* Take the decimal part and multiply by 1000 */
                n = (d-n)*1000;
                /* Convert to ascii */
                i2a(n, &p);
                /* Set the leading zeros for the next integer output to 3 */
                p.lz = 3;
                /* Always use the same decimal width */
                p.width = 3;
                /* Ignore sign for decimal part*/
                p.sign = 0;
                /* Output a decimal point */
                putf(putp, '.');
                /* Output the decimal part. */
                written += putchw(putp, &p);
                break;
#endif
            case '%':
                written += putf(putp, ch);
                break;
            default:
                break;
            }
        }
    }
 abort:;
 
 return written;
}