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