]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/udatpg.cpp
ICU-59117.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / udatpg.cpp
CommitLineData
f3c0d7a5
A
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
46f4442e
A
3/*
4*******************************************************************************
5*
2ca993e8 6* Copyright (C) 2009-2015, International Business Machines
46f4442e
A
7* Corporation and others. All Rights Reserved.
8*
9*******************************************************************************
10* file name: udatpg.cpp
f3c0d7a5 11* encoding: UTF-8
46f4442e
A
12* tab size: 8 (not used)
13* indentation:4
14*
15* created on: 2007jul30
16* created by: Markus W. Scherer
17*/
18
19#include "unicode/utypes.h"
20
21#if !UCONFIG_NO_FORMATTING
22
23#include "unicode/udatpg.h"
24#include "unicode/uenum.h"
25#include "unicode/strenum.h"
b331163b 26#include "unicode/unistr.h"
46f4442e 27#include "unicode/dtptngen.h"
b331163b 28#include "unicode/uchar.h"
46f4442e 29#include "ustrenum.h"
b331163b 30#include "dtitv_impl.h"
46f4442e
A
31
32U_NAMESPACE_USE
33
51004dcb 34U_CAPI UDateTimePatternGenerator * U_EXPORT2
46f4442e
A
35udatpg_open(const char *locale, UErrorCode *pErrorCode) {
36 if(locale==NULL) {
37 return (UDateTimePatternGenerator *)DateTimePatternGenerator::createInstance(*pErrorCode);
38 } else {
39 return (UDateTimePatternGenerator *)DateTimePatternGenerator::createInstance(Locale(locale), *pErrorCode);
40 }
41}
42
51004dcb 43U_CAPI UDateTimePatternGenerator * U_EXPORT2
46f4442e
A
44udatpg_openEmpty(UErrorCode *pErrorCode) {
45 return (UDateTimePatternGenerator *)DateTimePatternGenerator::createEmptyInstance(*pErrorCode);
46}
47
51004dcb 48U_CAPI void U_EXPORT2
46f4442e
A
49udatpg_close(UDateTimePatternGenerator *dtpg) {
50 delete (DateTimePatternGenerator *)dtpg;
51}
52
51004dcb 53U_CAPI UDateTimePatternGenerator * U_EXPORT2
46f4442e
A
54udatpg_clone(const UDateTimePatternGenerator *dtpg, UErrorCode *pErrorCode) {
55 if(U_FAILURE(*pErrorCode)) {
56 return NULL;
57 }
58 return (UDateTimePatternGenerator *)(((const DateTimePatternGenerator *)dtpg)->clone());
59}
60
51004dcb 61U_CAPI int32_t U_EXPORT2
46f4442e
A
62udatpg_getBestPattern(UDateTimePatternGenerator *dtpg,
63 const UChar *skeleton, int32_t length,
64 UChar *bestPattern, int32_t capacity,
65 UErrorCode *pErrorCode) {
729e4ab9
A
66 return udatpg_getBestPatternWithOptions(dtpg, skeleton, length,
67 UDATPG_MATCH_NO_OPTIONS,
68 bestPattern, capacity, pErrorCode);
69}
70
51004dcb 71U_CAPI int32_t U_EXPORT2
729e4ab9
A
72udatpg_getBestPatternWithOptions(UDateTimePatternGenerator *dtpg,
73 const UChar *skeleton, int32_t length,
74 UDateTimePatternMatchOptions options,
75 UChar *bestPattern, int32_t capacity,
76 UErrorCode *pErrorCode) {
46f4442e
A
77 if(U_FAILURE(*pErrorCode)) {
78 return 0;
79 }
80 if(skeleton==NULL && length!=0) {
81 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
82 return 0;
83 }
84 UnicodeString skeletonString((UBool)(length<0), skeleton, length);
729e4ab9 85 UnicodeString result=((DateTimePatternGenerator *)dtpg)->getBestPattern(skeletonString, options, *pErrorCode);
46f4442e
A
86 return result.extract(bestPattern, capacity, *pErrorCode);
87}
88
51004dcb 89U_CAPI int32_t U_EXPORT2
2ca993e8 90udatpg_getSkeleton(UDateTimePatternGenerator * /* dtpg */,
46f4442e
A
91 const UChar *pattern, int32_t length,
92 UChar *skeleton, int32_t capacity,
93 UErrorCode *pErrorCode) {
94 if(U_FAILURE(*pErrorCode)) {
95 return 0;
96 }
97 if(pattern==NULL && length!=0) {
98 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
99 return 0;
100 }
101 UnicodeString patternString((UBool)(length<0), pattern, length);
2ca993e8
A
102 UnicodeString result=DateTimePatternGenerator::staticGetSkeleton(
103 patternString, *pErrorCode);
46f4442e
A
104 return result.extract(skeleton, capacity, *pErrorCode);
105}
106
51004dcb 107U_CAPI int32_t U_EXPORT2
2ca993e8 108udatpg_getBaseSkeleton(UDateTimePatternGenerator * /* dtpg */,
46f4442e
A
109 const UChar *pattern, int32_t length,
110 UChar *skeleton, int32_t capacity,
111 UErrorCode *pErrorCode) {
112 if(U_FAILURE(*pErrorCode)) {
113 return 0;
114 }
115 if(pattern==NULL && length!=0) {
116 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
117 return 0;
118 }
119 UnicodeString patternString((UBool)(length<0), pattern, length);
2ca993e8
A
120 UnicodeString result=DateTimePatternGenerator::staticGetBaseSkeleton(
121 patternString, *pErrorCode);
46f4442e
A
122 return result.extract(skeleton, capacity, *pErrorCode);
123}
124
51004dcb 125U_CAPI UDateTimePatternConflict U_EXPORT2
46f4442e
A
126udatpg_addPattern(UDateTimePatternGenerator *dtpg,
127 const UChar *pattern, int32_t patternLength,
128 UBool override,
129 UChar *conflictingPattern, int32_t capacity, int32_t *pLength,
130 UErrorCode *pErrorCode) {
131 if(U_FAILURE(*pErrorCode)) {
132 return UDATPG_NO_CONFLICT;
133 }
134 if(pattern==NULL && patternLength!=0) {
135 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
136 return UDATPG_NO_CONFLICT;
137 }
138 UnicodeString patternString((UBool)(patternLength<0), pattern, patternLength);
139 UnicodeString conflictingPatternString;
140 UDateTimePatternConflict result=((DateTimePatternGenerator *)dtpg)->
141 addPattern(patternString, override, conflictingPatternString, *pErrorCode);
142 int32_t length=conflictingPatternString.extract(conflictingPattern, capacity, *pErrorCode);
143 if(pLength!=NULL) {
144 *pLength=length;
145 }
146 return result;
147}
148
51004dcb 149U_CAPI void U_EXPORT2
46f4442e
A
150udatpg_setAppendItemFormat(UDateTimePatternGenerator *dtpg,
151 UDateTimePatternField field,
152 const UChar *value, int32_t length) {
153 UnicodeString valueString((UBool)(length<0), value, length);
154 ((DateTimePatternGenerator *)dtpg)->setAppendItemFormat(field, valueString);
155}
156
51004dcb 157U_CAPI const UChar * U_EXPORT2
46f4442e
A
158udatpg_getAppendItemFormat(const UDateTimePatternGenerator *dtpg,
159 UDateTimePatternField field,
160 int32_t *pLength) {
161 const UnicodeString &result=((const DateTimePatternGenerator *)dtpg)->getAppendItemFormat(field);
162 if(pLength!=NULL) {
163 *pLength=result.length();
164 }
165 return result.getBuffer();
166}
167
51004dcb 168U_CAPI void U_EXPORT2
46f4442e
A
169udatpg_setAppendItemName(UDateTimePatternGenerator *dtpg,
170 UDateTimePatternField field,
171 const UChar *value, int32_t length) {
172 UnicodeString valueString((UBool)(length<0), value, length);
173 ((DateTimePatternGenerator *)dtpg)->setAppendItemName(field, valueString);
174}
175
51004dcb 176U_CAPI const UChar * U_EXPORT2
46f4442e
A
177udatpg_getAppendItemName(const UDateTimePatternGenerator *dtpg,
178 UDateTimePatternField field,
179 int32_t *pLength) {
180 const UnicodeString &result=((const DateTimePatternGenerator *)dtpg)->getAppendItemName(field);
181 if(pLength!=NULL) {
182 *pLength=result.length();
183 }
184 return result.getBuffer();
185}
186
51004dcb 187U_CAPI void U_EXPORT2
46f4442e
A
188udatpg_setDateTimeFormat(const UDateTimePatternGenerator *dtpg,
189 const UChar *dtFormat, int32_t length) {
190 UnicodeString dtFormatString((UBool)(length<0), dtFormat, length);
191 ((DateTimePatternGenerator *)dtpg)->setDateTimeFormat(dtFormatString);
192}
193
51004dcb 194U_CAPI const UChar * U_EXPORT2
46f4442e
A
195udatpg_getDateTimeFormat(const UDateTimePatternGenerator *dtpg,
196 int32_t *pLength) {
197 const UnicodeString &result=((const DateTimePatternGenerator *)dtpg)->getDateTimeFormat();
198 if(pLength!=NULL) {
199 *pLength=result.length();
200 }
201 return result.getBuffer();
202}
203
51004dcb 204U_CAPI void U_EXPORT2
46f4442e
A
205udatpg_setDecimal(UDateTimePatternGenerator *dtpg,
206 const UChar *decimal, int32_t length) {
207 UnicodeString decimalString((UBool)(length<0), decimal, length);
208 ((DateTimePatternGenerator *)dtpg)->setDecimal(decimalString);
209}
210
51004dcb 211U_CAPI const UChar * U_EXPORT2
46f4442e
A
212udatpg_getDecimal(const UDateTimePatternGenerator *dtpg,
213 int32_t *pLength) {
214 const UnicodeString &result=((const DateTimePatternGenerator *)dtpg)->getDecimal();
215 if(pLength!=NULL) {
216 *pLength=result.length();
217 }
218 return result.getBuffer();
219}
220
51004dcb 221U_CAPI int32_t U_EXPORT2
46f4442e
A
222udatpg_replaceFieldTypes(UDateTimePatternGenerator *dtpg,
223 const UChar *pattern, int32_t patternLength,
224 const UChar *skeleton, int32_t skeletonLength,
225 UChar *dest, int32_t destCapacity,
226 UErrorCode *pErrorCode) {
729e4ab9
A
227 return udatpg_replaceFieldTypesWithOptions(dtpg, pattern, patternLength, skeleton, skeletonLength,
228 UDATPG_MATCH_NO_OPTIONS,
229 dest, destCapacity, pErrorCode);
230}
231
51004dcb 232U_CAPI int32_t U_EXPORT2
729e4ab9
A
233udatpg_replaceFieldTypesWithOptions(UDateTimePatternGenerator *dtpg,
234 const UChar *pattern, int32_t patternLength,
235 const UChar *skeleton, int32_t skeletonLength,
236 UDateTimePatternMatchOptions options,
237 UChar *dest, int32_t destCapacity,
238 UErrorCode *pErrorCode) {
46f4442e
A
239 if(U_FAILURE(*pErrorCode)) {
240 return 0;
241 }
242 if((pattern==NULL && patternLength!=0) || (skeleton==NULL && skeletonLength!=0)) {
243 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
244 return 0;
245 }
246 UnicodeString patternString((UBool)(patternLength<0), pattern, patternLength);
247 UnicodeString skeletonString((UBool)(skeletonLength<0), skeleton, skeletonLength);
729e4ab9 248 UnicodeString result=((DateTimePatternGenerator *)dtpg)->replaceFieldTypes(patternString, skeletonString, options, *pErrorCode);
46f4442e
A
249 return result.extract(dest, destCapacity, *pErrorCode);
250}
251
51004dcb 252U_CAPI UEnumeration * U_EXPORT2
46f4442e 253udatpg_openSkeletons(const UDateTimePatternGenerator *dtpg, UErrorCode *pErrorCode) {
729e4ab9 254 return uenum_openFromStringEnumeration(
46f4442e
A
255 ((DateTimePatternGenerator *)dtpg)->getSkeletons(*pErrorCode),
256 pErrorCode);
257}
258
51004dcb 259U_CAPI UEnumeration * U_EXPORT2
46f4442e 260udatpg_openBaseSkeletons(const UDateTimePatternGenerator *dtpg, UErrorCode *pErrorCode) {
729e4ab9 261 return uenum_openFromStringEnumeration(
46f4442e
A
262 ((DateTimePatternGenerator *)dtpg)->getBaseSkeletons(*pErrorCode),
263 pErrorCode);
264}
265
51004dcb 266U_CAPI const UChar * U_EXPORT2
46f4442e
A
267udatpg_getPatternForSkeleton(const UDateTimePatternGenerator *dtpg,
268 const UChar *skeleton, int32_t skeletonLength,
269 int32_t *pLength) {
270 UnicodeString skeletonString((UBool)(skeletonLength<0), skeleton, skeletonLength);
271 const UnicodeString &result=((const DateTimePatternGenerator *)dtpg)->getPatternForSkeleton(skeletonString);
272 if(pLength!=NULL) {
273 *pLength=result.length();
274 }
275 return result.getBuffer();
276}
277
b331163b
A
278// Helper function for uadatpg_remapPatternWithOptionsLoc
279static int32_t
280_doReplaceAndReturnAdj( UDateTimePatternGenerator *dtpg, uint32_t options, UBool matchHourLen,
281 UnicodeString &patternString, const UnicodeString &skeleton, const UnicodeString &otherCycSkeleton,
282 int32_t timePatStart, int32_t timePatLimit, int32_t timeNonHourStart, int32_t timeNonHourLimit,
283 UErrorCode *pErrorCode) {
284 if (matchHourLen) {
285 options |= UDATPG_MATCH_HOUR_FIELD_LENGTH;
286 }
287 UnicodeString replacement=((DateTimePatternGenerator *)dtpg)->getBestPattern(otherCycSkeleton, (UDateTimePatternMatchOptions)options, *pErrorCode);
288 if (U_FAILURE(*pErrorCode)) {
289 return 0;
290 }
291 UnicodeString stringForOrigSkeleton=((DateTimePatternGenerator *)dtpg)->getBestPattern(skeleton, (UDateTimePatternMatchOptions)options, *pErrorCode);
292 if (U_SUCCESS(*pErrorCode)) {
293 int32_t index = patternString.indexOf(stringForOrigSkeleton);
294 if (index >= 0) {
295 int32_t stringForOrigSkelLen = stringForOrigSkeleton.length();
296 patternString.replace(index, stringForOrigSkelLen, replacement);
297 return replacement.length() - stringForOrigSkelLen;
298 }
299 } else {
300 *pErrorCode = U_ZERO_ERROR;
301 }
302 if (timeNonHourStart >= 0 && timeNonHourLimit > timeNonHourStart) {
303 // find any minutes/seconds/milliseconds part of replacement, set that back to the
304 // minutes/seconds/milliseconds part of the original pattern.
305 // First get the minutes/seconds/milliseconds part of the original pattern.
306 UnicodeString nonHour;
307 patternString.extractBetween(timeNonHourStart, timeNonHourLimit, nonHour);
308 // Now scan to find position from just after hours to end of minutes/seconds/milliseconds.
309 timeNonHourStart = -1;
310 timeNonHourLimit = 0;
311 UBool inQuoted = FALSE;
312 int32_t repPos, repLen = replacement.length();
313 for (repPos = 0; repPos < repLen; repPos++) {
314 UChar repChr = replacement.charAt(repPos);
315 if (repChr == 0x27 /* ASCII-range single quote */) {
316 inQuoted = !inQuoted;
317 } else if (!inQuoted) {
318 if (repChr==LOW_H || repChr==CAP_H || repChr==CAP_K || repChr==LOW_K) { // hHKk, hour
319 timeNonHourStart = repPos + 1;
320 } else if (timeNonHourStart < 0 && (repChr==LOW_M || repChr==LOW_S)) { // 'm' or 's' and we did not have hour
321 timeNonHourStart = repPos;
322 }
323 if (!u_isWhitespace(repChr) && timeNonHourStart >= 0 && repChr!=LOW_A) { // NonHour portion should not include 'a'
324 timeNonHourLimit = repPos + 1;
325 }
326 }
327 }
328 // If we found minutes/seconds/milliseconds in replacement, restore that part to original.
329 if (timeNonHourStart >= 0 && timeNonHourLimit > timeNonHourStart) {
330 replacement.replaceBetween(timeNonHourStart, timeNonHourLimit, nonHour);
331 }
332 }
333 patternString.replaceBetween(timePatStart, timePatLimit, replacement);
334 return replacement.length() - (timePatLimit - timePatStart); // positive if replacement is longer
335}
336
337/*
338 * uadatpg_remapPatternWithOptionsLoc
339 *
340 * Thee general idea is:
341 * 1. Scan the pattern for one or more time subpatterns
342 * 2. For each time subpattern, if the hour pattern characters don't match the
343 * time cycle that we want to force to, then:
344 * a) Save the nonHour portion of the subpattern (from just after hours to end
345 * of minutes/seconds/ milliseconds)
346 * b) Turn the pattern characters in that subpattern into a skeleton, but with
347 * the hour pattern characters switched to the desired time cycle
348 * c) Use that skeleton to get the locale's corresponding replacement pattern
349 * for the desired time cycle (with all desired elements - min, sec, etc.)
350 * d) In that replacement pattern, find the new nonHour portion, and restore
351 * that to the original nonHour portion
352 * e) Finally, replace the original time subpattern with the adjusted
353 * replacement.
354 */
57a6839d
A
355U_CAPI int32_t U_EXPORT2
356uadatpg_remapPatternWithOptions(UDateTimePatternGenerator *dtpg,
357 const UChar *pattern, int32_t patternLength,
358 UDateTimePatternMatchOptions options,
359 UChar *newPattern, int32_t newPatternCapacity,
360 UErrorCode *pErrorCode) {
361 if (U_FAILURE(*pErrorCode)) {
362 return 0;
363 }
364 if ( pattern==NULL || ((newPattern==NULL)? newPatternCapacity!=0: newPatternCapacity<0) ) {
365 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
366 return 0;
367 }
368 UnicodeString patternString((patternLength < 0), pattern, patternLength);
369 UBool force12 = ((options & UADATPG_FORCE_HOUR_CYCLE_MASK) == UADATPG_FORCE_12_HOUR_CYCLE);
370 UBool force24 = ((options & UADATPG_FORCE_HOUR_CYCLE_MASK) == UADATPG_FORCE_24_HOUR_CYCLE);
371 if (force12 || force24) {
372 UBool inQuoted = FALSE;
373 UBool inTimePat = FALSE;
374 UBool needReplacement = FALSE;
375 int32_t timePatStart = 0;
376 int32_t timePatLimit = 0;
b331163b
A
377 int32_t timeNonHourStart = -1;
378 int32_t timeNonHourLimit = 0;
379 UnicodeString skeleton, otherCycSkeleton;
2ca993e8 380 UnicodeString timePatChars("abBhHKkmsSzZOvVXx", -1, US_INV); // all pattern chars for times
b331163b 381 int32_t numForcedH = 0;
57a6839d 382 int32_t patPos, patLen = patternString.length();
b331163b 383
57a6839d
A
384 for (patPos = 0; patPos < patLen; patPos++) {
385 UChar patChr = patternString.charAt(patPos);
b331163b 386 UChar otherCycPatChr = patChr;
57a6839d
A
387 if (patChr == 0x27 /* ASCII-range single quote */) {
388 inQuoted = !inQuoted;
389 } else if (!inQuoted) {
b331163b 390 if (timePatChars.indexOf(patChr) >= 0) {
57a6839d
A
391 // in a time pattern
392 if (!inTimePat) {
393 inTimePat = TRUE;
394 timePatStart = patPos;
b331163b 395 timeNonHourStart = -1;
57a6839d 396 skeleton.remove();
b331163b
A
397 otherCycSkeleton.remove();
398 numForcedH = 0;
57a6839d 399 }
b331163b
A
400 if (patChr==LOW_H || patChr==CAP_K) { // hK, hour, 12-hour cycle
401 if (force24) {
402 otherCycPatChr = CAP_H; // force to H
57a6839d 403 needReplacement = TRUE;
b331163b
A
404 timeNonHourStart = patPos + 1;
405 // If we are switching from a 12-hour cycle to a 24-hour cycle
406 // and the pattern for 12-hour cycle was zero-padded to 2 digits,
407 // make sure the new pattern for 24-hour cycle is also padded to
408 // 2 digits regardless of locale default, to match the
409 // expectations of the pattern provider. However we don't need
410 // to do this going the other direction (from 24- to 12-hour
411 // cycles, don't require that the 12-hour cycle has zero padding
412 // just because the 24-hour cycle did; the 12-hour cycle will
413 // add other elements such as a, so there wil be a length change
414 // anyway).
415 numForcedH++;
57a6839d 416 }
b331163b
A
417 } else if (patChr==CAP_H || patChr==LOW_K) { // Hk, hour, 24-hour cycle
418 if (force12) {
419 otherCycPatChr = LOW_H; // force to h
57a6839d 420 needReplacement = TRUE;
b331163b 421 timeNonHourStart = patPos + 1;
57a6839d 422 }
b331163b
A
423 } else if (timeNonHourStart < 0 && (patChr==LOW_M || patChr==LOW_S)) { // 'm' or 's' and we did not have hour
424 timeNonHourStart = patPos;
57a6839d
A
425 }
426 skeleton.append(patChr);
b331163b 427 otherCycSkeleton.append(otherCycPatChr);
57a6839d
A
428 } else if ((patChr >= 0x41 && patChr <= 0x5A) || (patChr >= 0x61 && patChr <= 0x7A)) {
429 // a non-time pattern character, forces end of any time pattern
430 if (inTimePat) {
431 inTimePat = FALSE;
432 if (needReplacement) {
433 needReplacement = FALSE;
434 // do replacement
b331163b
A
435 int32_t posAdjust = _doReplaceAndReturnAdj(dtpg, options, numForcedH >= 2, patternString, skeleton, otherCycSkeleton,
436 timePatStart, timePatLimit, timeNonHourStart, timeNonHourLimit, pErrorCode);
57a6839d
A
437 patLen += posAdjust;
438 patPos += posAdjust;
439 }
440 }
441 }
b331163b
A
442 if (inTimePat && !u_isWhitespace(patChr)) {
443 timePatLimit = patPos + 1;
2ca993e8 444 if (timeNonHourStart >= 0 && patChr!=LOW_A && patChr!=LOW_B && patChr!=CAP_B) { // NonHour portion should not include 'a','b','B'
b331163b
A
445 timeNonHourLimit = timePatLimit;
446 }
447 }
57a6839d
A
448 }
449 }
450 // end of string
b331163b 451 if (needReplacement) {
57a6839d 452 // do replacement
b331163b
A
453 _doReplaceAndReturnAdj(dtpg, options, numForcedH >= 2, patternString, skeleton, otherCycSkeleton,
454 timePatStart, timePatLimit, timeNonHourStart, timeNonHourLimit, pErrorCode);
57a6839d
A
455 }
456 }
457 return patternString.extract(newPattern, newPatternCapacity, *pErrorCode);
458}
459
46f4442e 460#endif