1/*
2*******************************************************************************
3*   Copyright (C) 1996-2014, International Business Machines
4*   Corporation and others.  All Rights Reserved.
5*******************************************************************************
6*/
7
8#include "unicode/utypes.h"
9
10#if !UCONFIG_NO_FORMATTING
11
12#include "unicode/udat.h"
13
14#include "unicode/uloc.h"
15#include "unicode/datefmt.h"
16#include "unicode/timezone.h"
17#include "unicode/smpdtfmt.h"
18#include "unicode/fieldpos.h"
19#include "unicode/parsepos.h"
20#include "unicode/calendar.h"
21#include "unicode/numfmt.h"
22#include "unicode/dtfmtsym.h"
23#include "unicode/ustring.h"
24#include "unicode/udisplaycontext.h"
25#include "cpputils.h"
26#include "reldtfmt.h"
27#include "umutex.h"
28
29U_NAMESPACE_USE
30
31/**
32 * Verify that fmt is a SimpleDateFormat. Invalid error if not.
33 * @param fmt the UDateFormat, definitely a DateFormat, maybe something else
34 * @param status error code, will be set to failure if there is a familure or the fmt is NULL.
35 */
36static void verifyIsSimpleDateFormat(const UDateFormat* fmt, UErrorCode *status) {
37   if(U_SUCCESS(*status) &&
38       dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))==NULL) {
39       *status = U_ILLEGAL_ARGUMENT_ERROR;
40   }
41}
42
43// This mirrors the correspondence between the
44// SimpleDateFormat::fgPatternIndexToDateFormatField and
45// SimpleDateFormat::fgPatternIndexToCalendarField arrays.
46static UCalendarDateFields gDateFieldMapping[] = {
47    UCAL_ERA,                  // UDAT_ERA_FIELD = 0
48    UCAL_YEAR,                 // UDAT_YEAR_FIELD = 1
49    UCAL_MONTH,                // UDAT_MONTH_FIELD = 2
50    UCAL_DATE,                 // UDAT_DATE_FIELD = 3
51    UCAL_HOUR_OF_DAY,          // UDAT_HOUR_OF_DAY1_FIELD = 4
52    UCAL_HOUR_OF_DAY,          // UDAT_HOUR_OF_DAY0_FIELD = 5
53    UCAL_MINUTE,               // UDAT_MINUTE_FIELD = 6
54    UCAL_SECOND,               // UDAT_SECOND_FIELD = 7
55    UCAL_MILLISECOND,          // UDAT_FRACTIONAL_SECOND_FIELD = 8
56    UCAL_DAY_OF_WEEK,          // UDAT_DAY_OF_WEEK_FIELD = 9
57    UCAL_DAY_OF_YEAR,          // UDAT_DAY_OF_YEAR_FIELD = 10
58    UCAL_DAY_OF_WEEK_IN_MONTH, // UDAT_DAY_OF_WEEK_IN_MONTH_FIELD = 11
59    UCAL_WEEK_OF_YEAR,         // UDAT_WEEK_OF_YEAR_FIELD = 12
60    UCAL_WEEK_OF_MONTH,        // UDAT_WEEK_OF_MONTH_FIELD = 13
61    UCAL_AM_PM,                // UDAT_AM_PM_FIELD = 14
62    UCAL_HOUR,                 // UDAT_HOUR1_FIELD = 15
63    UCAL_HOUR,                 // UDAT_HOUR0_FIELD = 16
64    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_FIELD = 17
65    UCAL_YEAR_WOY,             // UDAT_YEAR_WOY_FIELD = 18
66    UCAL_DOW_LOCAL,            // UDAT_DOW_LOCAL_FIELD = 19
67    UCAL_EXTENDED_YEAR,        // UDAT_EXTENDED_YEAR_FIELD = 20
68    UCAL_JULIAN_DAY,           // UDAT_JULIAN_DAY_FIELD = 21
69    UCAL_MILLISECONDS_IN_DAY,  // UDAT_MILLISECONDS_IN_DAY_FIELD = 22
70    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_RFC_FIELD = 23 (also UCAL_DST_OFFSET)
71    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_GENERIC_FIELD = 24 (also UCAL_DST_OFFSET)
72    UCAL_DOW_LOCAL,            // UDAT_STANDALONE_DAY_FIELD = 25
73    UCAL_MONTH,                // UDAT_STANDALONE_MONTH_FIELD = 26
74    UCAL_MONTH,                // UDAT_QUARTER_FIELD = 27
75    UCAL_MONTH,                // UDAT_STANDALONE_QUARTER_FIELD = 28
76    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_SPECIAL_FIELD = 29 (also UCAL_DST_OFFSET)
77    UCAL_YEAR,                 // UDAT_YEAR_NAME_FIELD = 30
78    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD = 31 (also UCAL_DST_OFFSET)
79    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_ISO_FIELD = 32 (also UCAL_DST_OFFSET)
80    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_ISO_LOCAL_FIELD = 33 (also UCAL_DST_OFFSET)
81    UCAL_EXTENDED_YEAR,        // UDAT_RELATED_YEAR_FIELD = 34 (not an exact match)
82    UCAL_FIELD_COUNT,          // UDAT_FIELD_COUNT = 35
83    // UCAL_IS_LEAP_MONTH is not the target of a mapping
84};
85
86U_CAPI UCalendarDateFields U_EXPORT2
87udat_toCalendarDateField(UDateFormatField field) {
88  return gDateFieldMapping[field];
89}
90
91/* For now- one opener. */
92static UDateFormatOpener gOpener = NULL;
93
94U_INTERNAL void U_EXPORT2
95udat_registerOpener(UDateFormatOpener opener, UErrorCode *status)
96{
97  if(U_FAILURE(*status)) return;
98  umtx_lock(NULL);
99  if(gOpener==NULL) {
100    gOpener = opener;
101  } else {
102    *status = U_ILLEGAL_ARGUMENT_ERROR;
103  }
104  umtx_unlock(NULL);
105}
106
107U_INTERNAL UDateFormatOpener U_EXPORT2
108udat_unregisterOpener(UDateFormatOpener opener, UErrorCode *status)
109{
110  if(U_FAILURE(*status)) return NULL;
111  UDateFormatOpener oldOpener = NULL;
112  umtx_lock(NULL);
113  if(gOpener==NULL || gOpener!=opener) {
114    *status = U_ILLEGAL_ARGUMENT_ERROR;
115  } else {
116    oldOpener=gOpener;
117    gOpener=NULL;
118  }
119  umtx_unlock(NULL);
120  return oldOpener;
121}
122
123
124
125U_CAPI UDateFormat* U_EXPORT2
126udat_open(UDateFormatStyle  timeStyle,
127          UDateFormatStyle  dateStyle,
128          const char        *locale,
129          const UChar       *tzID,
130          int32_t           tzIDLength,
131          const UChar       *pattern,
132          int32_t           patternLength,
133          UErrorCode        *status)
134{
135    DateFormat *fmt;
136    if(U_FAILURE(*status)) {
137        return 0;
138    }
139    if(gOpener!=NULL) { // if it's registered
140      fmt = (DateFormat*) (*gOpener)(timeStyle,dateStyle,locale,tzID,tzIDLength,pattern,patternLength,status);
141      if(fmt!=NULL) {
142        return (UDateFormat*)fmt;
143      } // else fall through.
144    }
145    if(timeStyle != UDAT_PATTERN) {
146        if(locale == 0) {
147            fmt = DateFormat::createDateTimeInstance((DateFormat::EStyle)dateStyle,
148                (DateFormat::EStyle)timeStyle);
149        }
150        else {
151            fmt = DateFormat::createDateTimeInstance((DateFormat::EStyle)dateStyle,
152                (DateFormat::EStyle)timeStyle,
153                Locale(locale));
154        }
155    }
156    else {
157        UnicodeString pat((UBool)(patternLength == -1), pattern, patternLength);
158
159        if(locale == 0) {
160            fmt = new SimpleDateFormat(pat, *status);
161        }
162        else {
163            fmt = new SimpleDateFormat(pat, Locale(locale), *status);
164        }
165    }
166
167    if(fmt == 0) {
168        *status = U_MEMORY_ALLOCATION_ERROR;
169        return 0;
170    }
171
172    if(tzID != 0) {
173        TimeZone *zone = TimeZone::createTimeZone(UnicodeString((UBool)(tzIDLength == -1), tzID, tzIDLength));
174        if(zone == 0) {
175            *status = U_MEMORY_ALLOCATION_ERROR;
176            delete fmt;
177            return 0;
178        }
179        fmt->adoptTimeZone(zone);
180    }
181
182    return (UDateFormat*)fmt;
183}
184
185
186U_CAPI void U_EXPORT2
187udat_close(UDateFormat* format)
188{
189    delete (DateFormat*)format;
190}
191
192U_CAPI UDateFormat* U_EXPORT2
193udat_clone(const UDateFormat *fmt,
194       UErrorCode *status)
195{
196    if(U_FAILURE(*status)) return 0;
197
198    Format *res = ((DateFormat*)fmt)->clone();
199
200    if(res == 0) {
201        *status = U_MEMORY_ALLOCATION_ERROR;
202        return 0;
203    }
204
205    return (UDateFormat*) res;
206}
207
208U_CAPI int32_t U_EXPORT2
209udat_format(    const    UDateFormat*    format,
210        UDate           dateToFormat,
211        UChar*          result,
212        int32_t         resultLength,
213        UFieldPosition* position,
214        UErrorCode*     status)
215{
216    if(U_FAILURE(*status)) return -1;
217
218    UnicodeString res;
219    if(!(result==NULL && resultLength==0)) {
220        // NULL destination for pure preflighting: empty dummy string
221        // otherwise, alias the destination buffer
222        res.setTo(result, 0, resultLength);
223    }
224
225    FieldPosition fp;
226
227    if(position != 0)
228        fp.setField(position->field);
229
230    ((DateFormat*)format)->format(dateToFormat, res, fp);
231
232    if(position != 0) {
233        position->beginIndex = fp.getBeginIndex();
234        position->endIndex = fp.getEndIndex();
235    }
236
237    return res.extract(result, resultLength, *status);
238}
239
240U_CAPI UDate U_EXPORT2
241udat_parse(    const    UDateFormat*        format,
242        const    UChar*          text,
243        int32_t         textLength,
244        int32_t         *parsePos,
245        UErrorCode      *status)
246{
247    if(U_FAILURE(*status)) return (UDate)0;
248
249    const UnicodeString src((UBool)(textLength == -1), text, textLength);
250    ParsePosition pp;
251    int32_t stackParsePos = 0;
252    UDate res;
253
254    if(parsePos == NULL) {
255        parsePos = &stackParsePos;
256    }
257
258    pp.setIndex(*parsePos);
259
260    res = ((DateFormat*)format)->parse(src, pp);
261
262    if(pp.getErrorIndex() == -1)
263        *parsePos = pp.getIndex();
264    else {
265        *parsePos = pp.getErrorIndex();
266        *status = U_PARSE_ERROR;
267    }
268
269    return res;
270}
271
272U_CAPI void U_EXPORT2
273udat_parseCalendar(const    UDateFormat*    format,
274                            UCalendar*      calendar,
275                   const    UChar*          text,
276                            int32_t         textLength,
277                            int32_t         *parsePos,
278                            UErrorCode      *status)
279{
280    if(U_FAILURE(*status)) return;
281
282    const UnicodeString src((UBool)(textLength == -1), text, textLength);
283    ParsePosition pp;
284
285    if(parsePos != 0)
286        pp.setIndex(*parsePos);
287
288    ((DateFormat*)format)->parse(src, *(Calendar*)calendar, pp);
289
290    if(parsePos != 0) {
291        if(pp.getErrorIndex() == -1)
292            *parsePos = pp.getIndex();
293        else {
294            *parsePos = pp.getErrorIndex();
295            *status = U_PARSE_ERROR;
296        }
297    }
298}
299
300U_CAPI UBool U_EXPORT2
301udat_isLenient(const UDateFormat* fmt)
302{
303    return ((DateFormat*)fmt)->isLenient();
304}
305
306U_CAPI void U_EXPORT2
307udat_setLenient(    UDateFormat*    fmt,
308            UBool          isLenient)
309{
310    ((DateFormat*)fmt)->setLenient(isLenient);
311}
312
313U_CAPI const UCalendar* U_EXPORT2
314udat_getCalendar(const UDateFormat* fmt)
315{
316    return (const UCalendar*) ((DateFormat*)fmt)->getCalendar();
317}
318
319U_CAPI void U_EXPORT2
320udat_setCalendar(UDateFormat*    fmt,
321                 const   UCalendar*      calendarToSet)
322{
323    ((DateFormat*)fmt)->setCalendar(*((Calendar*)calendarToSet));
324}
325
326U_CAPI const UNumberFormat* U_EXPORT2
327udat_getNumberFormat(const UDateFormat* fmt)
328{
329    return (const UNumberFormat*) ((DateFormat*)fmt)->getNumberFormat();
330}
331
332U_CAPI void U_EXPORT2
333udat_setNumberFormat(UDateFormat*    fmt,
334                     const   UNumberFormat*  numberFormatToSet)
335{
336    ((DateFormat*)fmt)->setNumberFormat(*((NumberFormat*)numberFormatToSet));
337}
338
339U_CAPI const char* U_EXPORT2
340udat_getAvailable(int32_t index)
341{
342    return uloc_getAvailable(index);
343}
344
345U_CAPI int32_t U_EXPORT2
346udat_countAvailable()
347{
348    return uloc_countAvailable();
349}
350
351U_CAPI UDate U_EXPORT2
352udat_get2DigitYearStart(    const   UDateFormat     *fmt,
353                        UErrorCode      *status)
354{
355    verifyIsSimpleDateFormat(fmt, status);
356    if(U_FAILURE(*status)) return (UDate)0;
357    return ((SimpleDateFormat*)fmt)->get2DigitYearStart(*status);
358}
359
360U_CAPI void U_EXPORT2
361udat_set2DigitYearStart(    UDateFormat     *fmt,
362                        UDate           d,
363                        UErrorCode      *status)
364{
365    verifyIsSimpleDateFormat(fmt, status);
366    if(U_FAILURE(*status)) return;
367    ((SimpleDateFormat*)fmt)->set2DigitYearStart(d, *status);
368}
369
370U_CAPI int32_t U_EXPORT2
371udat_toPattern(    const   UDateFormat     *fmt,
372        UBool          localized,
373        UChar           *result,
374        int32_t         resultLength,
375        UErrorCode      *status)
376{
377    if(U_FAILURE(*status)) return -1;
378
379    UnicodeString res;
380    if(!(result==NULL && resultLength==0)) {
381        // NULL destination for pure preflighting: empty dummy string
382        // otherwise, alias the destination buffer
383        res.setTo(result, 0, resultLength);
384    }
385
386    const DateFormat *df=reinterpret_cast<const DateFormat *>(fmt);
387    const SimpleDateFormat *sdtfmt=dynamic_cast<const SimpleDateFormat *>(df);
388    const RelativeDateFormat *reldtfmt;
389    if (sdtfmt!=NULL) {
390        if(localized)
391            sdtfmt->toLocalizedPattern(res, *status);
392        else
393            sdtfmt->toPattern(res);
394    } else if (!localized && (reldtfmt=dynamic_cast<const RelativeDateFormat *>(df))!=NULL) {
395        reldtfmt->toPattern(res, *status);
396    } else {
397        *status = U_ILLEGAL_ARGUMENT_ERROR;
398        return -1;
399    }
400
401    return res.extract(result, resultLength, *status);
402}
403
404// TODO: should this take an UErrorCode?
405// A: Yes. Of course.
406U_CAPI void U_EXPORT2
407udat_applyPattern(  UDateFormat     *format,
408                    UBool          localized,
409                    const   UChar           *pattern,
410                    int32_t         patternLength)
411{
412    const UnicodeString pat((UBool)(patternLength == -1), pattern, patternLength);
413    UErrorCode status = U_ZERO_ERROR;
414
415    verifyIsSimpleDateFormat(format, &status);
416    if(U_FAILURE(status)) {
417        return;
418    }
419
420    if(localized)
421        ((SimpleDateFormat*)format)->applyLocalizedPattern(pat, status);
422    else
423        ((SimpleDateFormat*)format)->applyPattern(pat);
424}
425
426U_CAPI int32_t U_EXPORT2
427udat_getSymbols(const   UDateFormat     *fmt,
428                UDateFormatSymbolType   type,
429                int32_t                 index,
430                UChar                   *result,
431                int32_t                 resultLength,
432                UErrorCode              *status)
433{
434    const DateFormatSymbols *syms;
435    const SimpleDateFormat* sdtfmt;
436    const RelativeDateFormat* rdtfmt;
437    if ((sdtfmt = dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) {
438        syms = sdtfmt->getDateFormatSymbols();
439    } else if ((rdtfmt = dynamic_cast<const RelativeDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) {
440        syms = rdtfmt->getDateFormatSymbols();
441    } else {
442        return -1;
443    }
444    int32_t count;
445    const UnicodeString *res = NULL;
446
447    switch(type) {
448    case UDAT_ERAS:
449        res = syms->getEras(count);
450        break;
451
452    case UDAT_ERA_NAMES:
453        res = syms->getEraNames(count);
454        break;
455
456    case UDAT_MONTHS:
457        res = syms->getMonths(count);
458        break;
459
460    case UDAT_SHORT_MONTHS:
461        res = syms->getShortMonths(count);
462        break;
463
464    case UDAT_WEEKDAYS:
465        res = syms->getWeekdays(count);
466        break;
467
468    case UDAT_SHORT_WEEKDAYS:
469        res = syms->getShortWeekdays(count);
470        break;
471
472    case UDAT_AM_PMS:
473        res = syms->getAmPmStrings(count);
474        break;
475
476    case UDAT_LOCALIZED_CHARS:
477        {
478            UnicodeString res1;
479            if(!(result==NULL && resultLength==0)) {
480                // NULL destination for pure preflighting: empty dummy string
481                // otherwise, alias the destination buffer
482                res1.setTo(result, 0, resultLength);
483            }
484            syms->getLocalPatternChars(res1);
485            return res1.extract(result, resultLength, *status);
486        }
487
488    case UDAT_NARROW_MONTHS:
489        res = syms->getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
490        break;
491
492    case UDAT_SHORTER_WEEKDAYS:
493        res = syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::SHORT);
494        break;
495
496    case UDAT_NARROW_WEEKDAYS:
497        res = syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
498        break;
499
500    case UDAT_STANDALONE_MONTHS:
501        res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
502        break;
503
504    case UDAT_STANDALONE_SHORT_MONTHS:
505        res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
506        break;
507
508    case UDAT_STANDALONE_NARROW_MONTHS:
509        res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
510        break;
511
512    case UDAT_STANDALONE_WEEKDAYS:
513        res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
514        break;
515
516    case UDAT_STANDALONE_SHORT_WEEKDAYS:
517        res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
518        break;
519
520    case UDAT_STANDALONE_SHORTER_WEEKDAYS:
521        res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::SHORT);
522        break;
523
524    case UDAT_STANDALONE_NARROW_WEEKDAYS:
525        res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
526        break;
527
528    case UDAT_QUARTERS:
529        res = syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
530        break;
531
532    case UDAT_SHORT_QUARTERS:
533        res = syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
534        break;
535
536    case UDAT_STANDALONE_QUARTERS:
537        res = syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
538        break;
539
540    case UDAT_STANDALONE_SHORT_QUARTERS:
541        res = syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
542        break;
543
544    }
545
546    if(index < count) {
547        return res[index].extract(result, resultLength, *status);
548    }
549    return 0;
550}
551
552// TODO: also needs an errorCode.
553U_CAPI int32_t U_EXPORT2
554udat_countSymbols(    const    UDateFormat                *fmt,
555            UDateFormatSymbolType    type)
556{
557    const DateFormatSymbols *syms;
558    const SimpleDateFormat* sdtfmt;
559    const RelativeDateFormat* rdtfmt;
560    if ((sdtfmt = dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) {
561        syms = sdtfmt->getDateFormatSymbols();
562    } else if ((rdtfmt = dynamic_cast<const RelativeDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) {
563        syms = rdtfmt->getDateFormatSymbols();
564    } else {
565        return 0;
566    }
567    int32_t count = 0;
568
569    switch(type) {
570    case UDAT_ERAS:
571        syms->getEras(count);
572        break;
573
574    case UDAT_MONTHS:
575        syms->getMonths(count);
576        break;
577
578    case UDAT_SHORT_MONTHS:
579        syms->getShortMonths(count);
580        break;
581
582    case UDAT_WEEKDAYS:
583        syms->getWeekdays(count);
584        break;
585
586    case UDAT_SHORT_WEEKDAYS:
587        syms->getShortWeekdays(count);
588        break;
589
590    case UDAT_AM_PMS:
591        syms->getAmPmStrings(count);
592        break;
593
594    case UDAT_LOCALIZED_CHARS:
595        count = 1;
596        break;
597
598    case UDAT_ERA_NAMES:
599        syms->getEraNames(count);
600        break;
601
602    case UDAT_NARROW_MONTHS:
603        syms->getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
604        break;
605
606    case UDAT_SHORTER_WEEKDAYS:
607        syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::SHORT);
608        break;
609
610    case UDAT_NARROW_WEEKDAYS:
611        syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
612        break;
613
614    case UDAT_STANDALONE_MONTHS:
615        syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
616        break;
617
618    case UDAT_STANDALONE_SHORT_MONTHS:
619        syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
620        break;
621
622    case UDAT_STANDALONE_NARROW_MONTHS:
623        syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
624        break;
625
626    case UDAT_STANDALONE_WEEKDAYS:
627        syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
628        break;
629
630    case UDAT_STANDALONE_SHORT_WEEKDAYS:
631        syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
632        break;
633
634    case UDAT_STANDALONE_SHORTER_WEEKDAYS:
635        syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::SHORT);
636        break;
637
638    case UDAT_STANDALONE_NARROW_WEEKDAYS:
639        syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
640        break;
641
642    case UDAT_QUARTERS:
643        syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
644        break;
645
646    case UDAT_SHORT_QUARTERS:
647        syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
648        break;
649
650    case UDAT_STANDALONE_QUARTERS:
651        syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
652        break;
653
654    case UDAT_STANDALONE_SHORT_QUARTERS:
655        syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
656        break;
657
658    }
659
660    return count;
661}
662
663U_NAMESPACE_BEGIN
664
665/*
666 * This DateFormatSymbolsSingleSetter class is a friend of DateFormatSymbols
667 * solely for the purpose of avoiding to clone the array of strings
668 * just to modify one of them and then setting all of them back.
669 * For example, the old code looked like this:
670 *  case UDAT_MONTHS:
671 *    res = syms->getMonths(count);
672 *    array = new UnicodeString[count];
673 *    if(array == 0) {
674 *      *status = U_MEMORY_ALLOCATION_ERROR;
675 *      return;
676 *    }
677 *    uprv_arrayCopy(res, array, count);
678 *    if(index < count)
679 *      array[index] = val;
680 *    syms->setMonths(array, count);
681 *    break;
682 *
683 * Even worse, the old code actually cloned the entire DateFormatSymbols object,
684 * cloned one value array, changed one value, and then made the SimpleDateFormat
685 * replace its DateFormatSymbols object with the new one.
686 *
687 * markus 2002-oct-14
688 */
689class DateFormatSymbolsSingleSetter /* not : public UObject because all methods are static */ {
690public:
691    static void
692        setSymbol(UnicodeString *array, int32_t count, int32_t index,
693        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
694    {
695        if(array!=NULL) {
696            if(index>=count) {
697                errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
698            } else if(value==NULL) {
699                errorCode=U_ILLEGAL_ARGUMENT_ERROR;
700            } else {
701                array[index].setTo(value, valueLength);
702            }
703        }
704    }
705
706    static void
707        setEra(DateFormatSymbols *syms, int32_t index,
708        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
709    {
710        setSymbol(syms->fEras, syms->fErasCount, index, value, valueLength, errorCode);
711    }
712
713    static void
714        setEraName(DateFormatSymbols *syms, int32_t index,
715        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
716    {
717        setSymbol(syms->fEraNames, syms->fEraNamesCount, index, value, valueLength, errorCode);
718    }
719
720    static void
721        setMonth(DateFormatSymbols *syms, int32_t index,
722        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
723    {
724        setSymbol(syms->fMonths, syms->fMonthsCount, index, value, valueLength, errorCode);
725    }
726
727    static void
728        setShortMonth(DateFormatSymbols *syms, int32_t index,
729        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
730    {
731        setSymbol(syms->fShortMonths, syms->fShortMonthsCount, index, value, valueLength, errorCode);
732    }
733
734    static void
735        setNarrowMonth(DateFormatSymbols *syms, int32_t index,
736        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
737    {
738        setSymbol(syms->fNarrowMonths, syms->fNarrowMonthsCount, index, value, valueLength, errorCode);
739    }
740
741    static void
742        setStandaloneMonth(DateFormatSymbols *syms, int32_t index,
743        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
744    {
745        setSymbol(syms->fStandaloneMonths, syms->fStandaloneMonthsCount, index, value, valueLength, errorCode);
746    }
747
748    static void
749        setStandaloneShortMonth(DateFormatSymbols *syms, int32_t index,
750        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
751    {
752        setSymbol(syms->fStandaloneShortMonths, syms->fStandaloneShortMonthsCount, index, value, valueLength, errorCode);
753    }
754
755    static void
756        setStandaloneNarrowMonth(DateFormatSymbols *syms, int32_t index,
757        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
758    {
759        setSymbol(syms->fStandaloneNarrowMonths, syms->fStandaloneNarrowMonthsCount, index, value, valueLength, errorCode);
760    }
761
762    static void
763        setWeekday(DateFormatSymbols *syms, int32_t index,
764        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
765    {
766        setSymbol(syms->fWeekdays, syms->fWeekdaysCount, index, value, valueLength, errorCode);
767    }
768
769    static void
770        setShortWeekday(DateFormatSymbols *syms, int32_t index,
771        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
772    {
773        setSymbol(syms->fShortWeekdays, syms->fShortWeekdaysCount, index, value, valueLength, errorCode);
774    }
775
776    static void
777        setShorterWeekday(DateFormatSymbols *syms, int32_t index,
778        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
779    {
780        setSymbol(syms->fShorterWeekdays, syms->fShorterWeekdaysCount, index, value, valueLength, errorCode);
781    }
782
783    static void
784        setNarrowWeekday(DateFormatSymbols *syms, int32_t index,
785        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
786    {
787        setSymbol(syms->fNarrowWeekdays, syms->fNarrowWeekdaysCount, index, value, valueLength, errorCode);
788    }
789
790    static void
791        setStandaloneWeekday(DateFormatSymbols *syms, int32_t index,
792        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
793    {
794        setSymbol(syms->fStandaloneWeekdays, syms->fStandaloneWeekdaysCount, index, value, valueLength, errorCode);
795    }
796
797    static void
798        setStandaloneShortWeekday(DateFormatSymbols *syms, int32_t index,
799        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
800    {
801        setSymbol(syms->fStandaloneShortWeekdays, syms->fStandaloneShortWeekdaysCount, index, value, valueLength, errorCode);
802    }
803
804    static void
805        setStandaloneShorterWeekday(DateFormatSymbols *syms, int32_t index,
806        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
807    {
808        setSymbol(syms->fStandaloneShorterWeekdays, syms->fStandaloneShorterWeekdaysCount, index, value, valueLength, errorCode);
809    }
810
811    static void
812        setStandaloneNarrowWeekday(DateFormatSymbols *syms, int32_t index,
813        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
814    {
815        setSymbol(syms->fStandaloneNarrowWeekdays, syms->fStandaloneNarrowWeekdaysCount, index, value, valueLength, errorCode);
816    }
817
818    static void
819        setQuarter(DateFormatSymbols *syms, int32_t index,
820        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
821    {
822        setSymbol(syms->fQuarters, syms->fQuartersCount, index, value, valueLength, errorCode);
823    }
824
825    static void
826        setShortQuarter(DateFormatSymbols *syms, int32_t index,
827        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
828    {
829        setSymbol(syms->fShortQuarters, syms->fShortQuartersCount, index, value, valueLength, errorCode);
830    }
831
832    static void
833        setStandaloneQuarter(DateFormatSymbols *syms, int32_t index,
834        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
835    {
836        setSymbol(syms->fStandaloneQuarters, syms->fStandaloneQuartersCount, index, value, valueLength, errorCode);
837    }
838
839    static void
840        setStandaloneShortQuarter(DateFormatSymbols *syms, int32_t index,
841        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
842    {
843        setSymbol(syms->fStandaloneShortQuarters, syms->fStandaloneShortQuartersCount, index, value, valueLength, errorCode);
844    }
845
846    static void
847        setAmPm(DateFormatSymbols *syms, int32_t index,
848        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
849    {
850        setSymbol(syms->fAmPms, syms->fAmPmsCount, index, value, valueLength, errorCode);
851    }
852
853    static void
854        setLocalPatternChars(DateFormatSymbols *syms,
855        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
856    {
857        setSymbol(&syms->fLocalPatternChars, 1, 0, value, valueLength, errorCode);
858    }
859};
860
861U_NAMESPACE_END
862
863U_CAPI void U_EXPORT2
864udat_setSymbols(    UDateFormat             *format,
865            UDateFormatSymbolType   type,
866            int32_t                 index,
867            UChar                   *value,
868            int32_t                 valueLength,
869            UErrorCode              *status)
870{
871    verifyIsSimpleDateFormat(format, status);
872    if(U_FAILURE(*status)) return;
873
874    DateFormatSymbols *syms = (DateFormatSymbols *)((SimpleDateFormat *)format)->getDateFormatSymbols();
875
876    switch(type) {
877    case UDAT_ERAS:
878        DateFormatSymbolsSingleSetter::setEra(syms, index, value, valueLength, *status);
879        break;
880
881    case UDAT_ERA_NAMES:
882        DateFormatSymbolsSingleSetter::setEraName(syms, index, value, valueLength, *status);
883        break;
884
885    case UDAT_MONTHS:
886        DateFormatSymbolsSingleSetter::setMonth(syms, index, value, valueLength, *status);
887        break;
888
889    case UDAT_SHORT_MONTHS:
890        DateFormatSymbolsSingleSetter::setShortMonth(syms, index, value, valueLength, *status);
891        break;
892
893    case UDAT_NARROW_MONTHS:
894        DateFormatSymbolsSingleSetter::setNarrowMonth(syms, index, value, valueLength, *status);
895        break;
896
897    case UDAT_STANDALONE_MONTHS:
898        DateFormatSymbolsSingleSetter::setStandaloneMonth(syms, index, value, valueLength, *status);
899        break;
900
901    case UDAT_STANDALONE_SHORT_MONTHS:
902        DateFormatSymbolsSingleSetter::setStandaloneShortMonth(syms, index, value, valueLength, *status);
903        break;
904
905    case UDAT_STANDALONE_NARROW_MONTHS:
906        DateFormatSymbolsSingleSetter::setStandaloneNarrowMonth(syms, index, value, valueLength, *status);
907        break;
908
909    case UDAT_WEEKDAYS:
910        DateFormatSymbolsSingleSetter::setWeekday(syms, index, value, valueLength, *status);
911        break;
912
913    case UDAT_SHORT_WEEKDAYS:
914        DateFormatSymbolsSingleSetter::setShortWeekday(syms, index, value, valueLength, *status);
915        break;
916
917    case UDAT_SHORTER_WEEKDAYS:
918        DateFormatSymbolsSingleSetter::setShorterWeekday(syms, index, value, valueLength, *status);
919        break;
920
921    case UDAT_NARROW_WEEKDAYS:
922        DateFormatSymbolsSingleSetter::setNarrowWeekday(syms, index, value, valueLength, *status);
923        break;
924
925    case UDAT_STANDALONE_WEEKDAYS:
926        DateFormatSymbolsSingleSetter::setStandaloneWeekday(syms, index, value, valueLength, *status);
927        break;
928
929    case UDAT_STANDALONE_SHORT_WEEKDAYS:
930        DateFormatSymbolsSingleSetter::setStandaloneShortWeekday(syms, index, value, valueLength, *status);
931        break;
932
933    case UDAT_STANDALONE_SHORTER_WEEKDAYS:
934        DateFormatSymbolsSingleSetter::setStandaloneShorterWeekday(syms, index, value, valueLength, *status);
935        break;
936
937    case UDAT_STANDALONE_NARROW_WEEKDAYS:
938        DateFormatSymbolsSingleSetter::setStandaloneNarrowWeekday(syms, index, value, valueLength, *status);
939        break;
940
941    case UDAT_QUARTERS:
942        DateFormatSymbolsSingleSetter::setQuarter(syms, index, value, valueLength, *status);
943        break;
944
945    case UDAT_SHORT_QUARTERS:
946        DateFormatSymbolsSingleSetter::setShortQuarter(syms, index, value, valueLength, *status);
947        break;
948
949    case UDAT_STANDALONE_QUARTERS:
950        DateFormatSymbolsSingleSetter::setStandaloneQuarter(syms, index, value, valueLength, *status);
951        break;
952
953    case UDAT_STANDALONE_SHORT_QUARTERS:
954        DateFormatSymbolsSingleSetter::setStandaloneShortQuarter(syms, index, value, valueLength, *status);
955        break;
956
957    case UDAT_AM_PMS:
958        DateFormatSymbolsSingleSetter::setAmPm(syms, index, value, valueLength, *status);
959        break;
960
961    case UDAT_LOCALIZED_CHARS:
962        DateFormatSymbolsSingleSetter::setLocalPatternChars(syms, value, valueLength, *status);
963        break;
964
965    default:
966        *status = U_UNSUPPORTED_ERROR;
967        break;
968
969    }
970}
971
972U_CAPI const char* U_EXPORT2
973udat_getLocaleByType(const UDateFormat *fmt,
974                     ULocDataLocaleType type,
975                     UErrorCode* status)
976{
977    if (fmt == NULL) {
978        if (U_SUCCESS(*status)) {
979            *status = U_ILLEGAL_ARGUMENT_ERROR;
980        }
981        return NULL;
982    }
983    return ((Format*)fmt)->getLocaleID(type, *status);
984}
985
986U_CAPI void U_EXPORT2
987udat_setContext(UDateFormat* fmt, UDisplayContext value, UErrorCode* status)
988{
989    if (U_FAILURE(*status)) {
990        return;
991    }
992    ((DateFormat*)fmt)->setContext(value, *status);
993    return;
994}
995
996U_CAPI UDisplayContext U_EXPORT2
997udat_getContext(const UDateFormat* fmt, UDisplayContextType type, UErrorCode* status)
998{
999    if (U_FAILURE(*status)) {
1000        return (UDisplayContext)0;
1001    }
1002    return ((const DateFormat*)fmt)->getContext(type, *status);
1003}
1004
1005
1006/**
1007 * Verify that fmt is a RelativeDateFormat. Invalid error if not.
1008 * @param fmt the UDateFormat, definitely a DateFormat, maybe something else
1009 * @param status error code, will be set to failure if there is a familure or the fmt is NULL.
1010 */
1011static void verifyIsRelativeDateFormat(const UDateFormat* fmt, UErrorCode *status) {
1012   if(U_SUCCESS(*status) &&
1013       dynamic_cast<const RelativeDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))==NULL) {
1014       *status = U_ILLEGAL_ARGUMENT_ERROR;
1015   }
1016}
1017
1018
1019U_CAPI int32_t U_EXPORT2
1020udat_toPatternRelativeDate(const UDateFormat *fmt,
1021                           UChar             *result,
1022                           int32_t           resultLength,
1023                           UErrorCode        *status)
1024{
1025    verifyIsRelativeDateFormat(fmt, status);
1026    if(U_FAILURE(*status)) return -1;
1027
1028    UnicodeString datePattern;
1029    if(!(result==NULL && resultLength==0)) {
1030        // NULL destination for pure preflighting: empty dummy string
1031        // otherwise, alias the destination buffer
1032        datePattern.setTo(result, 0, resultLength);
1033    }
1034    ((RelativeDateFormat*)fmt)->toPatternDate(datePattern, *status);
1035    return datePattern.extract(result, resultLength, *status);
1036}
1037
1038U_CAPI int32_t U_EXPORT2
1039udat_toPatternRelativeTime(const UDateFormat *fmt,
1040                           UChar             *result,
1041                           int32_t           resultLength,
1042                           UErrorCode        *status)
1043{
1044    verifyIsRelativeDateFormat(fmt, status);
1045    if(U_FAILURE(*status)) return -1;
1046
1047    UnicodeString timePattern;
1048    if(!(result==NULL && resultLength==0)) {
1049        // NULL destination for pure preflighting: empty dummy string
1050        // otherwise, alias the destination buffer
1051        timePattern.setTo(result, 0, resultLength);
1052    }
1053    ((RelativeDateFormat*)fmt)->toPatternTime(timePattern, *status);
1054    return timePattern.extract(result, resultLength, *status);
1055}
1056
1057U_CAPI void U_EXPORT2
1058udat_applyPatternRelative(UDateFormat *format,
1059                          const UChar *datePattern,
1060                          int32_t     datePatternLength,
1061                          const UChar *timePattern,
1062                          int32_t     timePatternLength,
1063                          UErrorCode  *status)
1064{
1065    verifyIsRelativeDateFormat(format, status);
1066    if(U_FAILURE(*status)) return;
1067    const UnicodeString datePat((UBool)(datePatternLength == -1), datePattern, datePatternLength);
1068    const UnicodeString timePat((UBool)(timePatternLength == -1), timePattern, timePatternLength);
1069    ((RelativeDateFormat*)format)->applyPatterns(datePat, timePat, *status);
1070}
1071
1072#endif /* #if !UCONFIG_NO_FORMATTING */
1073