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