int _doprnt()

in Frameworks/Foundation/FormatPrintf.mm [1049:1373]


int _doprnt(register const PrintType* fmt, va_list ap, PrintOutput* stream)
/* [<][>][^][v][top][bottom][index][help] */
{
    register PrintType* s;
    register int j;
    int i, c, width, precision, zfill, flags, between_fill;
    int nrchars = 0;
    const PrintType* oldfmt;
    PrintType *s1, buf[1025];
    char *cs = NULL, *cs1 = NULL;

    while ((c = *fmt++)) {
        if (c != '%') {
#ifdef CPM
            if (c == '\n') {
                if (PrintPutC('\r', stream) == EOF)
                    return nrchars ? -nrchars : -1;
                nrchars++;
            }
#endif
            if (PrintPutC(c, stream) == EOF) {
                return nrchars ? -nrchars : -1;
            }
            nrchars++;
            continue;
        }
        flags = 0;
        do {
            switch (*fmt) {
                case '-':
                    flags |= FL_LJUST;
                    break;
                case '+':
                    flags |= FL_SIGN;
                    break;
                case ' ':
                    flags |= FL_SPACE;
                    break;
                case '#':
                    flags |= FL_ALT;
                    break;
                case '0':
                    flags |= FL_ZEROFILL;
                    break;
                default:
                    flags |= FL_NOMORE;
                    continue;
            }
            fmt++;
        } while (!(flags & FL_NOMORE));

        oldfmt = fmt;
        fmt = gnum(fmt, &width, &ap);
        if (fmt != oldfmt) {
            flags |= FL_WIDTHSPEC;
        }

        if (*fmt == '.') {
            fmt++;
            oldfmt = fmt;
            fmt = gnum(fmt, &precision, &ap);
            if (precision >= 0) {
                flags |= FL_PRECSPEC;
            }
        }

        if ((flags & FL_WIDTHSPEC) && width < 0) {
            width = -width;
            flags |= FL_LJUST;
        }
        if (!(flags & FL_WIDTHSPEC)) {
            width = 0;
        }

        if (flags & FL_SIGN) {
            flags &= ~FL_SPACE;
        }

        if (flags & FL_LJUST) {
            flags &= ~FL_ZEROFILL;
        }

        s = s1 = buf;

        switch (*fmt) {
            case 'h':
                fmt++;

                if (*fmt == 'h') {
                    flags |= FL_CHAR;
                    fmt++;
                } else {
                    flags |= FL_SHORT;
                }

                break;
            case 'l':
                flags |= FL_LONG;
                fmt++;
                break;
            case 'L':
                flags |= FL_LONGDOUBLE;
                fmt++;
                break;

#if SIZE_MAX != UINT_MAX
#error Unexpected size_t size
#elif PTRDIFF_MAX != INT_MAX
#error Unexpected ptrdiff_t size
#endif
            case 'z': // size_t specifier
            case 't': // ptrdiff_t specifier
                fmt++;
                break;

#if INTMAX_MAX != LLONG_MAX
#error Unexpected intmax_t size
#endif
            case 'q': // long long specifier
            case 'j': // intmax_t specifier
                flags |= FL_LONG | FL_LONGLONG;
                fmt++;
                break;
        }

        if (*fmt == 'l') {
            flags |= FL_LONGLONG;
            fmt++;
        }

        switch (c = *fmt++) {
            default:
#ifdef CPM
                if (c == '\n') {
                    if (PrintPutC('\r', stream) == EOF)
                        return nrchars ? -nrchars : -1;
                    nrchars++;
                }
#endif
                if (PrintPutC(c, stream) == EOF) {
                    return nrchars ? -nrchars : -1;
                }
                nrchars++;
                continue;
            case 'n':
                if (flags & FL_SHORT) {
                    *EbrPtr(ap, short*) = (short)nrchars;
                } else if (flags & FL_LONG) {
                    *EbrPtr(ap, long*) = (long)nrchars;
                } else {
                    *EbrPtr(ap, int*) = (int)nrchars;
                }
                continue;
            case 's':
            case 'S':
#ifdef UTF8CStrings
                cs1 = EbrPtr(ap, char*);
                if (cs1 == NULL) {
                    cs1 = PrintNullStringC; //"(null)";
                }
                cs = cs1;
                while (precision || !(flags & FL_PRECSPEC)) {
                    if (*cs == '\0') {
                        break;
                    }
                    cs++;
                    precision--;
                }
#else
                s1 = EbrPtr(ap, PrintType*);
                if (s1 == NULL)
                    s1 = PrintNullString; //"(null)";
                s = s1;
                while (precision || !(flags & FL_PRECSPEC)) {
                    if (*s == '\0')
                        break;
                    s++;
                    precision--;
                }
#endif
                break;
            case '@': {
                id ptr = EbrVal(ap, id);
                id str = [ptr description];

                s1 = (PrintType*)[str cStringUsingEncoding:PrintEncodingType];
                if (s1 == NULL) {
                    s1 = PrintNullString; //"(null)";
                }
                s = s1;
                while (precision || !(flags & FL_PRECSPEC)) {
                    if (*s == '\0') {
                        break;
                    }
                    s++;
                    precision--;
                }
            } break;
            case 'p':
                set_pointer(flags);
            /* fallthrough */
            case 'b':
            case 'o':
            case 'u':
            case 'x':
            case 'X':
                if (!(flags & FL_PRECSPEC)) {
                    precision = 1;
                } else if (c != 'p') {
                    flags &= ~FL_ZEROFILL;
                }
                s = o_print(&ap, flags, s, c, precision, 0);
                break;
            case 'd':
            case 'i':
                flags |= FL_SIGNEDCONV;
                if (!(flags & FL_PRECSPEC)) {
                    precision = 1;
                } else {
                    flags &= ~FL_ZEROFILL;
                }
                s = o_print(&ap, flags, s, c, precision, 1);
                break;
            case 'c':
            case 'C':
                *s++ = EbrVal(ap, int);
                break;
#ifndef NOFLOAT
            case 'G':
            case 'g':
                if ((flags & FL_PRECSPEC) && (precision == 0)) {
                    precision = 1;
                }
            case 'f':
            case 'E':
            case 'e':
                if (!(flags & FL_PRECSPEC)) {
                    precision = 6;
                }

                if (precision >= sizeof(buf)) {
                    precision = sizeof(buf) - 1;
                }

                flags |= FL_SIGNEDCONV;
                s = _f_print(&ap, flags, s, c, precision);
                break;
#endif /* NOFLOAT */
            case 'r':
                assert(0);
                /*
                ap = va_arg(ap, StackReader*);
                fmt = va_arg(ap, char *);
                */
                continue;
        }
        zfill = ' ';
        if (flags & FL_ZEROFILL) {
            zfill = '0';
        }
        j = s - s1;
        if (cs != NULL) {
            j = cs - cs1;
        }

        /* between_fill is true under the following conditions:
        * 1- the fill character is '0'
        * and
        * 2a- the number is of the form 0x... or 0X...
        * or
        * 2b- the number contains a sign or space
        */
        between_fill = 0;
        if ((flags & FL_ZEROFILL) &&
            (((c == 'x' || c == 'X') && (flags & FL_ALT)) || (c == 'p') ||
             ((flags & FL_SIGNEDCONV) && ((cs1 ? *cs1 : *s1) == '+' || (cs1 ? *cs1 : *s1) == '-' || (cs1 ? *cs1 : *s1) == ' ')))) {
            between_fill++;
        }

        if ((i = width - j) > 0) {
            if (!(flags & FL_LJUST)) { /* right justify */
                nrchars += i;
                if (between_fill) {
                    if (flags & FL_SIGNEDCONV) {
                        j--;
                        nrchars++;
                        if (PrintPutC(cs1 ? *cs1++ : *s1++, stream) == EOF) {
                            return nrchars ? -nrchars : -1;
                        }
                    } else {
                        j -= 2;
                        nrchars += 2;
                        if ((PrintPutC(cs1 ? *cs1++ : *s1++, stream) == EOF) || (PrintPutC(cs1 ? *cs1++ : *s1++, stream) == EOF)) {
                            return nrchars ? -nrchars : -1;
                        }
                    }
                }
                do {
                    if (PrintPutC(zfill, stream) == EOF) {
                        return nrchars ? -nrchars : -1;
                    }
                } while (--i);
            }
        }

        nrchars += j;
        while (--j >= 0) {
            if (PrintPutC(cs1 ? *cs1++ : *s1++, stream) == EOF) {
                return nrchars ? -nrchars : -1;
            }
        }

        cs = cs1 = NULL;

        if (i > 0) {
            nrchars += i;
        }
        while (--i >= 0) {
            if (PrintPutC(zfill, stream) == EOF) {
                return nrchars ? -nrchars : -1;
            }
        }
    }
    return nrchars;
}