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