File: CFRelativeDateTimeFormatter.c

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (190 lines) | stat: -rw-r--r-- 7,899 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*  CFRelativeDateTimeFormatter.c
    Copyright (c) 2018-2019, Apple Inc. and the Swift project authors

    Portions Copyright (c) 2014-2019, Apple Inc. and the Swift project authors
    Licensed under Apache License v2.0 with Runtime Library Exception
    See http://swift.org/LICENSE.txt for license information
    See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
    Responsibility: I-Ting Liu
 */

#include "CFRelativeDateTimeFormatter.h"

#include <assert.h>
#include "CFICULogging.h"
#include "CFInternal.h"
#include "CFRuntime_Internal.h"

struct __CFRelativeDateTimeFormatter {
    CFRuntimeBase _base;
    CFRelativeDateTimeFormatterStyle _style;
    CFRelativeDateTimeFormatterUnitsStyle _unitsStyle;
    CFLocaleRef _locale;
    CFRelativeDateTimeFormattingContext _formattingContext;
};

static UDateRelativeDateTimeFormatterStyle icuRelativeDateTimeStyleFromUnitsStyle(CFRelativeDateTimeFormatterUnitsStyle style) {
    switch (style) {
        case CFRelativeDateTimeFormatterUnitsStyleSpellOut:
        case CFRelativeDateTimeFormatterUnitsStyleFull:
            return UDAT_STYLE_LONG;
        case CFRelativeDateTimeFormatterUnitsStyleShort:
            return UDAT_STYLE_SHORT;
        case CFRelativeDateTimeFormatterUnitsStyleAbbreviated:
            return UDAT_STYLE_NARROW;
        default:
            HALT_MSG("Invalid CFRelativeDateTimeFormatterStyle");
    }
}

static URelativeDateTimeUnit icuRelativeDateTimeUnitFromCFUnit(CFCalendarUnit unit) {
    switch (unit) {
        case kCFCalendarUnitYear:
            return UDAT_REL_UNIT_YEAR;
        case kCFCalendarUnitMonth:
            return UDAT_REL_UNIT_MONTH;
        case kCFCalendarUnitWeekOfMonth:
            return UDAT_REL_UNIT_WEEK;
        case kCFCalendarUnitDay:
            return UDAT_REL_UNIT_DAY;
        case kCFCalendarUnitHour:
            return UDAT_REL_UNIT_HOUR;
        case kCFCalendarUnitMinute:
            return UDAT_REL_UNIT_MINUTE;
        case kCFCalendarUnitSecond:
            return UDAT_REL_UNIT_SECOND;
        default:
            HALT_MSG("Invalid CFCalendarUnit");
    }
}

static UDisplayContext icuFormattingContextFromCFContext(CFRelativeDateTimeFormattingContext context) {
    switch (context) {
        case CFRelativeDateTimeFormattingContextUnknown:
        case CFRelativeDateTimeFormattingContextDynamic:
            return UDISPCTX_CAPITALIZATION_NONE;
        case CFRelativeDateTimeFormattingContextStandalone:
            return UDISPCTX_CAPITALIZATION_FOR_STANDALONE;
        case CFRelativeDateTimeFormattingContextListItem:
            return UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU;
        case CFRelativeDateTimeFormattingContextBeginningOfSentence:
            return UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE;
        case CFRelativeDateTimeFormattingContextMiddleOfSentence:
            return UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE;
        default:
            HALT_MSG("Invalid CFRelativeDateTimeFormattingContext");
    }
}

static void __CFRelativeDateTimeFormatterDeallocate(CFTypeRef cf) {
    assert(cf != NULL);
    CFRelativeDateTimeFormatterRef formatter = (CFRelativeDateTimeFormatterRef)cf;
    if (formatter->_locale) { CFRelease(formatter->_locale); }
}

static CFStringRef __CFRelativeDateTimeFormatterCopyDescription(CFTypeRef cf) {
    assert(cf != NULL);
    CFRelativeDateTimeFormatterRef formatter = (CFRelativeDateTimeFormatterRef)cf;
    return CFStringCreateWithFormat(CFGetAllocator(formatter), NULL, CFSTR("<CFRelativeDateTimeFormatter %p>[%p]"), formatter, CFGetAllocator(formatter));
}

const CFRuntimeClass __CFRelativeDateTimeFormatterClass = {
    0,
    "CFRelativeDateTimeFormatter",
    NULL,   // init
    NULL,   // copy
    __CFRelativeDateTimeFormatterDeallocate,
    NULL,   // equal
    NULL,   // hash
    NULL,   // copy formatting desc
    __CFRelativeDateTimeFormatterCopyDescription
};

CFTypeID _CFRelativeDateTimeFormatterGetTypeID(void) {
    return _kCFRuntimeIDCFRelativeDateTimeFormatter;
}

CFRelativeDateTimeFormatterRef _CFRelativeDateTimeFormatterCreate(CFAllocatorRef allocator, CFLocaleRef locale, CFRelativeDateTimeFormatterUnitsStyle unitsStyle, CFRelativeDateTimeFormatterStyle style, CFRelativeDateTimeFormattingContext formattingContext) {
    if (allocator == NULL) { allocator = __CFGetDefaultAllocator(); }
    __CFGenericValidateType(allocator, CFAllocatorGetTypeID());

    CFAssert1(locale != NULL, __kCFLogAssertion, "%s(): locale cannot be NULL", __PRETTY_FUNCTION__);
    __CFGenericValidateType(locale, CFLocaleGetTypeID());

    size_t size = sizeof(struct __CFRelativeDateTimeFormatter) - sizeof(CFRuntimeBase);
    struct __CFRelativeDateTimeFormatter *formatter;
    formatter = (struct __CFRelativeDateTimeFormatter*)_CFRuntimeCreateInstance(allocator, _CFRelativeDateTimeFormatterGetTypeID(), size, NULL);
    if (formatter == NULL) { return NULL; }

    formatter->_locale = CFRetain(locale);
    formatter->_formattingContext = formattingContext;
    formatter->_unitsStyle = unitsStyle;
    formatter->_style = style;

    return formatter;
}

CFStringRef _CFRelativeDateTimeFormatterCreateStringWithCalendarUnit(CFAllocatorRef allocator, CFRelativeDateTimeFormatterRef formatter, CFCalendarUnit unit, double offset) {
    CFLocaleRef locale = formatter->_locale;
    CFStringRef localeIdentifier = CFLocaleGetIdentifier(locale);
    char buffer[ULOC_FULLNAME_CAPACITY];
    const char *cLocaleIdentifier = CFStringGetCStringPtr(localeIdentifier, kCFStringEncodingASCII);
    if (NULL == cLocaleIdentifier) {
        if (CFStringGetCString(localeIdentifier, buffer, ULOC_FULLNAME_CAPACITY, kCFStringEncodingASCII)) {
            cLocaleIdentifier = buffer;
        }
    }

    UNumberFormat *numFmt = NULL;
    CFRelativeDateTimeFormatterUnitsStyle unitsStyle = formatter->_unitsStyle;
    if (unitsStyle == CFRelativeDateTimeFormatterUnitsStyleSpellOut) {
        UErrorCode status = U_ZERO_ERROR;
        numFmt = __cficu_unum_open(UNUM_SPELLOUT, NULL, 0, cLocaleIdentifier, NULL, &status);
        if (U_FAILURE(status)) {
            if (numFmt) {
                __cficu_unum_close(numFmt);
            }
            return NULL;
        }
    }

    UDateRelativeDateTimeFormatterStyle style = icuRelativeDateTimeStyleFromUnitsStyle(unitsStyle);

    UErrorCode status = U_ZERO_ERROR;
    UDisplayContext context = icuFormattingContextFromCFContext(formatter->_formattingContext);
    // This takes over the ownership of numFmt, so there's not need to close numFmt.
    URelativeDateTimeFormatter *fmt = __cficu_ureldatefmt_open(cLocaleIdentifier, numFmt, style, context, &status);
    if (U_FAILURE(status)) {
        if (fmt) {
            __cficu_ureldatefmt_close(fmt);
        }
        return NULL;
    }

    URelativeDateTimeUnit icuUnit = icuRelativeDateTimeUnitFromCFUnit(unit);

    int32_t len = 0;
    const int32_t RESULT_BUFFER_SIZE = 128;
    UChar result[RESULT_BUFFER_SIZE + 1];
    status = U_ZERO_ERROR;
    CFRelativeDateTimeFormatterStyle dateTimeStyle = formatter->_style;
    switch (dateTimeStyle) {
        case CFRelativeDateTimeFormatterStyleNumeric:
            len = __cficu_ureldatefmt_formatNumeric(fmt, offset, icuUnit, result, RESULT_BUFFER_SIZE, &status);
            break;
        case CFRelativeDateTimeFormatterStyleNamed:
            len = __cficu_ureldatefmt_format(fmt, offset, icuUnit, result, RESULT_BUFFER_SIZE, &status);
            break;
        default:
            HALT_MSG("Invalid CFRelativeDateTimeFormatterStyle");
    }

    CFAssert1(fmt != NULL, __kCFLogAssertion, "%s(): URelativeDateTimeFormatter should not be NULL", __PRETTY_FUNCTION__);
    __cficu_ureldatefmt_close(fmt);

    if (U_FAILURE(status)){ return NULL; }

    if (allocator == NULL) { allocator = __CFGetDefaultAllocator(); }
    return CFStringCreateWithCharacters(allocator, result, len);
}