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