static void __CFStringAppendFormatCore()

in Frameworks/CoreFoundation/String.subproj/CFString.c [6079:6671]


static void __CFStringAppendFormatCore(CFMutableStringRef outputString, CFStringRef (*copyDescFunc)(void *, const void *), CFStringRef (*contextDescFunc)(void *, const void *, const void *, bool, bool *), CFDictionaryRef formatOptions, CFDictionaryRef stringsDictConfig, CFStringRef formatString, CFIndex initialArgPosition, const void *origValues, CFIndex originalValuesSize, va_list args) {
    SInt32 numSpecs, sizeSpecs, sizeArgNum, formatIdx, curSpec, argNum;
    CFIndex formatLen;
#define FORMAT_BUFFER_LEN 400
    const uint8_t *cformat = NULL;
    const UniChar *uformat = NULL;
    UniChar *formatChars = NULL;
    UniChar localFormatBuffer[FORMAT_BUFFER_LEN];
    
#define VPRINTF_BUFFER_LEN 61
    CFFormatSpec localSpecsBuffer[VPRINTF_BUFFER_LEN];
    CFFormatSpec *specs;
    CFPrintValue localValuesBuffer[VPRINTF_BUFFER_LEN];
    CFPrintValue *values;
    const CFPrintValue *originalValues = (const CFPrintValue *)origValues;
    CFDictionaryRef localConfigs[VPRINTF_BUFFER_LEN];
    CFDictionaryRef *configs;
    CFMutableDictionaryRef formattingConfig = NULL;
    CFIndex numConfigs;
    CFAllocatorRef tmpAlloc = NULL;
    intmax_t dummyLocation;     // A place for %n to do its thing in; should be the widest possible int value

    numSpecs = 0;
    sizeSpecs = 0;
    sizeArgNum = 0;
    numConfigs = 0;
    specs = NULL;
    values = NULL;
    configs = NULL;


    formatLen = CFStringGetLength(formatString);
    if (!CF_IS_OBJC(__kCFStringTypeID, formatString) && !CF_IS_SWIFT(CFStringGetTypeID(), formatString)) {
        __CFAssertIsString(formatString);
        if (!__CFStrIsUnicode(formatString)) {
            cformat = (const uint8_t *)__CFStrContents(formatString);
            if (cformat) cformat += __CFStrSkipAnyLengthByte(formatString);
        } else {
            uformat = (const UniChar *)__CFStrContents(formatString);
        }
    }
    if (!cformat && !uformat) {
        formatChars = (formatLen > FORMAT_BUFFER_LEN) ? (UniChar *)CFAllocatorAllocate(tmpAlloc = __CFGetDefaultAllocator(), formatLen * sizeof(UniChar), 0) : localFormatBuffer; 
    if (formatChars != localFormatBuffer && __CFOASafe) __CFSetLastAllocationEventName(formatChars, "CFString (temp)");
        CFStringGetCharacters(formatString, CFRangeMake(0, formatLen), formatChars);
        uformat = formatChars;
    }

    /* Compute an upper bound for the number of format specifications */
    if (cformat) {
        for (formatIdx = 0; formatIdx < formatLen; formatIdx++) if ('%' == cformat[formatIdx]) sizeSpecs++;
    } else {
        for (formatIdx = 0; formatIdx < formatLen; formatIdx++) if ('%' == uformat[formatIdx]) sizeSpecs++;
    }
    tmpAlloc = __CFGetDefaultAllocator();
    specs = ((2 * sizeSpecs + 1) > VPRINTF_BUFFER_LEN) ? (CFFormatSpec *)CFAllocatorAllocate(tmpAlloc, (2 * sizeSpecs + 1) * sizeof(CFFormatSpec), 0) : localSpecsBuffer;
    if (specs != localSpecsBuffer && __CFOASafe) __CFSetLastAllocationEventName(specs, "CFString (temp)");

    configs = ((sizeSpecs < VPRINTF_BUFFER_LEN) ? localConfigs : (CFDictionaryRef *)CFAllocatorAllocate(tmpAlloc, sizeof(CFStringRef) * sizeSpecs, 0));

    /* Collect format specification information from the format string */
    for (curSpec = 0, formatIdx = 0; formatIdx < formatLen; curSpec++) {
    SInt32 newFmtIdx;
    specs[curSpec].loc = formatIdx;
    specs[curSpec].len = 0;
    specs[curSpec].size = 0;
    specs[curSpec].type = 0;
    specs[curSpec].flags = 0;
    specs[curSpec].widthArg = -1;
    specs[curSpec].precArg = -1;
    specs[curSpec].mainArgNum = -1;
    specs[curSpec].precArgNum = -1;
    specs[curSpec].widthArgNum = -1;
    specs[curSpec].configDictIndex = -1;
        if (cformat) {
            for (newFmtIdx = formatIdx; newFmtIdx < formatLen && '%' != cformat[newFmtIdx]; newFmtIdx++);
        } else {
            for (newFmtIdx = formatIdx; newFmtIdx < formatLen && '%' != uformat[newFmtIdx]; newFmtIdx++);
        }
    if (newFmtIdx != formatIdx) {   /* Literal chunk */
        specs[curSpec].type = CFFormatLiteralType;
        specs[curSpec].len = newFmtIdx - formatIdx;
    } else {
        CFStringRef configKey = NULL;
        newFmtIdx++;    /* Skip % */
        __CFParseFormatSpec(uformat, cformat, &newFmtIdx, formatLen, &(specs[curSpec]), &configKey);
            if (CFFormatLiteralType == specs[curSpec].type) {
        specs[curSpec].loc = formatIdx + 1;
        specs[curSpec].len = 1;
        } else {
        specs[curSpec].len = newFmtIdx - formatIdx;
        }
    }
    formatIdx = newFmtIdx;

// fprintf(stderr, "specs[%d] = {\n  size = %d,\n  type = %d,\n  loc = %d,\n  len = %d,\n  mainArgNum = %d,\n  precArgNum = %d,\n  widthArgNum = %d\n}\n", curSpec, specs[curSpec].size, specs[curSpec].type, specs[curSpec].loc, specs[curSpec].len, specs[curSpec].mainArgNum, specs[curSpec].precArgNum, specs[curSpec].widthArgNum);

    }
    numSpecs = curSpec;

    // Max of three args per spec, reasoning thus: 1 width, 1 prec, 1 value
    sizeArgNum = ((NULL == originalValues) ? (3 * sizeSpecs + 1) : originalValuesSize);

    values = (sizeArgNum > VPRINTF_BUFFER_LEN) ? (CFPrintValue *)CFAllocatorAllocate(tmpAlloc, sizeArgNum * sizeof(CFPrintValue), 0) : localValuesBuffer;
    if (values != localValuesBuffer && __CFOASafe) __CFSetLastAllocationEventName(values, "CFString (temp)");
    memset(values, 0, sizeArgNum * sizeof(CFPrintValue));

#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
    // va_copy is a C99 extension. No support on Windows
    va_list copiedArgs;
    if (numConfigs > 0) va_copy(copiedArgs, args); // we need to preserve the original state for passing down
#endif

    /* Compute values array */
    argNum = initialArgPosition;
    for (curSpec = 0; curSpec < numSpecs; curSpec++) {
    SInt32 newMaxArgNum;
    if (0 == specs[curSpec].type) continue;
    if (CFFormatLiteralType == specs[curSpec].type) continue;
    newMaxArgNum = sizeArgNum;
    if (newMaxArgNum < specs[curSpec].mainArgNum) {
        newMaxArgNum = specs[curSpec].mainArgNum;
    }
    if (newMaxArgNum < specs[curSpec].precArgNum) {
        newMaxArgNum = specs[curSpec].precArgNum;
    }
    if (newMaxArgNum < specs[curSpec].widthArgNum) {
        newMaxArgNum = specs[curSpec].widthArgNum;
    }
    if (sizeArgNum < newMaxArgNum) {
        if (specs != localSpecsBuffer) CFAllocatorDeallocate(tmpAlloc, specs);
        if (values != localValuesBuffer) CFAllocatorDeallocate(tmpAlloc, values);
        if (formatChars && (formatChars != localFormatBuffer)) CFAllocatorDeallocate(tmpAlloc, formatChars);
        return;  // more args than we expected!
    }
    /* It is actually incorrect to reorder some specs and not all; we just do some random garbage here */
    if (-2 == specs[curSpec].widthArgNum) {
        specs[curSpec].widthArgNum = argNum++;
    }
    if (-2 == specs[curSpec].precArgNum) {
        specs[curSpec].precArgNum = argNum++;
    }
    if (-1 == specs[curSpec].mainArgNum) {
        specs[curSpec].mainArgNum = argNum++;
    }

    values[specs[curSpec].mainArgNum].size = specs[curSpec].size;
    values[specs[curSpec].mainArgNum].type = specs[curSpec].type;


    if (-1 != specs[curSpec].widthArgNum) {
        values[specs[curSpec].widthArgNum].size = 0;
        values[specs[curSpec].widthArgNum].type = CFFormatLongType;
    }
    if (-1 != specs[curSpec].precArgNum) {
        values[specs[curSpec].precArgNum].size = 0;
        values[specs[curSpec].precArgNum].type = CFFormatLongType;
    }
    }

    /* Collect the arguments in correct type from vararg list */
    for (argNum = 0; argNum < sizeArgNum; argNum++) {
    if ((NULL != originalValues) && (0 == values[argNum].type)) values[argNum] = originalValues[argNum];
    switch (values[argNum].type) {
    case 0:
    case CFFormatLiteralType:
        break;
    case CFFormatLongType:
        case CFFormatSingleUnicharType:
        if (CFFormatSize1 == values[argNum].size) {
        values[argNum].value.int64Value = (int64_t)(int8_t)va_arg(args, int);
        } else if (CFFormatSize2 == values[argNum].size) {
        values[argNum].value.int64Value = (int64_t)(int16_t)va_arg(args, int);
        } else if (CFFormatSize4 == values[argNum].size) {
        values[argNum].value.int64Value = (int64_t)va_arg(args, int32_t);
        } else if (CFFormatSize8 == values[argNum].size) {
        values[argNum].value.int64Value = (int64_t)va_arg(args, int64_t);
        } else {
        values[argNum].value.int64Value = (int64_t)va_arg(args, int);
        }
        break;
    case CFFormatDoubleType:
#if LONG_DOUBLE_SUPPORT
        if (CFFormatSize16 == values[argNum].size) {
        values[argNum].value.longDoubleValue = va_arg(args, long double);
        } else 
#endif
        {
        values[argNum].value.doubleValue = va_arg(args, double);
        }
        break;
    case CFFormatPointerType:
    case CFFormatObjectType:
    case CFFormatCFType:
    case CFFormatUnicharsType:
    case CFFormatCharsType:
    case CFFormatPascalCharsType:
        values[argNum].value.pointerValue = va_arg(args, void *);
        break;
    case CFFormatDummyPointerType:
        (void)va_arg(args, void *);     // Skip the provided argument
        values[argNum].value.pointerValue = &dummyLocation;
        break;
    }
    }
    va_end(args);

    /* Format the pieces together */

    if (NULL == originalValues) {
    originalValues = values;
    originalValuesSize = sizeArgNum;
    }

    SInt32 numSpecsContext = 0;
    CFFormatSpec *specsContext = (CFFormatSpec *)calloc(numSpecs, sizeof(CFFormatSpec));
    const CFStringRef replacement = CFSTR("%@NSCONTEXT");
    
    for (curSpec = 0; curSpec < numSpecs; curSpec++) {
    SInt32 width = 0, precision = 0;
    UniChar *up, ch;
    Boolean hasWidth = false, hasPrecision = false;

    // widthArgNum and widthArg are never set at the same time; same for precArg*
    if (-1 != specs[curSpec].widthArgNum) {
        width = (SInt32)values[specs[curSpec].widthArgNum].value.int64Value;
        hasWidth = true;
    }
    if (-1 != specs[curSpec].precArgNum) {
        precision = (SInt32)values[specs[curSpec].precArgNum].value.int64Value;
        hasPrecision = true;
    }
    if (-1 != specs[curSpec].widthArg) {
        width = specs[curSpec].widthArg;
        hasWidth = true;
    }
    if (-1 != specs[curSpec].precArg) {
        precision = specs[curSpec].precArg;
        hasPrecision = true;
    }

    switch (specs[curSpec].type) {
    case CFFormatLongType:
    case CFFormatDoubleType:
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
            if (formatOptions && (specs[curSpec].flags & kCFStringFormatLocalizable) && (CFGetTypeID(formatOptions) == CFLocaleGetTypeID())) {    // We have a locale, so we do localized formatting
                if (__CFStringFormatLocalizedNumber(outputString, (CFLocaleRef)formatOptions, values, &specs[curSpec], width, precision, hasPrecision)) break;
            }
            /* Otherwise fall-thru to the next case! */
#endif
         case CFFormatPointerType: {
                char formatBuffer[128];
#if defined(__GNUC__)
                char buffer[BUFFER_LEN + width + precision];
#else
                char stackBuffer[BUFFER_LEN];
                char *dynamicBuffer = NULL;
                char *buffer = stackBuffer;
                if (256+width+precision > BUFFER_LEN) {
                    dynamicBuffer = (char *)CFAllocatorAllocate(kCFAllocatorSystemDefault, 256+width+precision, 0);
                    buffer = dynamicBuffer;
                }
#endif
                SInt32 cidx, idx, loc;
        Boolean appended = false;
                loc = specs[curSpec].loc;
                // In preparation to call snprintf(), copy the format string out
                if (cformat) {
                    for (idx = 0, cidx = 0; cidx < specs[curSpec].len; idx++, cidx++) {
                        if ('$' == cformat[loc + cidx]) {
                            for (idx--; '0' <= formatBuffer[idx] && formatBuffer[idx] <= '9'; idx--);
                        } else if ('q' == cformat[loc + cidx]) { // WINOBJC: Microsoft CRT doesn't support 'q' format specifier for snprintf calls. To handle this replace with 'll'
                            formatBuffer[idx] = 'l';
                            formatBuffer[++idx] = 'l';
                        } else {
                            formatBuffer[idx] = cformat[loc + cidx];
                        }
                    }
                } else {
                    for (idx = 0, cidx = 0; cidx < specs[curSpec].len; idx++, cidx++) {
                        if ('$' == uformat[loc + cidx]) {
                            for (idx--; '0' <= formatBuffer[idx] && formatBuffer[idx] <= '9'; idx--);
                        } else if ('q' == uformat[loc + cidx]) { // WINOBJC: Microsoft CRT doesn't support 'q' format specifier for snprintf calls. To handle this replace with 'll'
                            formatBuffer[idx] = 'l';
                            formatBuffer[++idx] = 'l';
                        } else {
                            formatBuffer[idx] = (int8_t)uformat[loc + cidx];
                        }
                    }
                }
                formatBuffer[idx] = '\0';
        // Should modify format buffer here if necessary; for example, to translate %qd to
        // the equivalent, on architectures which do not have %q.
                buffer[sizeof(buffer) - 1] = '\0';
                switch (specs[curSpec].type) {
                    case CFFormatLongType:
                        if (CFFormatSize8 == specs[curSpec].size) {
                            SNPRINTF(int64_t, values[specs[curSpec].mainArgNum].value.int64Value)
                        } else {
                            SNPRINTF(SInt32, values[specs[curSpec].mainArgNum].value.int64Value)
                        }
                        break;
                    case CFFormatPointerType:
                    case CFFormatDummyPointerType:
                        SNPRINTF(void *, values[specs[curSpec].mainArgNum].value.pointerValue)
                        break;

                    case CFFormatDoubleType:
#if LONG_DOUBLE_SUPPORT
                        if (CFFormatSize16 == specs[curSpec].size) {
                SNPRINTF(long double, values[specs[curSpec].mainArgNum].value.longDoubleValue)
            } else 
#endif
            {
                SNPRINTF(double, values[specs[curSpec].mainArgNum].value.doubleValue)
            }
            // See if we need to localize the decimal point
                        if (formatOptions) {    // We have localization info
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
                CFStringRef decimalSeparator = (CFGetTypeID(formatOptions) == CFLocaleGetTypeID()) ? (CFStringRef)CFLocaleGetValue((CFLocaleRef)formatOptions, kCFLocaleDecimalSeparatorKey) : (CFStringRef)CFDictionaryGetValue(formatOptions, CFSTR("NSDecimalSeparator"));
#else
                            CFStringRef decimalSeparator = CFSTR(".");
#endif
                            if (decimalSeparator != NULL) { // We have a decimal separator in there
                                CFIndex decimalPointLoc = 0;
                                while (buffer[decimalPointLoc] != 0 && buffer[decimalPointLoc] != '.') decimalPointLoc++;
                                if (buffer[decimalPointLoc] == '.') {   // And we have a decimal point in the formatted string
                                    buffer[decimalPointLoc] = 0;
                                    CFStringAppendCString(outputString, (const char *)buffer, __CFStringGetEightBitStringEncoding());
                                    CFStringAppend(outputString, decimalSeparator);
                                    CFStringAppendCString(outputString, (const char *)(buffer + decimalPointLoc + 1), __CFStringGetEightBitStringEncoding());
                                    appended = true;
                                }
                            }
                        }
                        break;
                }
                if (!appended) CFStringAppendCString(outputString, (const char *)buffer, __CFStringGetEightBitStringEncoding());            
#if !defined(__GNUC__)
                if (dynamicBuffer) {
                        CFAllocatorDeallocate(kCFAllocatorSystemDefault, dynamicBuffer);
                }
#endif
            }
            break;
    case CFFormatLiteralType:
            if (cformat) {
                __CFStringAppendBytes(outputString, (const char *)(cformat+specs[curSpec].loc), specs[curSpec].len, __CFStringGetEightBitStringEncoding());
            } else {
                CFStringAppendCharacters(outputString, uformat+specs[curSpec].loc, specs[curSpec].len);
            }
        break;
    case CFFormatPascalCharsType:
        case CFFormatCharsType:
        if (values[specs[curSpec].mainArgNum].value.pointerValue == NULL) {
        CFStringAppendCString(outputString, "(null)", kCFStringEncodingASCII);
            } else {
                int len;
                const char *str = (const char *)values[specs[curSpec].mainArgNum].value.pointerValue;
                if (specs[curSpec].type == CFFormatPascalCharsType) {   // Pascal string case
                    len = ((unsigned char *)str)[0];
                    str++;
                    if (hasPrecision && precision < len) len = precision;
                } else {    // C-string case
                    if (!hasPrecision) {    // No precision, so rely on the terminating null character
                        len = strlen(str);
                    } else {    // Don't blindly call strlen() if there is a precision; the string might not have a terminating null (3131988)
                        const char *terminatingNull = (const char *)memchr(str, 0, precision);  // Basically strlen() on only the first precision characters of str
                        if (terminatingNull) {  // There was a null in the first precision characters
                            len = terminatingNull - str;
                        } else {
                            len = precision;
                        }
                    }
                }
        // Since the spec says the behavior of the ' ', '0', '#', and '+' flags is undefined for
        // '%s', and since we have ignored them in the past, the behavior is hereby cast in stone
        // to ignore those flags (and, say, never pad with '0' instead of space).
        if (specs[curSpec].flags & kCFStringFormatMinusFlag) {
            __CFStringAppendBytes(outputString, str, len, __CFStringGetSystemEncoding());
            if (hasWidth && width > len) {
            int w = width - len;    // We need this many spaces; do it ten at a time
            do {__CFStringAppendBytes(outputString, "          ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0);
            }
        } else {
            if (hasWidth && width > len) {
            int w = width - len;    // We need this many spaces; do it ten at a time
            do {__CFStringAppendBytes(outputString, "          ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0);
            }
            __CFStringAppendBytes(outputString, str, len, __CFStringGetSystemEncoding());
        }
        }
            break;
        case CFFormatSingleUnicharType:
            ch = (UniChar)values[specs[curSpec].mainArgNum].value.int64Value;
            CFStringAppendCharacters(outputString, &ch, 1);
            break;
        case CFFormatUnicharsType:
            up = (UniChar *)values[specs[curSpec].mainArgNum].value.pointerValue;
            if (NULL == up) {
                CFStringAppendCString(outputString, "(null)", kCFStringEncodingASCII);
            } else {
                int len;
                if (hasPrecision) {
                    // if we have precision, still pay attention to earlier null termination, as we do with %s (19784466)
                    for (len = 0; (len < precision) && (0 != up[len]); len++);
                } else {
                    // if no precision, then simply find the length
                    for (len = 0; 0 != up[len]; len++);
                }
        // Since the spec says the behavior of the ' ', '0', '#', and '+' flags is undefined for
        // '%s', and since we have ignored them in the past, the behavior is hereby cast in stone
        // to ignore those flags (and, say, never pad with '0' instead of space).
        if (specs[curSpec].flags & kCFStringFormatMinusFlag) {
            CFStringAppendCharacters(outputString, up, len);
            if (hasWidth && width > len) {
            int w = width - len;    // We need this many spaces; do it ten at a time
            do {__CFStringAppendBytes(outputString, "          ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0);
            }
        } else {
            if (hasWidth && width > len) {
            int w = width - len;    // We need this many spaces; do it ten at a time
            do {__CFStringAppendBytes(outputString, "          ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0);
            }
            CFStringAppendCharacters(outputString, up, len);
        }
            }
            break;
    case CFFormatCFType:
    case CFFormatObjectType:
        if (specs[curSpec].configDictIndex != -1) { // config dict
        CFTypeRef object = NULL;
        switch (values[specs[curSpec].mainArgNum].type) {
            case CFFormatLongType:
            object = CFNumberCreate(tmpAlloc, kCFNumberSInt64Type, &(values[specs[curSpec].mainArgNum].value.int64Value));
            break;
            
            case CFFormatDoubleType:
#if LONG_DOUBLE_SUPPORT
            if (CFFormatSize16 == values[specs[curSpec].mainArgNum].size) {
                double aValue = values[specs[curSpec].mainArgNum].value.longDoubleValue; // losing precision

                object = CFNumberCreate(tmpAlloc, kCFNumberDoubleType, &aValue);
            } else
#endif
            {
                object = CFNumberCreate(tmpAlloc, kCFNumberDoubleType, &(values[specs[curSpec].mainArgNum].value.doubleValue));
            }
            break;

            case CFFormatPointerType:
            object = CFNumberCreate(tmpAlloc, kCFNumberCFIndexType, &(values[specs[curSpec].mainArgNum].value.pointerValue));
            break;

            case CFFormatPascalCharsType:
            case CFFormatCharsType:
            if (NULL != values[specs[curSpec].mainArgNum].value.pointerValue) {
                CFMutableStringRef aString = CFStringCreateMutable(tmpAlloc, 0);
                int len;
                const char *str = (const char *)values[specs[curSpec].mainArgNum].value.pointerValue;
                if (specs[curSpec].type == CFFormatPascalCharsType) {   // Pascal string case
                len = ((unsigned char *)str)[0];
                str++;
                if (hasPrecision && precision < len) len = precision;
                } else {    // C-string case
                if (!hasPrecision) {    // No precision, so rely on the terminating null character
                    len = strlen(str);
                } else {    // Don't blindly call strlen() if there is a precision; the string might not have a terminating null (3131988)
                    const char *terminatingNull = (const char *)memchr(str, 0, precision);  // Basically strlen() on only the first precision characters of str
                    if (terminatingNull) {  // There was a null in the first precision characters
                    len = terminatingNull - str;
                    } else {
                    len = precision;
                    }
                }
                }
                // Since the spec says the behavior of the ' ', '0', '#', and '+' flags is undefined for
                // '%s', and since we have ignored them in the past, the behavior is hereby cast in stone
                // to ignore those flags (and, say, never pad with '0' instead of space).
                if (specs[curSpec].flags & kCFStringFormatMinusFlag) {
                __CFStringAppendBytes(aString, str, len, __CFStringGetSystemEncoding());
                if (hasWidth && width > len) {
                    int w = width - len;    // We need this many spaces; do it ten at a time
                    do {__CFStringAppendBytes(aString, "          ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0);
                }
                } else {
                if (hasWidth && width > len) {
                    int w = width - len;    // We need this many spaces; do it ten at a time
                    do {__CFStringAppendBytes(aString, "          ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0);
                }
                __CFStringAppendBytes(aString, str, len, __CFStringGetSystemEncoding());
                }

                object = aString;
            }
            break;

            case CFFormatSingleUnicharType:
            ch = (UniChar)values[specs[curSpec].mainArgNum].value.int64Value;
            object = CFStringCreateWithCharactersNoCopy(tmpAlloc, &ch, 1, kCFAllocatorNull);
            break;

            case CFFormatUnicharsType:
            //??? need to handle width, precision, and padding arguments
            up = (UniChar *)values[specs[curSpec].mainArgNum].value.pointerValue;
            if (NULL != up) {
                CFMutableStringRef aString = CFStringCreateMutable(tmpAlloc, 0);
                int len;
                for (len = 0; 0 != up[len]; len++);
                // Since the spec says the behavior of the ' ', '0', '#', and '+' flags is undefined for
                // '%s', and since we have ignored them in the past, the behavior is hereby cast in stone
                // to ignore those flags (and, say, never pad with '0' instead of space).
                if (hasPrecision && precision < len) len = precision;
                if (specs[curSpec].flags & kCFStringFormatMinusFlag) {
                CFStringAppendCharacters(aString, up, len);
                if (hasWidth && width > len) {
                    int w = width - len;    // We need this many spaces; do it ten at a time
                    do {__CFStringAppendBytes(aString, "          ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0);
                }
                } else {
                if (hasWidth && width > len) {
                    int w = width - len;    // We need this many spaces; do it ten at a time
                    do {__CFStringAppendBytes(aString, "          ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0);
                }
                CFStringAppendCharacters(aString, up, len);
                }
                object = aString;
            }
            break;

            case CFFormatCFType:
            case CFFormatObjectType:
            if (NULL != values[specs[curSpec].mainArgNum].value.pointerValue) object = CFRetain(values[specs[curSpec].mainArgNum].value.pointerValue);
            break;
        }

        if (NULL != object) CFRelease(object);

        } else if (NULL != values[specs[curSpec].mainArgNum].value.pointerValue) {
                CFStringRef str = NULL;
                if (contextDescFunc) {
                    bool found = NO;
                    str = contextDescFunc(values[specs[curSpec].mainArgNum].value.pointerValue, formatString, replacement, NO, &found);
                    if (found) {
                        str = static_cast<CFStringRef>(CFRetain(replacement));
                        specsContext[numSpecsContext] = specs[curSpec];
                        numSpecsContext++;
                    }
                }
                if (!str) {
                    if (copyDescFunc) {
                        str = copyDescFunc(values[specs[curSpec].mainArgNum].value.pointerValue, formatOptions);
                    } else {
                        str = __CFCopyFormattingDescription(values[specs[curSpec].mainArgNum].value.pointerValue, formatOptions);
                        if (NULL == str) {
                            str = CFCopyDescription(values[specs[curSpec].mainArgNum].value.pointerValue);
                        }
                    }
                }
                if (str) {
                    CFStringAppend(outputString, str);
                    CFRelease(str);
                } else {
                    CFStringAppendCString(outputString, "(null description)", kCFStringEncodingASCII);
                }
            } else {
        CFStringAppendCString(outputString, "(null)", kCFStringEncodingASCII);
            }
            break;
        }
    }
    
    for (SInt32 i = 0; i < numSpecsContext; i++) {
        CFRange range = CFStringFind(outputString, replacement, 0);
        CFStringRef str = contextDescFunc(values[specsContext[i].mainArgNum].value.pointerValue, outputString, replacement, true, NULL);
        if (str) {
            CFStringReplace(outputString, range, str);
            CFRelease(str);
        }
    }
    
    free(specsContext);

#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
    // va_copy is a C99 extension. No support on Windows
    if (numConfigs > 0) va_end(copiedArgs);
#endif 
    if (specs != localSpecsBuffer) CFAllocatorDeallocate(tmpAlloc, specs);
    if (values != localValuesBuffer) CFAllocatorDeallocate(tmpAlloc, values);
    if (formatChars && (formatChars != localFormatBuffer)) CFAllocatorDeallocate(tmpAlloc, formatChars);
    if (configs != localConfigs) CFAllocatorDeallocate(tmpAlloc, configs);
    if (formattingConfig != NULL) CFRelease(formattingConfig);
}