ae5387273e3d38e80297701284e23143e0677bc0
[platform/framework/web/crosswalk.git] / src / third_party / icu / source / i18n / choicfmt.cpp
1 /*
2 *******************************************************************************
3 * Copyright (C) 1997-2009, International Business Machines Corporation and    *
4 * others. All Rights Reserved.                                                *
5 *******************************************************************************
6 *
7 * File CHOICFMT.CPP
8 *
9 * Modification History:
10 *
11 *   Date        Name        Description
12 *   02/19/97    aliu        Converted from java.
13 *   03/20/97    helena      Finished first cut of implementation and got rid 
14 *                           of nextDouble/previousDouble and replaced with
15 *                           boolean array.
16 *   4/10/97     aliu        Clean up.  Modified to work on AIX.
17 *   06/04/97    helena      Fixed applyPattern(), toPattern() and not to include 
18 *                           wchar.h.
19 *   07/09/97    helena      Made ParsePosition into a class.
20 *   08/06/97    nos         removed overloaded constructor, fixed 'format(array)'
21 *   07/22/98    stephen     JDK 1.2 Sync - removed UBool array (doubleFlags)
22 *   02/22/99    stephen     Removed character literals for EBCDIC safety
23 ********************************************************************************
24 */
25
26 #include "unicode/utypes.h"
27
28 #if !UCONFIG_NO_FORMATTING
29
30 #include "unicode/choicfmt.h"
31 #include "unicode/numfmt.h"
32 #include "unicode/locid.h"
33 #include "cpputils.h"
34 #include "cstring.h"
35 #include "putilimp.h"
36 #include <stdio.h>
37 #include <float.h>
38
39 // *****************************************************************************
40 // class ChoiceFormat
41 // *****************************************************************************
42
43 U_NAMESPACE_BEGIN
44
45 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ChoiceFormat)
46
47 // Special characters used by ChoiceFormat.  There are two characters
48 // used interchangeably to indicate <=.  Either is parsed, but only
49 // LESS_EQUAL is generated by toPattern().
50 #define SINGLE_QUOTE ((UChar)0x0027)   /*'*/
51 #define LESS_THAN    ((UChar)0x003C)   /*<*/
52 #define LESS_EQUAL   ((UChar)0x0023)   /*#*/
53 #define LESS_EQUAL2  ((UChar)0x2264)
54 #define VERTICAL_BAR ((UChar)0x007C)   /*|*/
55 #define MINUS        ((UChar)0x002D)   /*-*/
56
57 #ifdef INFINITY
58 #undef INFINITY
59 #endif
60 #define INFINITY     ((UChar)0x221E)
61
62 static const UChar gPositiveInfinity[] = {INFINITY, 0};
63 static const UChar gNegativeInfinity[] = {MINUS, INFINITY, 0};
64 #define POSITIVE_INF_STRLEN 1
65 #define NEGATIVE_INF_STRLEN 2
66
67 // -------------------------------------
68 // Creates a ChoiceFormat instance based on the pattern.
69
70 ChoiceFormat::ChoiceFormat(const UnicodeString& newPattern,
71                            UErrorCode& status)
72 : fChoiceLimits(0),
73   fClosures(0),
74   fChoiceFormats(0),
75   fCount(0)
76 {
77     applyPattern(newPattern, status);
78 }
79
80 // -------------------------------------
81 // Creates a ChoiceFormat instance with the limit array and 
82 // format strings for each limit.
83
84 ChoiceFormat::ChoiceFormat(const double* limits, 
85                            const UnicodeString* formats, 
86                            int32_t cnt )
87 : fChoiceLimits(0),
88   fClosures(0),
89   fChoiceFormats(0),
90   fCount(0)
91 {
92     setChoices(limits, formats, cnt );
93 }
94
95 // -------------------------------------
96
97 ChoiceFormat::ChoiceFormat(const double* limits, 
98                            const UBool* closures,
99                            const UnicodeString* formats, 
100                            int32_t cnt )
101 : fChoiceLimits(0),
102   fClosures(0),
103   fChoiceFormats(0),
104   fCount(0)
105 {
106     setChoices(limits, closures, formats, cnt );
107 }
108
109 // -------------------------------------
110 // copy constructor
111
112 ChoiceFormat::ChoiceFormat(const    ChoiceFormat&   that) 
113 : NumberFormat(that),
114   fChoiceLimits(0),
115   fClosures(0),
116   fChoiceFormats(0)
117 {
118     *this = that;
119 }
120
121 // -------------------------------------
122 // Private constructor that creates a 
123 // ChoiceFormat instance based on the 
124 // pattern and populates UParseError
125
126 ChoiceFormat::ChoiceFormat(const UnicodeString& newPattern,
127                            UParseError& parseError,
128                            UErrorCode& status)
129 : fChoiceLimits(0),
130   fClosures(0),
131   fChoiceFormats(0),
132   fCount(0)
133 {
134     applyPattern(newPattern,parseError, status);
135 }
136 // -------------------------------------
137
138 UBool
139 ChoiceFormat::operator==(const Format& that) const
140 {
141     if (this == &that) return TRUE;
142     if (!NumberFormat::operator==(that)) return FALSE;
143     ChoiceFormat& thatAlias = (ChoiceFormat&)that;
144     if (fCount != thatAlias.fCount) return FALSE;
145     // Checks the limits, the corresponding format string and LE or LT flags.
146     // LE means less than and equal to, LT means less than.
147     for (int32_t i = 0; i < fCount; i++) {
148         if ((fChoiceLimits[i] != thatAlias.fChoiceLimits[i]) ||
149             (fClosures[i] != thatAlias.fClosures[i]) ||
150             (fChoiceFormats[i] != thatAlias.fChoiceFormats[i]))
151             return FALSE;
152     }
153     return TRUE;
154 }
155
156 // -------------------------------------
157 // copy constructor
158
159 const ChoiceFormat&
160 ChoiceFormat::operator=(const   ChoiceFormat& that)
161 {
162     if (this != &that) {
163         NumberFormat::operator=(that);
164         fCount = that.fCount;
165         uprv_free(fChoiceLimits);
166         fChoiceLimits = NULL;
167         uprv_free(fClosures);
168         fClosures = NULL;
169         delete [] fChoiceFormats;
170         fChoiceFormats = NULL;
171
172         fChoiceLimits = (double*) uprv_malloc( sizeof(double) * fCount);
173         fClosures = (UBool*) uprv_malloc( sizeof(UBool) * fCount);
174         fChoiceFormats = new UnicodeString[fCount];
175         
176         // check for memory allocation error
177         if (!fChoiceLimits || !fClosures || !fChoiceFormats) {
178             if (fChoiceLimits) {
179                 uprv_free(fChoiceLimits);
180                 fChoiceLimits = NULL;
181             }
182             if (fClosures) {
183                 uprv_free(fClosures);
184                 fClosures = NULL;
185             }
186             if (fChoiceFormats) {
187                 delete[] fChoiceFormats;
188                 fChoiceFormats = NULL;
189             }
190         } else {
191             uprv_arrayCopy(that.fChoiceLimits, fChoiceLimits, fCount);
192             uprv_arrayCopy(that.fClosures, fClosures, fCount);
193             uprv_arrayCopy(that.fChoiceFormats, fChoiceFormats, fCount);
194         }
195     }
196     return *this;
197 }
198
199 // -------------------------------------
200
201 ChoiceFormat::~ChoiceFormat()
202 {
203     uprv_free(fChoiceLimits);
204     fChoiceLimits = NULL;
205     uprv_free(fClosures);
206     fClosures = NULL;
207     delete [] fChoiceFormats;
208     fChoiceFormats = NULL;
209     fCount = 0;
210 }
211
212 /**
213  * Convert a string to a double value
214  */
215 double
216 ChoiceFormat::stod(const UnicodeString& string)
217 {
218     char source[256];
219     char* end;
220
221     string.extract(0, string.length(), source, (int32_t)sizeof(source), US_INV);    /* invariant codepage */
222     return uprv_strtod(source,&end);
223 }
224
225 // -------------------------------------
226
227 /**
228  * Convert a double value to a string without the overhead of ICU.
229  */
230 UnicodeString&
231 ChoiceFormat::dtos(double value,
232                    UnicodeString& string)
233 {
234     /* Buffer to contain the digits and any extra formatting stuff. */
235     char temp[DBL_DIG + 16];
236     char *itrPtr = temp;
237     char *expPtr;
238
239     sprintf(temp, "%.*g", DBL_DIG, value);
240
241     /* Find and convert the decimal point.
242        Using setlocale on some machines will cause sprintf to use a comma for certain locales.
243     */
244     while (*itrPtr && (*itrPtr == '-' || isdigit(*itrPtr))) {
245         itrPtr++;
246     }
247     if (*itrPtr != 0 && *itrPtr != 'e') {
248         /* We reached something that looks like a decimal point.
249         In case someone used setlocale(), which changes the decimal point. */
250         *itrPtr = '.';
251         itrPtr++;
252     }
253     /* Search for the exponent */
254     while (*itrPtr && *itrPtr != 'e') {
255         itrPtr++;
256     }
257     if (*itrPtr == 'e') {
258         itrPtr++;
259         /* Verify the exponent sign */
260         if (*itrPtr == '+' || *itrPtr == '-') {
261             itrPtr++;
262         }
263         /* Remove leading zeros. You will see this on Windows machines. */
264         expPtr = itrPtr;
265         while (*itrPtr == '0') {
266             itrPtr++;
267         }
268         if (*itrPtr && expPtr != itrPtr) {
269             /* Shift the exponent without zeros. */
270             while (*itrPtr) {
271                 *(expPtr++)  = *(itrPtr++);
272             }
273             // NULL terminate
274             *expPtr = 0;
275         }
276     }
277
278     string = UnicodeString(temp, -1, US_INV);    /* invariant codepage */
279     return string;
280 }
281
282 // -------------------------------------
283 // calls the overloaded applyPattern method.
284
285 void
286 ChoiceFormat::applyPattern(const UnicodeString& pattern,
287                            UErrorCode& status)
288 {
289     UParseError parseError;
290     applyPattern(pattern, parseError, status);
291 }
292
293 // -------------------------------------
294 // Applies the pattern to this ChoiceFormat instance.
295
296 void
297 ChoiceFormat::applyPattern(const UnicodeString& pattern,
298                            UParseError& parseError,
299                            UErrorCode& status)
300 {
301     if (U_FAILURE(status)) 
302     {
303         return;
304     }
305
306     // Clear error struct
307     parseError.offset = -1;
308     parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
309
310     // Perform 2 passes.  The first computes the number of limits in
311     // this pattern (fCount), which is 1 more than the number of
312     // literal VERTICAL_BAR characters.
313     int32_t count = 1;
314     int32_t i;
315     for (i=0; i<pattern.length(); ++i) {
316         UChar c = pattern[i];
317         if (c == SINGLE_QUOTE) {
318             // Skip over the entire quote, including embedded
319             // contiguous pairs of SINGLE_QUOTE.
320             for (;;) {
321                 do {
322                     ++i;
323                 } while (i<pattern.length() &&
324                          pattern[i] != SINGLE_QUOTE);
325                 if ((i+1)<pattern.length() &&
326                     pattern[i+1] == SINGLE_QUOTE) {
327                     // SINGLE_QUOTE pair; skip over it
328                     ++i;
329                 } else {
330                     break;
331                 }
332             }
333         } else if (c == VERTICAL_BAR) {
334             ++count;
335         }
336     }
337
338     // Allocate the required storage.
339     double *newLimits = (double*) uprv_malloc( sizeof(double) * count);
340     /* test for NULL */
341     if (newLimits == 0) {
342         status = U_MEMORY_ALLOCATION_ERROR;
343         return;
344     }
345     UBool *newClosures = (UBool*) uprv_malloc( sizeof(UBool) * count);
346     /* test for NULL */
347     if (newClosures == 0) {
348         status = U_MEMORY_ALLOCATION_ERROR;
349         uprv_free(newLimits);
350         return;
351     }
352     UnicodeString *newFormats = new UnicodeString[count];
353     /* test for NULL */
354     if (newFormats == 0) {
355         status = U_MEMORY_ALLOCATION_ERROR;
356         uprv_free(newLimits);
357         uprv_free(newClosures);
358         return;
359     }
360
361     // Perform the second pass
362     int32_t k = 0; // index into newXxx[] arrays
363     UnicodeString buf; // scratch buffer
364     UBool inQuote = FALSE;
365     UBool inNumber = TRUE; // TRUE before < or #, FALSE after
366
367     for (i=0; i<pattern.length(); ++i) {
368         UChar c = pattern[i];
369         if (c == SINGLE_QUOTE) {
370             // Check for SINGLE_QUOTE pair indicating a literal quote
371             if ((i+1) < pattern.length() &&
372                 pattern[i+1] == SINGLE_QUOTE) {
373                 buf += SINGLE_QUOTE;
374                 ++i;
375             } else {
376                 inQuote = !inQuote;
377             }
378         } else if (inQuote) {
379             buf += c;
380         } else if (c == LESS_THAN || c == LESS_EQUAL || c == LESS_EQUAL2) {
381             if (!inNumber || buf.length() == 0) {
382                 goto error;
383             }
384             inNumber = FALSE;
385
386             double limit;
387             buf.trim();
388             if (!buf.compare(gPositiveInfinity, POSITIVE_INF_STRLEN)) {
389                 limit = uprv_getInfinity();
390             } else if (!buf.compare(gNegativeInfinity, NEGATIVE_INF_STRLEN)) {
391                 limit = -uprv_getInfinity();
392             } else {
393                 limit = stod(buf);
394             }
395
396             if (k == count) {
397                 // This shouldn't happen.  If it does, it means that
398                 // the count determined in the first pass did not
399                 // match the number of elements found in the second
400                 // pass.
401                 goto error;
402             }
403             newLimits[k] = limit;
404             newClosures[k] = (c == LESS_THAN);
405
406             if (k > 0 && limit <= newLimits[k-1]) {
407                 // Each limit must be strictly > than the previous
408                 // limit.  One exception: Two subsequent limits may be
409                 // == if the first closure is FALSE and the second
410                 // closure is TRUE.  This places the limit value in
411                 // the second interval.
412                 if (!(limit == newLimits[k-1] &&
413                       !newClosures[k-1] &&
414                       newClosures[k])) {
415                     goto error;
416                 }
417             }
418
419             buf.truncate(0);
420         } else if (c == VERTICAL_BAR) {
421             if (inNumber) {
422                 goto error;
423             }
424             inNumber = TRUE;
425
426             newFormats[k] = buf;
427             ++k;
428             buf.truncate(0);
429         } else {
430             buf += c;
431         }        
432     }
433
434     if (k != (count-1) || inNumber || inQuote) {
435         goto error;
436     }
437     newFormats[k] = buf;
438
439     // Don't modify this object until the parse succeeds
440     uprv_free(fChoiceLimits);
441     uprv_free(fClosures);
442     delete[] fChoiceFormats;
443     fCount = count;
444     fChoiceLimits  = newLimits;
445     fClosures      = newClosures;
446     fChoiceFormats = newFormats;
447     return;
448
449 error:
450     status = U_ILLEGAL_ARGUMENT_ERROR;
451     syntaxError(pattern,i,parseError);
452     uprv_free(newLimits);
453     uprv_free(newClosures);
454     delete[] newFormats;
455     return;
456
457 }
458 // -------------------------------------
459 // Reconstruct the original input pattern.
460
461 UnicodeString&
462 ChoiceFormat::toPattern(UnicodeString& result) const
463 {
464     result.remove();
465     for (int32_t i = 0; i < fCount; ++i) {
466         if (i != 0) {
467             result += VERTICAL_BAR;
468         }
469         UnicodeString buf;
470         if (uprv_isPositiveInfinity(fChoiceLimits[i])) {
471             result += INFINITY;
472         } else if (uprv_isNegativeInfinity(fChoiceLimits[i])) {
473             result += MINUS;
474             result += INFINITY;
475         } else {
476             result += dtos(fChoiceLimits[i], buf);
477         }
478         if (fClosures[i]) {
479             result += LESS_THAN;
480         } else {
481             result += LESS_EQUAL;
482         }
483         // Append fChoiceFormats[i], using quotes if there are special
484         // characters.  Single quotes themselves must be escaped in
485         // either case.
486         const UnicodeString& text = fChoiceFormats[i];
487         UBool needQuote = text.indexOf(LESS_THAN) >= 0
488             || text.indexOf(LESS_EQUAL) >= 0
489             || text.indexOf(LESS_EQUAL2) >= 0
490             || text.indexOf(VERTICAL_BAR) >= 0;
491         if (needQuote) {
492             result += SINGLE_QUOTE;
493         }
494         if (text.indexOf(SINGLE_QUOTE) < 0) {
495             result += text;
496         }
497         else {
498             for (int32_t j = 0; j < text.length(); ++j) {
499                 UChar c = text[j];
500                 result += c;
501                 if (c == SINGLE_QUOTE) {
502                     result += c;
503                 }
504             }
505         }
506         if (needQuote) {
507             result += SINGLE_QUOTE;
508         }
509     }
510
511     return result;
512 }
513
514 // -------------------------------------
515 // Sets the limit and format arrays. 
516 void
517 ChoiceFormat::setChoices(  const double* limits, 
518                            const UnicodeString* formats, 
519                            int32_t cnt )
520 {
521     setChoices(limits, 0, formats, cnt);
522 }
523
524 // -------------------------------------
525 // Sets the limit and format arrays. 
526 void
527 ChoiceFormat::setChoices(  const double* limits, 
528                            const UBool* closures,
529                            const UnicodeString* formats, 
530                            int32_t cnt )
531 {
532     if(limits == 0 || formats == 0)
533         return;
534
535     if (fChoiceLimits) {
536         uprv_free(fChoiceLimits);
537     }
538     if (fClosures) {
539         uprv_free(fClosures);
540     }
541     if (fChoiceFormats) {
542         delete [] fChoiceFormats;
543     }
544
545     // Note that the old arrays are deleted and this owns
546     // the created array.
547     fCount = cnt;
548     fChoiceLimits = (double*) uprv_malloc( sizeof(double) * fCount);
549     fClosures = (UBool*) uprv_malloc( sizeof(UBool) * fCount);
550     fChoiceFormats = new UnicodeString[fCount];
551
552     //check for memory allocation error
553     if (!fChoiceLimits || !fClosures || !fChoiceFormats) {
554         if (fChoiceLimits) {
555             uprv_free(fChoiceLimits);
556             fChoiceLimits = NULL;
557         }
558         if (fClosures) {
559             uprv_free(fClosures);
560             fClosures = NULL;
561         }
562         if (fChoiceFormats) {
563             delete[] fChoiceFormats;
564             fChoiceFormats = NULL;
565         }
566         return;
567     }
568     
569     uprv_arrayCopy(limits, fChoiceLimits, fCount);
570     uprv_arrayCopy(formats, fChoiceFormats, fCount);
571
572     if (closures != 0) {
573         uprv_arrayCopy(closures, fClosures, fCount);
574     } else {
575         int32_t i;
576         for (i=0; i<fCount; ++i) {
577             fClosures[i] = FALSE;
578         }
579     }
580 }
581
582 // -------------------------------------
583 // Gets the limit array.
584
585 const double*
586 ChoiceFormat::getLimits(int32_t& cnt) const 
587 {
588     cnt = fCount;
589     return fChoiceLimits;
590 }
591
592 // -------------------------------------
593 // Gets the closures array.
594
595 const UBool*
596 ChoiceFormat::getClosures(int32_t& cnt) const 
597 {
598     cnt = fCount;
599     return fClosures;
600 }
601
602 // -------------------------------------
603 // Gets the format array.
604
605 const UnicodeString*
606 ChoiceFormat::getFormats(int32_t& cnt) const
607 {
608     cnt = fCount;
609     return fChoiceFormats;
610 }
611
612 // -------------------------------------
613 // Formats an int64 number, it's actually formatted as
614 // a double.  The returned format string may differ
615 // from the input number because of this.
616
617 UnicodeString&
618 ChoiceFormat::format(int64_t number, 
619                      UnicodeString& appendTo, 
620                      FieldPosition& status) const
621 {
622     return format((double) number, appendTo, status);
623 }
624
625 // -------------------------------------
626 // Formats a long number, it's actually formatted as
627 // a double.  The returned format string may differ
628 // from the input number because of this.
629
630 UnicodeString&
631 ChoiceFormat::format(int32_t number, 
632                      UnicodeString& appendTo, 
633                      FieldPosition& status) const
634 {
635     return format((double) number, appendTo, status);
636 }
637
638 // -------------------------------------
639 // Formats a double number.
640
641 UnicodeString&
642 ChoiceFormat::format(double number, 
643                      UnicodeString& appendTo, 
644                      FieldPosition& /*pos*/) const
645 {
646     // find the number
647     int32_t i;
648     for (i = 0; i < fCount; ++i) {
649         if (fClosures[i]) {
650             if (!(number > fChoiceLimits[i])) {
651                 // same as number <= fChoiceLimits, except catches NaN
652                 break;
653             }
654         } else if (!(number >= fChoiceLimits[i])) {
655             // same as number < fChoiceLimits, except catches NaN
656             break;
657         }
658     }
659     --i;
660     if (i < 0) {
661         i = 0;
662     }
663     // return either a formatted number, or a string
664     appendTo += fChoiceFormats[i];
665     return appendTo;
666 }
667
668 // -------------------------------------
669 // Formats an array of objects. Checks if the data type of the objects
670 // to get the right value for formatting.  
671
672 UnicodeString&
673 ChoiceFormat::format(const Formattable* objs,
674                      int32_t cnt,
675                      UnicodeString& appendTo,
676                      FieldPosition& pos,
677                      UErrorCode& status) const
678 {
679     if(cnt < 0) {
680         status = U_ILLEGAL_ARGUMENT_ERROR;
681         return appendTo;
682     }
683
684     UnicodeString buffer;
685     for (int32_t i = 0; i < cnt; i++) {
686         double objDouble = objs[i].getDouble(status);
687         if (U_SUCCESS(status)) {
688             buffer.remove();
689             appendTo += format(objDouble, buffer, pos);
690         }
691     }
692
693     return appendTo;
694 }
695
696 // -------------------------------------
697 // Formats an array of objects. Checks if the data type of the objects
698 // to get the right value for formatting.  
699
700 UnicodeString&
701 ChoiceFormat::format(const Formattable& obj, 
702                      UnicodeString& appendTo, 
703                      FieldPosition& pos,
704                      UErrorCode& status) const
705 {
706     return NumberFormat::format(obj, appendTo, pos, status);
707 }
708 // -------------------------------------
709
710 void
711 ChoiceFormat::parse(const UnicodeString& text, 
712                     Formattable& result,
713                     ParsePosition& status) const
714 {
715     // find the best number (defined as the one with the longest parse)
716     int32_t start = status.getIndex();
717     int32_t furthest = start;
718     double bestNumber = uprv_getNaN();
719     double tempNumber = 0.0;
720     for (int i = 0; i < fCount; ++i) {
721         int32_t len = fChoiceFormats[i].length();
722         if (text.compare(start, len, fChoiceFormats[i]) == 0) {
723             status.setIndex(start + len);
724             tempNumber = fChoiceLimits[i];
725             if (status.getIndex() > furthest) {
726                 furthest = status.getIndex();
727                 bestNumber = tempNumber;
728                 if (furthest == text.length()) 
729                     break;
730             }
731         }
732     }
733     status.setIndex(furthest);
734     if (status.getIndex() == start) {
735         status.setErrorIndex(furthest);
736     }
737     result.setDouble(bestNumber);
738 }
739
740 // -------------------------------------
741 // Parses the text and return the Formattable object.  
742
743 void
744 ChoiceFormat::parse(const UnicodeString& text, 
745                     Formattable& result,
746                     UErrorCode& status) const
747 {
748     NumberFormat::parse(text, result, status);
749 }
750
751 // -------------------------------------
752
753 Format*
754 ChoiceFormat::clone() const
755 {
756     ChoiceFormat *aCopy = new ChoiceFormat(*this);
757     return aCopy;
758 }
759
760 U_NAMESPACE_END
761
762 #endif /* #if !UCONFIG_NO_FORMATTING */
763
764 //eof