CF_INLINE void __CFParseFormatSpec()

in Frameworks/CoreFoundation/String.subproj/CFString.c [5815:6026]


CF_INLINE void __CFParseFormatSpec(const UniChar *uformat, const uint8_t *cformat, SInt32 *fmtIdx, SInt32 fmtLen, CFFormatSpec *spec, CFStringRef *configKeyPointer) {
    Boolean seenDot = false;
    Boolean seenSharp = false;
    Boolean seenOpenBracket = false;
    Boolean validBracketSequence = false;
    CFIndex keyLength = 0;
    CFIndex keyIndex = kCFNotFound;

    for (;;) {
    UniChar ch;
    if (fmtLen <= *fmtIdx) return;  /* no type */
        if (cformat) ch = (UniChar)cformat[(*fmtIdx)++]; else ch = uformat[(*fmtIdx)++];

    if (keyIndex >= 0) {
            if ((ch < '0') || ((ch > '9') && (ch < 'A')) || ((ch > 'Z') && (ch < 'a') && (ch != '_')) || (ch > 'z')) {
        if (ch == ']') {
                    if (seenOpenBracket) {
                        validBracketSequence = true;
                        keyLength = (*fmtIdx) - 1 - keyIndex;
                    }
                } else if (ch == '@') {
                    if (validBracketSequence) {
                        spec->flags |= kCFStringFormatEntityMarkerFlag;
                    } else {
                        keyLength = (*fmtIdx) - 1 - keyIndex;
                    }

                    spec->flags |= kCFStringFormatExternalSpecFlag;
                    spec->type = CFFormatCFType;
                    spec->size = CFFormatSizePointer;  // 4 or 8 depending on LP64

                    if ((NULL != configKeyPointer) && (keyLength > 0)) {
                        if (cformat) {
                            *configKeyPointer = CFStringCreateWithBytes(NULL, cformat + keyIndex, keyLength, __CFStringGetEightBitStringEncoding(), FALSE);
                        } else {
                            *configKeyPointer = CFStringCreateWithCharactersNoCopy(NULL, uformat + keyIndex, keyLength, kCFAllocatorNull);
                        }
                    }
                    return;
                } else {
                    keyIndex = kCFNotFound;
                }
            }
            continue;
        }
reswtch:switch (ch) {
    case '#':   // ignored for now
        seenSharp = true;
        break;
        case '[':
            if (!seenOpenBracket) { // We can only have one
                seenOpenBracket = true;
                keyIndex = *fmtIdx;
            }
            break;
    case 0x20:
        if (!(spec->flags & kCFStringFormatPlusFlag)) spec->flags |= kCFStringFormatSpaceFlag;
        break;
    case '-':
        spec->flags |= kCFStringFormatMinusFlag;
        spec->flags &= ~kCFStringFormatZeroFlag;    // remove zero flag
        break;
    case '+':
        spec->flags |= kCFStringFormatPlusFlag;
        spec->flags &= ~kCFStringFormatSpaceFlag;   // remove space flag
        break;
    case '0':
            if (seenDot) {    // after we see '.' and then we see '0', it is 0 precision. We should not see '.' after '0' if '0' is the zero padding flag
                spec->precArg = 0;
                break;
            }
        if (!(spec->flags & kCFStringFormatMinusFlag)) spec->flags |= kCFStringFormatZeroFlag;
        break;
    case 'h':
        if (*fmtIdx < fmtLen) {
        // fetch next character, don't increment fmtIdx
        if (cformat) ch = (UniChar)cformat[(*fmtIdx)]; else ch = uformat[(*fmtIdx)];
        if ('h' == ch) {    // 'hh' for char, like 'c'
            (*fmtIdx)++;
            spec->size = CFFormatSize1;
            break;
        }
        }
        spec->size = CFFormatSize2;
        break;
    case 'l':
        if (*fmtIdx < fmtLen) {
        // fetch next character, don't increment fmtIdx
        if (cformat) ch = (UniChar)cformat[(*fmtIdx)]; else ch = uformat[(*fmtIdx)];
        if ('l' == ch) {    // 'll' for long long, like 'q'
            (*fmtIdx)++;
            spec->size = CFFormatSize8;
            break;
        }
        }
        spec->size = CFFormatSizeLong;  // 4 or 8 depending on LP64
        break;
#if LONG_DOUBLE_SUPPORT
    case 'L':
        spec->size = CFFormatSize16;
        break;
#endif
    case 'q':
        spec->size = CFFormatSize8;
        break;
    case 't': case 'z':
        spec->size = CFFormatSizeLong;  // 4 or 8 depending on LP64
        break;
    case 'j':
        spec->size = CFFormatSize8; 
        break;
    case 'c':
        spec->type = CFFormatLongType;
        spec->size = CFFormatSize1;
        return;
        case 'D': case 'd': case 'i': case 'U': case 'u':
            // we can localize all but octal or hex
            if (_CFExecutableLinkedOnOrAfter(CFSystemVersionMountainLion)) spec->flags |= kCFStringFormatLocalizable;
            spec->numericFormatStyle = CFFormatStyleDecimal;
            if (ch == 'u' || ch == 'U') spec->numericFormatStyle = CFFormatStyleUnsigned;
            // fall thru
        case 'O': case 'o': case 'x': case 'X':
            spec->type = CFFormatLongType;
            // Seems like if spec->size == 0, we should spec->size = CFFormatSize4. However, 0 is handled correctly.
        return;
        case 'f': case 'F': case 'g': case 'G': case 'e': case 'E': {
                // we can localize all but hex float output
                if (_CFExecutableLinkedOnOrAfter(CFSystemVersionMountainLion)) spec->flags |= kCFStringFormatLocalizable;
                char lch = (ch >= 'A' && ch <= 'Z') ? (ch - 'A' + 'a') : ch;
                spec->numericFormatStyle = ((lch == 'e' || lch == 'g') ? CFFormatStyleScientific : 0) | ((lch == 'f' || lch == 'g') ? CFFormatStyleDecimal : 0);
                if (seenDot && spec->precArg == -1 && spec->precArgNum == -1) { // for the cases that we have '.' but no precision followed, not even '*'
                    spec->precArg = 0;
                }
            }
            // fall thru
        case 'a': case 'A':
        spec->type = CFFormatDoubleType;
        if (spec->size != CFFormatSize16) spec->size = CFFormatSize8;
        return;
    case 'n':       /* %n is not handled correctly; for Leopard or newer apps, we disable it further */
        spec->type = 1 ? CFFormatDummyPointerType : CFFormatPointerType;
        spec->size = CFFormatSizePointer;  // 4 or 8 depending on LP64
        return;
    case 'p':   
        spec->type = CFFormatPointerType;
        spec->size = CFFormatSizePointer;  // 4 or 8 depending on LP64
        return;
    case 's':
        spec->type = CFFormatCharsType;
        spec->size = CFFormatSizePointer;  // 4 or 8 depending on LP64
        return;
    case 'S':
        spec->type = CFFormatUnicharsType;
        spec->size = CFFormatSizePointer;  // 4 or 8 depending on LP64
        return;
        case 'C':
            spec->type = CFFormatSingleUnicharType;
            spec->size = CFFormatSize2;
            return;
    case 'P':
        spec->type = CFFormatPascalCharsType;
        spec->size = CFFormatSizePointer;  // 4 or 8 depending on LP64
        return;
    case '@':
        if (seenSharp) {
        seenSharp = false;
        keyIndex = *fmtIdx;
        break;
        } else {
        spec->type = CFFormatCFType;
        spec->size = CFFormatSizePointer;  // 4 or 8 depending on LP64
        return;
        }
    case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': {
        int64_t number = 0;
        do {
        number = 10 * number + (ch - '0');
                if (cformat) ch = (UniChar)cformat[(*fmtIdx)++]; else ch = uformat[(*fmtIdx)++];
        } while ((UInt32)(ch - '0') <= 9);
        if ('$' == ch) {
        if (-2 == spec->precArgNum) {
            spec->precArgNum = (int8_t)number - 1;  // Arg numbers start from 1
        } else if (-2 == spec->widthArgNum) {
            spec->widthArgNum = (int8_t)number - 1; // Arg numbers start from 1
        } else {
            spec->mainArgNum = (int8_t)number - 1;  // Arg numbers start from 1
        }
        break;
        } else if (seenDot) {   /* else it's either precision or width */
        spec->precArg = (SInt32)number;
        } else {
        spec->widthArg = (SInt32)number;
        }
        goto reswtch;
    }
    case '*':
        spec->widthArgNum = -2;
        break;
    case '.':
        seenDot = true;
            if (cformat) ch = (UniChar)cformat[(*fmtIdx)++]; else ch = uformat[(*fmtIdx)++];
        if ('*' == ch) {
        spec->precArgNum = -2;
        break;
        }
        goto reswtch;
    default:
        spec->type = CFFormatLiteralType;
        return;
    }
    }
}