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);
}