1 /*
2 *******************************************************************************
3 * Copyright (C) 1997-2010, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
6 *
7 * File FMTABLE.CPP
8 *
9 * Modification History:
10 *
11 * Date Name Description
12 * 03/25/97 clhuang Initial Implementation.
13 ********************************************************************************
14 */
15
16 #include "unicode/utypes.h"
17
18 #if !UCONFIG_NO_FORMATTING
19
20 #include "unicode/fmtable.h"
21 #include "unicode/ustring.h"
22 #include "unicode/measure.h"
23 #include "unicode/curramt.h"
24 #include "charstr.h"
25 #include "cmemory.h"
26 #include "cstring.h"
27 #include "decNumber.h"
28 #include "digitlst.h"
29
30 // *****************************************************************************
31 // class Formattable
32 // *****************************************************************************
33
34 U_NAMESPACE_BEGIN
35
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable)36 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable)
37
38 //-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
39
40 // NOTE: As of 3.0, there are limitations to the UObject API. It does
41 // not (yet) support cloning, operator=, nor operator==. To
42 // work around this, I implement some simple inlines here. Later
43 // these can be modified or removed. [alan]
44
45 // NOTE: These inlines assume that all fObjects are in fact instances
46 // of the Measure class, which is true as of 3.0. [alan]
47
48 // Return TRUE if *a == *b.
49 static inline UBool objectEquals(const UObject* a, const UObject* b) {
50 // LATER: return *a == *b;
51 return *((const Measure*) a) == *((const Measure*) b);
52 }
53
54 // Return a clone of *a.
objectClone(const UObject * a)55 static inline UObject* objectClone(const UObject* a) {
56 // LATER: return a->clone();
57 return ((const Measure*) a)->clone();
58 }
59
60 // Return TRUE if *a is an instance of Measure.
instanceOfMeasure(const UObject * a)61 static inline UBool instanceOfMeasure(const UObject* a) {
62 return dynamic_cast<const Measure*>(a) != NULL;
63 }
64
65 /**
66 * Creates a new Formattable array and copies the values from the specified
67 * original.
68 * @param array the original array
69 * @param count the original array count
70 * @return the new Formattable array.
71 */
createArrayCopy(const Formattable * array,int32_t count)72 static Formattable* createArrayCopy(const Formattable* array, int32_t count) {
73 Formattable *result = new Formattable[count];
74 if (result != NULL) {
75 for (int32_t i=0; i<count; ++i)
76 result[i] = array[i]; // Don't memcpy!
77 }
78 return result;
79 }
80
81 //-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
82
83 /**
84 * Set 'ec' to 'err' only if 'ec' is not already set to a failing UErrorCode.
85 */
setError(UErrorCode & ec,UErrorCode err)86 static void setError(UErrorCode& ec, UErrorCode err) {
87 if (U_SUCCESS(ec)) {
88 ec = err;
89 }
90 }
91
92 //
93 // Common initialization code, shared by constructors.
94 // Put everything into a known state.
95 //
init()96 void Formattable::init() {
97 fValue.fInt64 = 0;
98 fType = kLong;
99 fDecimalStr = NULL;
100 fDecimalNum = NULL;
101 fBogus.setToBogus();
102 }
103
104 // -------------------------------------
105 // default constructor.
106 // Creates a formattable object with a long value 0.
107
Formattable()108 Formattable::Formattable() {
109 init();
110 }
111
112 // -------------------------------------
113 // Creates a formattable object with a Date instance.
114
Formattable(UDate date,ISDATE)115 Formattable::Formattable(UDate date, ISDATE /*isDate*/)
116 {
117 init();
118 fType = kDate;
119 fValue.fDate = date;
120 }
121
122 // -------------------------------------
123 // Creates a formattable object with a double value.
124
Formattable(double value)125 Formattable::Formattable(double value)
126 {
127 init();
128 fType = kDouble;
129 fValue.fDouble = value;
130 }
131
132 // -------------------------------------
133 // Creates a formattable object with an int32_t value.
134
Formattable(int32_t value)135 Formattable::Formattable(int32_t value)
136 {
137 init();
138 fValue.fInt64 = value;
139 }
140
141 // -------------------------------------
142 // Creates a formattable object with an int64_t value.
143
Formattable(int64_t value)144 Formattable::Formattable(int64_t value)
145 {
146 init();
147 fType = kInt64;
148 fValue.fInt64 = value;
149 }
150
151 // -------------------------------------
152 // Creates a formattable object with a decimal number value from a string.
153
Formattable(const StringPiece & number,UErrorCode & status)154 Formattable::Formattable(const StringPiece &number, UErrorCode &status) {
155 init();
156 setDecimalNumber(number, status);
157 }
158
159
160 // -------------------------------------
161 // Creates a formattable object with a UnicodeString instance.
162
Formattable(const UnicodeString & stringToCopy)163 Formattable::Formattable(const UnicodeString& stringToCopy)
164 {
165 init();
166 fType = kString;
167 fValue.fString = new UnicodeString(stringToCopy);
168 }
169
170 // -------------------------------------
171 // Creates a formattable object with a UnicodeString* value.
172 // (adopting symantics)
173
Formattable(UnicodeString * stringToAdopt)174 Formattable::Formattable(UnicodeString* stringToAdopt)
175 {
176 init();
177 fType = kString;
178 fValue.fString = stringToAdopt;
179 }
180
Formattable(UObject * objectToAdopt)181 Formattable::Formattable(UObject* objectToAdopt)
182 {
183 init();
184 fType = kObject;
185 fValue.fObject = objectToAdopt;
186 }
187
188 // -------------------------------------
189
Formattable(const Formattable * arrayToCopy,int32_t count)190 Formattable::Formattable(const Formattable* arrayToCopy, int32_t count)
191 : UObject(), fType(kArray)
192 {
193 init();
194 fType = kArray;
195 fValue.fArrayAndCount.fArray = createArrayCopy(arrayToCopy, count);
196 fValue.fArrayAndCount.fCount = count;
197 }
198
199 // -------------------------------------
200 // copy constructor
201
202 #ifdef U_WINODWS
203 #pragram warning(disable: 4996)
204 #endif
205
Formattable(const Formattable & source)206 Formattable::Formattable(const Formattable &source)
207 : UObject(*this)
208 {
209 init();
210 *this = source;
211 }
212
213 // -------------------------------------
214 // assignment operator
215
216 Formattable&
operator =(const Formattable & source)217 Formattable::operator=(const Formattable& source)
218 {
219 if (this != &source)
220 {
221 // Disposes the current formattable value/setting.
222 dispose();
223
224 // Sets the correct data type for this value.
225 fType = source.fType;
226 switch (fType)
227 {
228 case kArray:
229 // Sets each element in the array one by one and records the array count.
230 fValue.fArrayAndCount.fCount = source.fValue.fArrayAndCount.fCount;
231 fValue.fArrayAndCount.fArray = createArrayCopy(source.fValue.fArrayAndCount.fArray,
232 source.fValue.fArrayAndCount.fCount);
233 break;
234 case kString:
235 // Sets the string value.
236 fValue.fString = new UnicodeString(*source.fValue.fString);
237 break;
238 case kDouble:
239 // Sets the double value.
240 fValue.fDouble = source.fValue.fDouble;
241 break;
242 case kLong:
243 case kInt64:
244 // Sets the long value.
245 fValue.fInt64 = source.fValue.fInt64;
246 break;
247 case kDate:
248 // Sets the Date value.
249 fValue.fDate = source.fValue.fDate;
250 break;
251 case kObject:
252 fValue.fObject = objectClone(source.fValue.fObject);
253 break;
254 }
255
256 UErrorCode status = U_ZERO_ERROR;
257 if (source.fDecimalNum != NULL) {
258 fDecimalNum = new DigitList(*source.fDecimalNum);
259 }
260 if (source.fDecimalStr != NULL) {
261 fDecimalStr = new CharString(*source.fDecimalStr, status);
262 if (U_FAILURE(status)) {
263 delete fDecimalStr;
264 fDecimalStr = NULL;
265 }
266 }
267 }
268 return *this;
269 }
270
271 // -------------------------------------
272
273 UBool
operator ==(const Formattable & that) const274 Formattable::operator==(const Formattable& that) const
275 {
276 int32_t i;
277
278 if (this == &that) return TRUE;
279
280 // Returns FALSE if the data types are different.
281 if (fType != that.fType) return FALSE;
282
283 // Compares the actual data values.
284 UBool equal = TRUE;
285 switch (fType) {
286 case kDate:
287 equal = (fValue.fDate == that.fValue.fDate);
288 break;
289 case kDouble:
290 equal = (fValue.fDouble == that.fValue.fDouble);
291 break;
292 case kLong:
293 case kInt64:
294 equal = (fValue.fInt64 == that.fValue.fInt64);
295 break;
296 case kString:
297 equal = (*(fValue.fString) == *(that.fValue.fString));
298 break;
299 case kArray:
300 if (fValue.fArrayAndCount.fCount != that.fValue.fArrayAndCount.fCount) {
301 equal = FALSE;
302 break;
303 }
304 // Checks each element for equality.
305 for (i=0; i<fValue.fArrayAndCount.fCount; ++i) {
306 if (fValue.fArrayAndCount.fArray[i] != that.fValue.fArrayAndCount.fArray[i]) {
307 equal = FALSE;
308 break;
309 }
310 }
311 break;
312 case kObject:
313 if (fValue.fObject == NULL || that.fValue.fObject == NULL) {
314 equal = FALSE;
315 } else {
316 equal = objectEquals(fValue.fObject, that.fValue.fObject);
317 }
318 break;
319 }
320
321 // TODO: compare digit lists if numeric.
322 return equal;
323 }
324
325 // -------------------------------------
326
~Formattable()327 Formattable::~Formattable()
328 {
329 dispose();
330 }
331
332 // -------------------------------------
333
dispose()334 void Formattable::dispose()
335 {
336 // Deletes the data value if necessary.
337 switch (fType) {
338 case kString:
339 delete fValue.fString;
340 break;
341 case kArray:
342 delete[] fValue.fArrayAndCount.fArray;
343 break;
344 case kObject:
345 delete fValue.fObject;
346 break;
347 default:
348 break;
349 }
350
351 fType = kLong;
352 fValue.fInt64 = 0;
353 delete fDecimalStr;
354 fDecimalStr = NULL;
355 delete fDecimalNum;
356 fDecimalNum = NULL;
357 }
358
359 Formattable *
clone() const360 Formattable::clone() const {
361 return new Formattable(*this);
362 }
363
364 // -------------------------------------
365 // Gets the data type of this Formattable object.
366 Formattable::Type
getType() const367 Formattable::getType() const
368 {
369 return fType;
370 }
371
372 UBool
isNumeric() const373 Formattable::isNumeric() const {
374 switch (fType) {
375 case kDouble:
376 case kLong:
377 case kInt64:
378 return TRUE;
379 default:
380 return FALSE;
381 }
382 }
383
384 // -------------------------------------
385 int32_t
386 //Formattable::getLong(UErrorCode* status) const
getLong(UErrorCode & status) const387 Formattable::getLong(UErrorCode& status) const
388 {
389 if (U_FAILURE(status)) {
390 return 0;
391 }
392
393 switch (fType) {
394 case Formattable::kLong:
395 return (int32_t)fValue.fInt64;
396 case Formattable::kInt64:
397 if (fValue.fInt64 > INT32_MAX) {
398 status = U_INVALID_FORMAT_ERROR;
399 return INT32_MAX;
400 } else if (fValue.fInt64 < INT32_MIN) {
401 status = U_INVALID_FORMAT_ERROR;
402 return INT32_MIN;
403 } else {
404 return (int32_t)fValue.fInt64;
405 }
406 case Formattable::kDouble:
407 if (fValue.fDouble > INT32_MAX) {
408 status = U_INVALID_FORMAT_ERROR;
409 return INT32_MAX;
410 } else if (fValue.fDouble < INT32_MIN) {
411 status = U_INVALID_FORMAT_ERROR;
412 return INT32_MIN;
413 } else {
414 return (int32_t)fValue.fDouble; // loses fraction
415 }
416 case Formattable::kObject:
417 if (fValue.fObject == NULL) {
418 status = U_MEMORY_ALLOCATION_ERROR;
419 return 0;
420 }
421 // TODO Later replace this with instanceof call
422 if (instanceOfMeasure(fValue.fObject)) {
423 return ((const Measure*) fValue.fObject)->
424 getNumber().getLong(status);
425 }
426 default:
427 status = U_INVALID_FORMAT_ERROR;
428 return 0;
429 }
430 }
431
432 // -------------------------------------
433 int64_t
getInt64(UErrorCode & status) const434 Formattable::getInt64(UErrorCode& status) const
435 {
436 if (U_FAILURE(status)) {
437 return 0;
438 }
439
440 switch (fType) {
441 case Formattable::kLong:
442 case Formattable::kInt64:
443 return fValue.fInt64;
444 case Formattable::kDouble:
445 if (fValue.fDouble >= U_INT64_MAX) {
446 status = U_INVALID_FORMAT_ERROR;
447 return U_INT64_MAX;
448 } else if (fValue.fDouble <= U_INT64_MIN) {
449 status = U_INVALID_FORMAT_ERROR;
450 return U_INT64_MIN;
451 } else {
452 return (int64_t)fValue.fDouble;
453 }
454 case Formattable::kObject:
455 if (fValue.fObject == NULL) {
456 status = U_MEMORY_ALLOCATION_ERROR;
457 return 0;
458 }
459 // TODO Later replace this with instanceof call
460 if (instanceOfMeasure(fValue.fObject)) {
461 return ((const Measure*) fValue.fObject)->
462 getNumber().getInt64(status);
463 }
464 default:
465 status = U_INVALID_FORMAT_ERROR;
466 return 0;
467 }
468 }
469
470 // -------------------------------------
471 double
getDouble(UErrorCode & status) const472 Formattable::getDouble(UErrorCode& status) const
473 {
474 if (U_FAILURE(status)) {
475 return 0;
476 }
477
478 switch (fType) {
479 case Formattable::kLong:
480 case Formattable::kInt64: // loses precision
481 return (double)fValue.fInt64;
482 case Formattable::kDouble:
483 return fValue.fDouble;
484 case Formattable::kObject:
485 if (fValue.fObject == NULL) {
486 status = U_MEMORY_ALLOCATION_ERROR;
487 return 0;
488 }
489 // TODO Later replace this with instanceof call
490 if (instanceOfMeasure(fValue.fObject)) {
491 return ((const Measure*) fValue.fObject)->
492 getNumber().getDouble(status);
493 }
494 default:
495 status = U_INVALID_FORMAT_ERROR;
496 return 0;
497 }
498 }
499
500 const UObject*
getObject() const501 Formattable::getObject() const {
502 return (fType == kObject) ? fValue.fObject : NULL;
503 }
504
505 // -------------------------------------
506 // Sets the value to a double value d.
507
508 void
setDouble(double d)509 Formattable::setDouble(double d)
510 {
511 dispose();
512 fType = kDouble;
513 fValue.fDouble = d;
514 }
515
516 // -------------------------------------
517 // Sets the value to a long value l.
518
519 void
setLong(int32_t l)520 Formattable::setLong(int32_t l)
521 {
522 dispose();
523 fType = kLong;
524 fValue.fInt64 = l;
525 }
526
527 // -------------------------------------
528 // Sets the value to an int64 value ll.
529
530 void
setInt64(int64_t ll)531 Formattable::setInt64(int64_t ll)
532 {
533 dispose();
534 fType = kInt64;
535 fValue.fInt64 = ll;
536 }
537
538 // -------------------------------------
539 // Sets the value to a Date instance d.
540
541 void
setDate(UDate d)542 Formattable::setDate(UDate d)
543 {
544 dispose();
545 fType = kDate;
546 fValue.fDate = d;
547 }
548
549 // -------------------------------------
550 // Sets the value to a string value stringToCopy.
551
552 void
setString(const UnicodeString & stringToCopy)553 Formattable::setString(const UnicodeString& stringToCopy)
554 {
555 dispose();
556 fType = kString;
557 fValue.fString = new UnicodeString(stringToCopy);
558 }
559
560 // -------------------------------------
561 // Sets the value to an array of Formattable objects.
562
563 void
setArray(const Formattable * array,int32_t count)564 Formattable::setArray(const Formattable* array, int32_t count)
565 {
566 dispose();
567 fType = kArray;
568 fValue.fArrayAndCount.fArray = createArrayCopy(array, count);
569 fValue.fArrayAndCount.fCount = count;
570 }
571
572 // -------------------------------------
573 // Adopts the stringToAdopt value.
574
575 void
adoptString(UnicodeString * stringToAdopt)576 Formattable::adoptString(UnicodeString* stringToAdopt)
577 {
578 dispose();
579 fType = kString;
580 fValue.fString = stringToAdopt;
581 }
582
583 // -------------------------------------
584 // Adopts the array value and its count.
585
586 void
adoptArray(Formattable * array,int32_t count)587 Formattable::adoptArray(Formattable* array, int32_t count)
588 {
589 dispose();
590 fType = kArray;
591 fValue.fArrayAndCount.fArray = array;
592 fValue.fArrayAndCount.fCount = count;
593 }
594
595 void
adoptObject(UObject * objectToAdopt)596 Formattable::adoptObject(UObject* objectToAdopt) {
597 dispose();
598 fType = kObject;
599 fValue.fObject = objectToAdopt;
600 }
601
602 // -------------------------------------
603 UnicodeString&
getString(UnicodeString & result,UErrorCode & status) const604 Formattable::getString(UnicodeString& result, UErrorCode& status) const
605 {
606 if (fType != kString) {
607 setError(status, U_INVALID_FORMAT_ERROR);
608 result.setToBogus();
609 } else {
610 if (fValue.fString == NULL) {
611 setError(status, U_MEMORY_ALLOCATION_ERROR);
612 } else {
613 result = *fValue.fString;
614 }
615 }
616 return result;
617 }
618
619 // -------------------------------------
620 const UnicodeString&
getString(UErrorCode & status) const621 Formattable::getString(UErrorCode& status) const
622 {
623 if (fType != kString) {
624 setError(status, U_INVALID_FORMAT_ERROR);
625 return *getBogus();
626 }
627 if (fValue.fString == NULL) {
628 setError(status, U_MEMORY_ALLOCATION_ERROR);
629 return *getBogus();
630 }
631 return *fValue.fString;
632 }
633
634 // -------------------------------------
635 UnicodeString&
getString(UErrorCode & status)636 Formattable::getString(UErrorCode& status)
637 {
638 if (fType != kString) {
639 setError(status, U_INVALID_FORMAT_ERROR);
640 return *getBogus();
641 }
642 if (fValue.fString == NULL) {
643 setError(status, U_MEMORY_ALLOCATION_ERROR);
644 return *getBogus();
645 }
646 return *fValue.fString;
647 }
648
649 // -------------------------------------
650 const Formattable*
getArray(int32_t & count,UErrorCode & status) const651 Formattable::getArray(int32_t& count, UErrorCode& status) const
652 {
653 if (fType != kArray) {
654 setError(status, U_INVALID_FORMAT_ERROR);
655 count = 0;
656 return NULL;
657 }
658 count = fValue.fArrayAndCount.fCount;
659 return fValue.fArrayAndCount.fArray;
660 }
661
662 // -------------------------------------
663 // Gets the bogus string, ensures mondo bogosity.
664
665 UnicodeString*
getBogus() const666 Formattable::getBogus() const
667 {
668 return (UnicodeString*)&fBogus; /* cast away const :-( */
669 }
670
671
672 // --------------------------------------
getDecimalNumber(UErrorCode & status)673 StringPiece Formattable::getDecimalNumber(UErrorCode &status) {
674 if (U_FAILURE(status)) {
675 return "";
676 }
677 if (fDecimalStr != NULL) {
678 return fDecimalStr->toStringPiece();
679 }
680
681 if (fDecimalNum == NULL) {
682 // No decimal number for the formattable yet. Which means the value was
683 // set directly by the user as an int, int64 or double. If the value came
684 // from parsing, or from the user setting a decimal number, fDecimalNum
685 // would already be set.
686 //
687 fDecimalNum = new DigitList;
688 if (fDecimalNum == NULL) {
689 status = U_MEMORY_ALLOCATION_ERROR;
690 return "";
691 }
692
693 switch (fType) {
694 case kDouble:
695 fDecimalNum->set(this->getDouble());
696 break;
697 case kLong:
698 fDecimalNum->set(this->getLong());
699 break;
700 case kInt64:
701 fDecimalNum->set(this->getInt64());
702 break;
703 default:
704 // The formattable's value is not a numeric type.
705 status = U_INVALID_STATE_ERROR;
706 return "";
707 }
708 }
709
710 fDecimalStr = new CharString;
711 if (fDecimalStr == NULL) {
712 status = U_MEMORY_ALLOCATION_ERROR;
713 return "";
714 }
715 fDecimalNum->getDecimal(*fDecimalStr, status);
716
717 return fDecimalStr->toStringPiece();
718 }
719
720
721
722 // ---------------------------------------
723 void
adoptDigitList(DigitList * dl)724 Formattable::adoptDigitList(DigitList *dl) {
725 dispose();
726
727 fDecimalNum = dl;
728
729 // Set the value into the Union of simple type values.
730 // Cannot use the set() functions because they would delete the fDecimalNum value,
731
732 if (fDecimalNum->fitsIntoLong(FALSE)) {
733 fType = kLong;
734 fValue.fInt64 = fDecimalNum->getLong();
735 } else if (fDecimalNum->fitsIntoInt64(FALSE)) {
736 fType = kInt64;
737 fValue.fInt64 = fDecimalNum->getInt64();
738 } else {
739 fType = kDouble;
740 fValue.fDouble = fDecimalNum->getDouble();
741 }
742 }
743
744
745 // ---------------------------------------
746 void
setDecimalNumber(const StringPiece & numberString,UErrorCode & status)747 Formattable::setDecimalNumber(const StringPiece &numberString, UErrorCode &status) {
748 if (U_FAILURE(status)) {
749 return;
750 }
751 dispose();
752
753 // Copy the input string and nul-terminate it.
754 // The decNumber library requires nul-terminated input. StringPiece input
755 // is not guaranteed nul-terminated. Too bad.
756 // CharString automatically adds the nul.
757 DigitList *dnum = new DigitList();
758 if (dnum == NULL) {
759 status = U_MEMORY_ALLOCATION_ERROR;
760 return;
761 }
762 dnum->set(CharString(numberString, status).toStringPiece(), status);
763 if (U_FAILURE(status)) {
764 delete dnum;
765 return; // String didn't contain a decimal number.
766 }
767 adoptDigitList(dnum);
768
769 // Note that we do not hang on to the caller's input string.
770 // If we are asked for the string, we will regenerate one from fDecimalNum.
771 }
772
773 #if 0
774 //----------------------------------------------------
775 // console I/O
776 //----------------------------------------------------
777 #ifdef _DEBUG
778
779 #if U_IOSTREAM_SOURCE >= 199711
780 #include <iostream>
781 using namespace std;
782 #elif U_IOSTREAM_SOURCE >= 198506
783 #include <iostream.h>
784 #endif
785
786 #include "unicode/datefmt.h"
787 #include "unistrm.h"
788
789 class FormattableStreamer /* not : public UObject because all methods are static */ {
790 public:
791 static void streamOut(ostream& stream, const Formattable& obj);
792
793 private:
794 FormattableStreamer() {} // private - forbid instantiation
795 };
796
797 // This is for debugging purposes only. This will send a displayable
798 // form of the Formattable object to the output stream.
799
800 void
801 FormattableStreamer::streamOut(ostream& stream, const Formattable& obj)
802 {
803 static DateFormat *defDateFormat = 0;
804
805 UnicodeString buffer;
806 switch(obj.getType()) {
807 case Formattable::kDate :
808 // Creates a DateFormat instance for formatting the
809 // Date instance.
810 if (defDateFormat == 0) {
811 defDateFormat = DateFormat::createInstance();
812 }
813 defDateFormat->format(obj.getDate(), buffer);
814 stream << buffer;
815 break;
816 case Formattable::kDouble :
817 // Output the double as is.
818 stream << obj.getDouble() << 'D';
819 break;
820 case Formattable::kLong :
821 // Output the double as is.
822 stream << obj.getLong() << 'L';
823 break;
824 case Formattable::kString:
825 // Output the double as is. Please see UnicodeString console
826 // I/O routine for more details.
827 stream << '"' << obj.getString(buffer) << '"';
828 break;
829 case Formattable::kArray:
830 int32_t i, count;
831 const Formattable* array;
832 array = obj.getArray(count);
833 stream << '[';
834 // Recursively calling the console I/O routine for each element in the array.
835 for (i=0; i<count; ++i) {
836 FormattableStreamer::streamOut(stream, array[i]);
837 stream << ( (i==(count-1)) ? "" : ", " );
838 }
839 stream << ']';
840 break;
841 default:
842 // Not a recognizable Formattable object.
843 stream << "INVALID_Formattable";
844 }
845 stream.flush();
846 }
847 #endif
848
849 #endif
850
851 U_NAMESPACE_END
852
853 #endif /* #if !UCONFIG_NO_FORMATTING */
854
855 //eof
856