Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/intl/icu/source/i18n/unum.cpp
Line
Count
Source (jump to first uncovered line)
1
// © 2016 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
/*
4
*******************************************************************************
5
*   Copyright (C) 1996-2015, International Business Machines
6
*   Corporation and others.  All Rights Reserved.
7
*******************************************************************************
8
* Modification History:
9
*
10
*   Date        Name        Description
11
*   06/24/99    helena      Integrated Alan's NF enhancements and Java2 bug fixes
12
*******************************************************************************
13
*/
14
15
#include "unicode/utypes.h"
16
17
#if !UCONFIG_NO_FORMATTING
18
19
#include "unicode/unum.h"
20
21
#include "unicode/uloc.h"
22
#include "unicode/numfmt.h"
23
#include "unicode/decimfmt.h"
24
#include "unicode/rbnf.h"
25
#include "unicode/compactdecimalformat.h"
26
#include "unicode/ustring.h"
27
#include "unicode/fmtable.h"
28
#include "unicode/dcfmtsym.h"
29
#include "unicode/curramt.h"
30
#include "unicode/localpointer.h"
31
#include "unicode/udisplaycontext.h"
32
#include "uassert.h"
33
#include "cpputils.h"
34
#include "cstring.h"
35
36
37
U_NAMESPACE_USE
38
39
40
U_CAPI UNumberFormat* U_EXPORT2
41
unum_open(  UNumberFormatStyle    style,  
42
            const    UChar*    pattern,
43
            int32_t            patternLength,
44
            const    char*     locale,
45
            UParseError*       parseErr,
46
0
            UErrorCode*        status) {
47
0
    if(U_FAILURE(*status)) {
48
0
        return NULL;
49
0
    }
50
0
51
0
    NumberFormat *retVal = NULL;
52
0
53
0
    switch(style) {
54
0
    case UNUM_DECIMAL:
55
0
    case UNUM_CURRENCY:
56
0
    case UNUM_PERCENT:
57
0
    case UNUM_SCIENTIFIC:
58
0
    case UNUM_CURRENCY_ISO:
59
0
    case UNUM_CURRENCY_PLURAL:
60
0
    case UNUM_CURRENCY_ACCOUNTING:
61
0
    case UNUM_CASH_CURRENCY:
62
0
    case UNUM_CURRENCY_STANDARD:
63
0
        retVal = NumberFormat::createInstance(Locale(locale), style, *status);
64
0
        break;
65
0
66
0
    case UNUM_PATTERN_DECIMAL: {
67
0
        UParseError tErr;
68
0
        /* UnicodeString can handle the case when patternLength = -1. */
69
0
        const UnicodeString pat(pattern, patternLength);
70
0
71
0
        if(parseErr==NULL){
72
0
            parseErr = &tErr;
73
0
        }
74
0
75
0
        DecimalFormatSymbols *syms = new DecimalFormatSymbols(Locale(locale), *status);
76
0
        if(syms == NULL) {
77
0
            *status = U_MEMORY_ALLOCATION_ERROR;
78
0
            return NULL;
79
0
        }
80
0
        if (U_FAILURE(*status)) {
81
0
            delete syms;
82
0
            return NULL;
83
0
        }
84
0
85
0
        retVal = new DecimalFormat(pat, syms, *parseErr, *status);
86
0
        if(retVal == NULL) {
87
0
            delete syms;
88
0
        }
89
0
    } break;
90
0
91
0
#if U_HAVE_RBNF
92
0
    case UNUM_PATTERN_RULEBASED: {
93
0
        UParseError tErr;
94
0
        /* UnicodeString can handle the case when patternLength = -1. */
95
0
        const UnicodeString pat(pattern, patternLength);
96
0
        
97
0
        if(parseErr==NULL){
98
0
            parseErr = &tErr;
99
0
        }
100
0
        
101
0
        retVal = new RuleBasedNumberFormat(pat, Locale(locale), *parseErr, *status);
102
0
    } break;
103
0
104
0
    case UNUM_SPELLOUT:
105
0
        retVal = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status);
106
0
        break;
107
0
108
0
    case UNUM_ORDINAL:
109
0
        retVal = new RuleBasedNumberFormat(URBNF_ORDINAL, Locale(locale), *status);
110
0
        break;
111
0
112
0
    case UNUM_DURATION:
113
0
        retVal = new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status);
114
0
        break;
115
0
116
0
    case UNUM_NUMBERING_SYSTEM:
117
0
        retVal = new RuleBasedNumberFormat(URBNF_NUMBERING_SYSTEM, Locale(locale), *status);
118
0
        break;
119
0
#endif
120
0
121
0
    case UNUM_DECIMAL_COMPACT_SHORT:
122
0
        retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_SHORT, *status);
123
0
        break;
124
0
125
0
    case UNUM_DECIMAL_COMPACT_LONG:
126
0
        retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_LONG, *status);
127
0
        break;
128
0
129
0
    default:
130
0
        *status = U_UNSUPPORTED_ERROR;
131
0
        return NULL;
132
0
    }
133
0
134
0
    if(retVal == NULL && U_SUCCESS(*status)) {
135
0
        *status = U_MEMORY_ALLOCATION_ERROR;
136
0
    }
137
0
138
0
    return reinterpret_cast<UNumberFormat *>(retVal);
139
0
}
140
141
U_CAPI void U_EXPORT2
142
unum_close(UNumberFormat* fmt)
143
0
{
144
0
    delete (NumberFormat*) fmt;
145
0
}
146
147
U_CAPI UNumberFormat* U_EXPORT2
148
unum_clone(const UNumberFormat *fmt,
149
       UErrorCode *status)
150
0
{
151
0
    if(U_FAILURE(*status))
152
0
        return 0;
153
0
    
154
0
    Format *res = 0;
155
0
    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
156
0
    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
157
0
    if (df != NULL) {
158
0
        res = df->clone();
159
0
    } else {
160
0
        const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
161
0
        U_ASSERT(rbnf != NULL);
162
0
        res = rbnf->clone();
163
0
    }
164
0
165
0
    if(res == 0) {
166
0
        *status = U_MEMORY_ALLOCATION_ERROR;
167
0
        return 0;
168
0
    }
169
0
    
170
0
    return (UNumberFormat*) res;
171
0
}
172
173
U_CAPI int32_t U_EXPORT2
174
unum_format(    const    UNumberFormat*    fmt,
175
        int32_t           number,
176
        UChar*            result,
177
        int32_t           resultLength,
178
        UFieldPosition    *pos,
179
        UErrorCode*       status)
180
0
{
181
0
        return unum_formatInt64(fmt, number, result, resultLength, pos, status);
182
0
}
183
184
U_CAPI int32_t U_EXPORT2
185
unum_formatInt64(const UNumberFormat* fmt,
186
        int64_t         number,
187
        UChar*          result,
188
        int32_t         resultLength,
189
        UFieldPosition *pos,
190
        UErrorCode*     status)
191
0
{
192
0
    if(U_FAILURE(*status))
193
0
        return -1;
194
0
    
195
0
    UnicodeString res;
196
0
    if(!(result==NULL && resultLength==0)) {
197
0
        // NULL destination for pure preflighting: empty dummy string
198
0
        // otherwise, alias the destination buffer
199
0
        res.setTo(result, 0, resultLength);
200
0
    }
201
0
    
202
0
    FieldPosition fp;
203
0
    
204
0
    if(pos != 0)
205
0
        fp.setField(pos->field);
206
0
    
207
0
    ((const NumberFormat*)fmt)->format(number, res, fp, *status);
208
0
209
0
    if(pos != 0) {
210
0
        pos->beginIndex = fp.getBeginIndex();
211
0
        pos->endIndex = fp.getEndIndex();
212
0
    }
213
0
    
214
0
    return res.extract(result, resultLength, *status);
215
0
}
216
217
U_CAPI int32_t U_EXPORT2
218
unum_formatDouble(    const    UNumberFormat*  fmt,
219
            double          number,
220
            UChar*          result,
221
            int32_t         resultLength,
222
            UFieldPosition  *pos, /* 0 if ignore */
223
            UErrorCode*     status)
224
0
{
225
0
 
226
0
  if(U_FAILURE(*status)) return -1;
227
0
228
0
  UnicodeString res;
229
0
  if(!(result==NULL && resultLength==0)) {
230
0
    // NULL destination for pure preflighting: empty dummy string
231
0
    // otherwise, alias the destination buffer
232
0
    res.setTo(result, 0, resultLength);
233
0
  }
234
0
235
0
  FieldPosition fp;
236
0
  
237
0
  if(pos != 0)
238
0
    fp.setField(pos->field);
239
0
  
240
0
  ((const NumberFormat*)fmt)->format(number, res, fp, *status);
241
0
  
242
0
  if(pos != 0) {
243
0
    pos->beginIndex = fp.getBeginIndex();
244
0
    pos->endIndex = fp.getEndIndex();
245
0
  }
246
0
  
247
0
  return res.extract(result, resultLength, *status);
248
0
}
249
250
U_CAPI int32_t U_EXPORT2
251
unum_formatDoubleForFields(const UNumberFormat* format,
252
                           double number,
253
                           UChar* result,
254
                           int32_t resultLength,
255
                           UFieldPositionIterator* fpositer,
256
                           UErrorCode* status)
257
0
{
258
0
    if (U_FAILURE(*status))
259
0
        return -1;
260
0
261
0
    if (result == NULL ? resultLength != 0 : resultLength < 0) {
262
0
        *status = U_ILLEGAL_ARGUMENT_ERROR;
263
0
        return -1;
264
0
    }
265
0
266
0
    UnicodeString res;
267
0
    if (result != NULL) {
268
0
        // NULL destination for pure preflighting: empty dummy string
269
0
        // otherwise, alias the destination buffer
270
0
        res.setTo(result, 0, resultLength);
271
0
    }
272
0
273
0
    ((const NumberFormat*)format)->format(number, res, (FieldPositionIterator*)fpositer, *status);
274
0
275
0
    return res.extract(result, resultLength, *status);
276
0
}
277
278
U_CAPI int32_t U_EXPORT2 
279
unum_formatDecimal(const    UNumberFormat*  fmt,
280
            const char *    number,
281
            int32_t         length,
282
            UChar*          result,
283
            int32_t         resultLength,
284
            UFieldPosition  *pos, /* 0 if ignore */
285
0
            UErrorCode*     status) {
286
0
287
0
    if(U_FAILURE(*status)) {
288
0
        return -1;
289
0
    }
290
0
    if ((result == NULL && resultLength != 0) || resultLength < 0) {
291
0
        *status = U_ILLEGAL_ARGUMENT_ERROR;
292
0
        return -1;
293
0
    }
294
0
295
0
    FieldPosition fp;
296
0
    if(pos != 0) {
297
0
        fp.setField(pos->field);
298
0
    }
299
0
300
0
    if (length < 0) {
301
0
        length = static_cast<int32_t>(uprv_strlen(number));
302
0
    }
303
0
    StringPiece numSP(number, length);
304
0
    Formattable numFmtbl(numSP, *status);
305
0
306
0
    UnicodeString resultStr;
307
0
    if (resultLength > 0) {
308
0
        // Alias the destination buffer.
309
0
        resultStr.setTo(result, 0, resultLength);
310
0
    }
311
0
    ((const NumberFormat*)fmt)->format(numFmtbl, resultStr, fp, *status);
312
0
    if(pos != 0) {
313
0
        pos->beginIndex = fp.getBeginIndex();
314
0
        pos->endIndex = fp.getEndIndex();
315
0
    }
316
0
    return resultStr.extract(result, resultLength, *status);
317
0
}
318
319
320
321
322
U_CAPI int32_t U_EXPORT2 
323
unum_formatDoubleCurrency(const UNumberFormat* fmt,
324
                          double number,
325
                          UChar* currency,
326
                          UChar* result,
327
                          int32_t resultLength,
328
                          UFieldPosition* pos, /* ignored if 0 */
329
0
                          UErrorCode* status) {
330
0
    if (U_FAILURE(*status)) return -1;
331
0
332
0
    UnicodeString res;
333
0
    if (!(result==NULL && resultLength==0)) {
334
0
        // NULL destination for pure preflighting: empty dummy string
335
0
        // otherwise, alias the destination buffer
336
0
        res.setTo(result, 0, resultLength);
337
0
    }
338
0
    
339
0
    FieldPosition fp;
340
0
    if (pos != 0) {
341
0
        fp.setField(pos->field);
342
0
    }
343
0
    CurrencyAmount *tempCurrAmnt = new CurrencyAmount(number, currency, *status);
344
0
    // Check for null pointer.
345
0
    if (tempCurrAmnt == NULL) {
346
0
        *status = U_MEMORY_ALLOCATION_ERROR;
347
0
        return -1;
348
0
    }
349
0
    Formattable n(tempCurrAmnt);
350
0
    ((const NumberFormat*)fmt)->format(n, res, fp, *status);
351
0
    
352
0
    if (pos != 0) {
353
0
        pos->beginIndex = fp.getBeginIndex();
354
0
        pos->endIndex = fp.getEndIndex();
355
0
    }
356
0
  
357
0
    return res.extract(result, resultLength, *status);
358
0
}
359
360
static void
361
parseRes(Formattable& res,
362
         const   UNumberFormat*  fmt,
363
         const   UChar*          text,
364
         int32_t         textLength,
365
         int32_t         *parsePos /* 0 = start */,
366
         UErrorCode      *status)
367
0
{
368
0
    if(U_FAILURE(*status))
369
0
        return;
370
0
    
371
0
    const UnicodeString src((UBool)(textLength == -1), text, textLength);
372
0
    ParsePosition pp;
373
0
    
374
0
    if(parsePos != 0)
375
0
        pp.setIndex(*parsePos);
376
0
    
377
0
    ((const NumberFormat*)fmt)->parse(src, res, pp);
378
0
    
379
0
    if(pp.getErrorIndex() != -1) {
380
0
        *status = U_PARSE_ERROR;
381
0
        if(parsePos != 0) {
382
0
            *parsePos = pp.getErrorIndex();
383
0
        }
384
0
    } else if(parsePos != 0) {
385
0
        *parsePos = pp.getIndex();
386
0
    }
387
0
}
388
389
U_CAPI int32_t U_EXPORT2
390
unum_parse(    const   UNumberFormat*  fmt,
391
        const   UChar*          text,
392
        int32_t         textLength,
393
        int32_t         *parsePos /* 0 = start */,
394
        UErrorCode      *status)
395
0
{
396
0
    Formattable res;
397
0
    parseRes(res, fmt, text, textLength, parsePos, status);
398
0
    return res.getLong(*status);
399
0
}
400
401
U_CAPI int64_t U_EXPORT2
402
unum_parseInt64(    const   UNumberFormat*  fmt,
403
        const   UChar*          text,
404
        int32_t         textLength,
405
        int32_t         *parsePos /* 0 = start */,
406
        UErrorCode      *status)
407
0
{
408
0
    Formattable res;
409
0
    parseRes(res, fmt, text, textLength, parsePos, status);
410
0
    return res.getInt64(*status);
411
0
}
412
413
U_CAPI double U_EXPORT2
414
unum_parseDouble(    const   UNumberFormat*  fmt,
415
            const   UChar*          text,
416
            int32_t         textLength,
417
            int32_t         *parsePos /* 0 = start */,
418
            UErrorCode      *status)
419
0
{
420
0
    Formattable res;
421
0
    parseRes(res, fmt, text, textLength, parsePos, status);
422
0
    return res.getDouble(*status);
423
0
}
424
425
U_CAPI int32_t U_EXPORT2
426
unum_parseDecimal(const UNumberFormat*  fmt,
427
            const UChar*    text,
428
            int32_t         textLength,
429
            int32_t         *parsePos /* 0 = start */,
430
            char            *outBuf,
431
            int32_t         outBufLength,
432
            UErrorCode      *status)
433
0
{
434
0
    if (U_FAILURE(*status)) {
435
0
        return -1;
436
0
    }
437
0
    if ((outBuf == NULL && outBufLength != 0) || outBufLength < 0) {
438
0
        *status = U_ILLEGAL_ARGUMENT_ERROR;
439
0
        return -1;
440
0
    }
441
0
    Formattable res;
442
0
    parseRes(res, fmt, text, textLength, parsePos, status);
443
0
    StringPiece sp = res.getDecimalNumber(*status);
444
0
    if (U_FAILURE(*status)) {
445
0
       return -1;
446
0
    } else if (sp.size() > outBufLength) {
447
0
        *status = U_BUFFER_OVERFLOW_ERROR;
448
0
    } else if (sp.size() == outBufLength) {
449
0
        uprv_strncpy(outBuf, sp.data(), sp.size());
450
0
        *status = U_STRING_NOT_TERMINATED_WARNING;
451
0
    } else {
452
0
        U_ASSERT(outBufLength > 0);
453
0
        uprv_strcpy(outBuf, sp.data());
454
0
    }
455
0
    return sp.size();
456
0
}
457
458
U_CAPI double U_EXPORT2
459
unum_parseDoubleCurrency(const UNumberFormat* fmt,
460
                         const UChar* text,
461
                         int32_t textLength,
462
                         int32_t* parsePos, /* 0 = start */
463
                         UChar* currency,
464
0
                         UErrorCode* status) {
465
0
    double doubleVal = 0.0;
466
0
    currency[0] = 0;
467
0
    if (U_FAILURE(*status)) {
468
0
        return doubleVal;
469
0
    }
470
0
    const UnicodeString src((UBool)(textLength == -1), text, textLength);
471
0
    ParsePosition pp;
472
0
    if (parsePos != NULL) {
473
0
        pp.setIndex(*parsePos);
474
0
    }
475
0
    *status = U_PARSE_ERROR; // assume failure, reset if succeed
476
0
    LocalPointer<CurrencyAmount> currAmt(((const NumberFormat*)fmt)->parseCurrency(src, pp));
477
0
    if (pp.getErrorIndex() != -1) {
478
0
        if (parsePos != NULL) {
479
0
            *parsePos = pp.getErrorIndex();
480
0
        }
481
0
    } else {
482
0
        if (parsePos != NULL) {
483
0
            *parsePos = pp.getIndex();
484
0
        }
485
0
        if (pp.getIndex() > 0) {
486
0
            *status = U_ZERO_ERROR;
487
0
            u_strcpy(currency, currAmt->getISOCurrency());
488
0
            doubleVal = currAmt->getNumber().getDouble(*status);
489
0
        }
490
0
    }
491
0
    return doubleVal;
492
0
}
493
494
U_CAPI const char* U_EXPORT2
495
unum_getAvailable(int32_t index)
496
0
{
497
0
    return uloc_getAvailable(index);
498
0
}
499
500
U_CAPI int32_t U_EXPORT2
501
unum_countAvailable()
502
0
{
503
0
    return uloc_countAvailable();
504
0
}
505
506
U_CAPI int32_t U_EXPORT2
507
unum_getAttribute(const UNumberFormat*          fmt,
508
          UNumberFormatAttribute  attr)
509
0
{
510
0
    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
511
0
    if (attr == UNUM_LENIENT_PARSE) {
512
0
        // Supported for all subclasses
513
0
        return nf->isLenient();
514
0
    }
515
0
    else if (attr == UNUM_MAX_INTEGER_DIGITS) {
516
0
        return nf->getMaximumIntegerDigits();
517
0
    }
518
0
    else if (attr == UNUM_MIN_INTEGER_DIGITS) {
519
0
        return nf->getMinimumIntegerDigits();
520
0
    }
521
0
    else if (attr == UNUM_INTEGER_DIGITS) {
522
0
        // TODO: what should this return?
523
0
        return nf->getMinimumIntegerDigits();
524
0
    }
525
0
    else if (attr == UNUM_MAX_FRACTION_DIGITS) {
526
0
        return nf->getMaximumFractionDigits();
527
0
    }
528
0
    else if (attr == UNUM_MIN_FRACTION_DIGITS) {
529
0
        return nf->getMinimumFractionDigits();
530
0
    }
531
0
    else if (attr == UNUM_FRACTION_DIGITS) {
532
0
        // TODO: what should this return?
533
0
        return nf->getMinimumFractionDigits();
534
0
    }
535
0
    else if (attr == UNUM_ROUNDING_MODE) {
536
0
        return nf->getRoundingMode();
537
0
    }
538
0
539
0
    // The remaining attributes are only supported for DecimalFormat
540
0
    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
541
0
    if (df != NULL) {
542
0
        UErrorCode ignoredStatus = U_ZERO_ERROR;
543
0
        return df->getAttribute(attr, ignoredStatus);
544
0
    }
545
0
546
0
    return -1;
547
0
}
548
549
U_CAPI void U_EXPORT2
550
unum_setAttribute(    UNumberFormat*          fmt,
551
            UNumberFormatAttribute  attr,
552
            int32_t                 newValue)
553
0
{
554
0
    NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
555
0
    if (attr == UNUM_LENIENT_PARSE) {
556
0
        // Supported for all subclasses
557
0
        // keep this here as the class may not be a DecimalFormat
558
0
        return nf->setLenient(newValue != 0);
559
0
    }
560
0
    else if (attr == UNUM_MAX_INTEGER_DIGITS) {
561
0
        return nf->setMaximumIntegerDigits(newValue);
562
0
    }
563
0
    else if (attr == UNUM_MIN_INTEGER_DIGITS) {
564
0
        return nf->setMinimumIntegerDigits(newValue);
565
0
    }
566
0
    else if (attr == UNUM_INTEGER_DIGITS) {
567
0
        nf->setMinimumIntegerDigits(newValue);
568
0
        return nf->setMaximumIntegerDigits(newValue);
569
0
    }
570
0
    else if (attr == UNUM_MAX_FRACTION_DIGITS) {
571
0
        return nf->setMaximumFractionDigits(newValue);
572
0
    }
573
0
    else if (attr == UNUM_MIN_FRACTION_DIGITS) {
574
0
        return nf->setMinimumFractionDigits(newValue);
575
0
    }
576
0
    else if (attr == UNUM_FRACTION_DIGITS) {
577
0
        nf->setMinimumFractionDigits(newValue);
578
0
        return nf->setMaximumFractionDigits(newValue);
579
0
    }
580
0
    else if (attr == UNUM_ROUNDING_MODE) {
581
0
        return nf->setRoundingMode((NumberFormat::ERoundingMode)newValue);
582
0
    }
583
0
584
0
    // The remaining attributes are only supported for DecimalFormat
585
0
    DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
586
0
    if (df != NULL) {
587
0
        UErrorCode ignoredStatus = U_ZERO_ERROR;
588
0
        df->setAttribute(attr, newValue, ignoredStatus);
589
0
    }
590
0
}
591
592
U_CAPI double U_EXPORT2
593
unum_getDoubleAttribute(const UNumberFormat*          fmt,
594
          UNumberFormatAttribute  attr)
595
0
{
596
0
    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
597
0
    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
598
0
    if (df != NULL &&  attr == UNUM_ROUNDING_INCREMENT) {
599
0
        return df->getRoundingIncrement();
600
0
    } else {
601
0
        return -1.0;
602
0
    }
603
0
}
604
605
U_CAPI void U_EXPORT2
606
unum_setDoubleAttribute(    UNumberFormat*          fmt,
607
            UNumberFormatAttribute  attr,
608
            double                 newValue)
609
0
{
610
0
    NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
611
0
    DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
612
0
    if (df != NULL && attr == UNUM_ROUNDING_INCREMENT) {   
613
0
        df->setRoundingIncrement(newValue);
614
0
    }
615
0
}
616
617
U_CAPI int32_t U_EXPORT2
618
unum_getTextAttribute(const UNumberFormat*  fmt,
619
            UNumberFormatTextAttribute      tag,
620
            UChar*                          result,
621
            int32_t                         resultLength,
622
            UErrorCode*                     status)
623
0
{
624
0
    if(U_FAILURE(*status))
625
0
        return -1;
626
0
627
0
    UnicodeString res;
628
0
    if(!(result==NULL && resultLength==0)) {
629
0
        // NULL destination for pure preflighting: empty dummy string
630
0
        // otherwise, alias the destination buffer
631
0
        res.setTo(result, 0, resultLength);
632
0
    }
633
0
634
0
    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
635
0
    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
636
0
    if (df != NULL) {
637
0
        switch(tag) {
638
0
        case UNUM_POSITIVE_PREFIX:
639
0
            df->getPositivePrefix(res);
640
0
            break;
641
0
642
0
        case UNUM_POSITIVE_SUFFIX:
643
0
            df->getPositiveSuffix(res);
644
0
            break;
645
0
646
0
        case UNUM_NEGATIVE_PREFIX:
647
0
            df->getNegativePrefix(res);
648
0
            break;
649
0
650
0
        case UNUM_NEGATIVE_SUFFIX:
651
0
            df->getNegativeSuffix(res);
652
0
            break;
653
0
654
0
        case UNUM_PADDING_CHARACTER:
655
0
            res = df->getPadCharacterString();
656
0
            break;
657
0
658
0
        case UNUM_CURRENCY_CODE:
659
0
            res = UnicodeString(df->getCurrency());
660
0
            break;
661
0
662
0
        default:
663
0
            *status = U_UNSUPPORTED_ERROR;
664
0
            return -1;
665
0
        }
666
0
    } else {
667
0
        const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
668
0
        U_ASSERT(rbnf != NULL);
669
0
        if (tag == UNUM_DEFAULT_RULESET) {
670
0
            res = rbnf->getDefaultRuleSetName();
671
0
        } else if (tag == UNUM_PUBLIC_RULESETS) {
672
0
            int32_t count = rbnf->getNumberOfRuleSetNames();
673
0
            for (int i = 0; i < count; ++i) {
674
0
                res += rbnf->getRuleSetName(i);
675
0
                res += (UChar)0x003b; // semicolon
676
0
            }
677
0
        } else {
678
0
            *status = U_UNSUPPORTED_ERROR;
679
0
            return -1;
680
0
        }
681
0
    }
682
0
683
0
    return res.extract(result, resultLength, *status);
684
0
}
685
686
U_CAPI void U_EXPORT2
687
unum_setTextAttribute(    UNumberFormat*                    fmt,
688
            UNumberFormatTextAttribute      tag,
689
            const    UChar*                            newValue,
690
            int32_t                            newValueLength,
691
            UErrorCode                        *status)
692
0
{
693
0
    if(U_FAILURE(*status))
694
0
        return;
695
0
696
0
    UnicodeString val(newValue, newValueLength);
697
0
    NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
698
0
    DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
699
0
    if (df != NULL) {
700
0
      switch(tag) {
701
0
      case UNUM_POSITIVE_PREFIX:
702
0
        df->setPositivePrefix(val);
703
0
        break;
704
0
        
705
0
      case UNUM_POSITIVE_SUFFIX:
706
0
        df->setPositiveSuffix(val);
707
0
        break;
708
0
        
709
0
      case UNUM_NEGATIVE_PREFIX:
710
0
        df->setNegativePrefix(val);
711
0
        break;
712
0
        
713
0
      case UNUM_NEGATIVE_SUFFIX:
714
0
        df->setNegativeSuffix(val);
715
0
        break;
716
0
        
717
0
      case UNUM_PADDING_CHARACTER:
718
0
        df->setPadCharacter(val);
719
0
        break;
720
0
        
721
0
      case UNUM_CURRENCY_CODE:
722
0
        df->setCurrency(val.getTerminatedBuffer(), *status);
723
0
        break;
724
0
        
725
0
      default:
726
0
        *status = U_UNSUPPORTED_ERROR;
727
0
        break;
728
0
      }
729
0
    } else {
730
0
      RuleBasedNumberFormat* rbnf = dynamic_cast<RuleBasedNumberFormat*>(nf);
731
0
      U_ASSERT(rbnf != NULL);
732
0
      if (tag == UNUM_DEFAULT_RULESET) {
733
0
        rbnf->setDefaultRuleSet(val, *status);
734
0
      } else {
735
0
        *status = U_UNSUPPORTED_ERROR;
736
0
      }
737
0
    }
738
0
}
739
740
U_CAPI int32_t U_EXPORT2
741
unum_toPattern(    const    UNumberFormat*          fmt,
742
        UBool                  isPatternLocalized,
743
        UChar*                  result,
744
        int32_t                 resultLength,
745
        UErrorCode*             status)
746
0
{
747
0
    if(U_FAILURE(*status))
748
0
        return -1;
749
0
    
750
0
    UnicodeString pat;
751
0
    if(!(result==NULL && resultLength==0)) {
752
0
        // NULL destination for pure preflighting: empty dummy string
753
0
        // otherwise, alias the destination buffer
754
0
        pat.setTo(result, 0, resultLength);
755
0
    }
756
0
757
0
    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
758
0
    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
759
0
    if (df != NULL) {
760
0
      if(isPatternLocalized)
761
0
        df->toLocalizedPattern(pat);
762
0
      else
763
0
        df->toPattern(pat);
764
0
    } else {
765
0
      const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
766
0
      U_ASSERT(rbnf != NULL);
767
0
      pat = rbnf->getRules();
768
0
    }
769
0
    return pat.extract(result, resultLength, *status);
770
0
}
771
772
U_CAPI int32_t U_EXPORT2
773
unum_getSymbol(const UNumberFormat *fmt,
774
               UNumberFormatSymbol symbol,
775
               UChar *buffer,
776
               int32_t size,
777
               UErrorCode *status)
778
0
{
779
0
    if(status==NULL || U_FAILURE(*status)) {
780
0
        return 0;
781
0
    }
782
0
    if(fmt==NULL || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT) {
783
0
        *status=U_ILLEGAL_ARGUMENT_ERROR;
784
0
        return 0;
785
0
    }
786
0
    const NumberFormat *nf = reinterpret_cast<const NumberFormat *>(fmt);
787
0
    const DecimalFormat *dcf = dynamic_cast<const DecimalFormat *>(nf);
788
0
    if (dcf == NULL) {
789
0
      *status = U_UNSUPPORTED_ERROR;
790
0
      return 0;
791
0
    }
792
0
793
0
    return dcf->
794
0
      getDecimalFormatSymbols()->
795
0
        getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol).
796
0
          extract(buffer, size, *status);
797
0
}
798
799
U_CAPI void U_EXPORT2
800
unum_setSymbol(UNumberFormat *fmt,
801
               UNumberFormatSymbol symbol,
802
               const UChar *value,
803
               int32_t length,
804
               UErrorCode *status)
805
0
{
806
0
    if(status==NULL || U_FAILURE(*status)) {
807
0
        return;
808
0
    }
809
0
    if(fmt==NULL || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT || value==NULL || length<-1) {
810
0
        *status=U_ILLEGAL_ARGUMENT_ERROR;
811
0
        return;
812
0
    }
813
0
    NumberFormat *nf = reinterpret_cast<NumberFormat *>(fmt);
814
0
    DecimalFormat *dcf = dynamic_cast<DecimalFormat *>(nf);
815
0
    if (dcf == NULL) {
816
0
      *status = U_UNSUPPORTED_ERROR;
817
0
      return;
818
0
    }
819
0
820
0
    DecimalFormatSymbols symbols(*dcf->getDecimalFormatSymbols());
821
0
    symbols.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol,
822
0
        UnicodeString(value, length));  /* UnicodeString can handle the case when length = -1. */
823
0
    dcf->setDecimalFormatSymbols(symbols);
824
0
}
825
826
U_CAPI void U_EXPORT2
827
unum_applyPattern(  UNumberFormat  *fmt,
828
                    UBool          localized,
829
                    const UChar    *pattern,
830
                    int32_t        patternLength,
831
                    UParseError    *parseError,
832
                    UErrorCode*    status)
833
0
{
834
0
    UErrorCode tStatus = U_ZERO_ERROR;
835
0
    UParseError tParseError;
836
0
    
837
0
    if(parseError == NULL){
838
0
        parseError = &tParseError;
839
0
    }
840
0
    
841
0
    if(status==NULL){
842
0
        status = &tStatus;
843
0
    }
844
0
    
845
0
    int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
846
0
    const UnicodeString pat((UChar*)pattern, len, len);
847
0
848
0
    // Verify if the object passed is a DecimalFormat object
849
0
    NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
850
0
    DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
851
0
    if (df != NULL) {
852
0
      if(localized) {
853
0
        df->applyLocalizedPattern(pat,*parseError, *status);
854
0
      } else {
855
0
        df->applyPattern(pat,*parseError, *status);
856
0
      }
857
0
    } else {
858
0
      *status = U_UNSUPPORTED_ERROR;
859
0
      return;
860
0
    }
861
0
}
862
863
U_CAPI const char* U_EXPORT2
864
unum_getLocaleByType(const UNumberFormat *fmt,
865
                     ULocDataLocaleType type,
866
                     UErrorCode* status)
867
0
{
868
0
    if (fmt == NULL) {
869
0
        if (U_SUCCESS(*status)) {
870
0
            *status = U_ILLEGAL_ARGUMENT_ERROR;
871
0
        }
872
0
        return NULL;
873
0
    }
874
0
    return ((const Format*)fmt)->getLocaleID(type, *status);
875
0
}
876
877
U_CAPI void U_EXPORT2
878
unum_setContext(UNumberFormat* fmt, UDisplayContext value, UErrorCode* status)
879
0
{
880
0
    if (U_FAILURE(*status)) {
881
0
        return;
882
0
    }
883
0
    ((NumberFormat*)fmt)->setContext(value, *status);
884
0
    return;
885
0
}
886
887
U_CAPI UDisplayContext U_EXPORT2
888
unum_getContext(const UNumberFormat *fmt, UDisplayContextType type, UErrorCode* status)
889
0
{
890
0
    if (U_FAILURE(*status)) {
891
0
        return (UDisplayContext)0;
892
0
    }
893
0
    return ((const NumberFormat*)fmt)->getContext(type, *status);
894
0
}
895
896
U_INTERNAL UFormattable * U_EXPORT2
897
unum_parseToUFormattable(const UNumberFormat* fmt,
898
                         UFormattable *result,
899
                         const UChar* text,
900
                         int32_t textLength,
901
                         int32_t* parsePos, /* 0 = start */
902
0
                         UErrorCode* status) {
903
0
  UFormattable *newFormattable = NULL;
904
0
  if (U_FAILURE(*status)) return result;
905
0
  if (fmt == NULL || (text==NULL && textLength!=0)) {
906
0
    *status = U_ILLEGAL_ARGUMENT_ERROR;
907
0
    return result;
908
0
  }
909
0
  if (result == NULL) { // allocate if not allocated.
910
0
    newFormattable = result = ufmt_open(status);
911
0
  }
912
0
  parseRes(*(Formattable::fromUFormattable(result)), fmt, text, textLength, parsePos, status);
913
0
  if (U_FAILURE(*status) && newFormattable != NULL) {
914
0
    ufmt_close(newFormattable);
915
0
    result = NULL; // deallocate if there was a parse error
916
0
  }
917
0
  return result;
918
0
}
919
920
U_INTERNAL int32_t U_EXPORT2
921
unum_formatUFormattable(const UNumberFormat* fmt,
922
                        const UFormattable *number,
923
                        UChar *result,
924
                        int32_t resultLength,
925
                        UFieldPosition *pos, /* ignored if 0 */
926
0
                        UErrorCode *status) {
927
0
    if (U_FAILURE(*status)) {
928
0
      return 0;
929
0
    }
930
0
    if (fmt == NULL || number==NULL ||
931
0
        (result==NULL ? resultLength!=0 : resultLength<0)) {
932
0
      *status = U_ILLEGAL_ARGUMENT_ERROR;
933
0
      return 0;
934
0
    }
935
0
    UnicodeString res(result, 0, resultLength);
936
0
937
0
    FieldPosition fp;
938
0
939
0
    if(pos != 0)
940
0
        fp.setField(pos->field);
941
0
942
0
    ((const NumberFormat*)fmt)->format(*(Formattable::fromUFormattable(number)), res, fp, *status);
943
0
944
0
    if(pos != 0) {
945
0
        pos->beginIndex = fp.getBeginIndex();
946
0
        pos->endIndex = fp.getEndIndex();
947
0
    }
948
0
949
0
    return res.extract(result, resultLength, *status);
950
0
}
951
952
#endif /* #if !UCONFIG_NO_FORMATTING */