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
43U_NAMESPACE_BEGIN
44
45UOBJECT_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
62static const UChar gPositiveInfinity[] = {INFINITY, 0};
63static 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
70ChoiceFormat::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
84ChoiceFormat::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
97ChoiceFormat::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
112ChoiceFormat::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
126ChoiceFormat::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
138UBool
139ChoiceFormat::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
159const ChoiceFormat&
160ChoiceFormat::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
201ChoiceFormat::~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 */
215double
216ChoiceFormat::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 */
230UnicodeString&
231ChoiceFormat::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
285void
286ChoiceFormat::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
296void
297ChoiceFormat::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
449error:
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
461UnicodeString&
462ChoiceFormat::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.
516void
517ChoiceFormat::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.
526void
527ChoiceFormat::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
585const double*
586ChoiceFormat::getLimits(int32_t& cnt) const
587{
588    cnt = fCount;
589    return fChoiceLimits;
590}
591
592// -------------------------------------
593// Gets the closures array.
594
595const UBool*
596ChoiceFormat::getClosures(int32_t& cnt) const
597{
598    cnt = fCount;
599    return fClosures;
600}
601
602// -------------------------------------
603// Gets the format array.
604
605const UnicodeString*
606ChoiceFormat::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
617UnicodeString&
618ChoiceFormat::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
630UnicodeString&
631ChoiceFormat::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
641UnicodeString&
642ChoiceFormat::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
672UnicodeString&
673ChoiceFormat::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
700UnicodeString&
701ChoiceFormat::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
710void
711ChoiceFormat::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
743void
744ChoiceFormat::parse(const UnicodeString& text,
745                    Formattable& result,
746                    UErrorCode& status) const
747{
748    NumberFormat::parse(text, result, status);
749}
750
751// -------------------------------------
752
753Format*
754ChoiceFormat::clone() const
755{
756    ChoiceFormat *aCopy = new ChoiceFormat(*this);
757    return aCopy;
758}
759
760U_NAMESPACE_END
761
762#endif /* #if !UCONFIG_NO_FORMATTING */
763
764//eof
765