home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Programming / ICU / src / icu / source / i18n / msgfmt.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-19  |  36.6 KB  |  1,141 lines

  1. /*
  2. ********************************************************************************
  3. *                                                                              *
  4. * COPYRIGHT:                                                                   *
  5. *   (C) Copyright Taligent, Inc.,  1997                                        *
  6. *   (C) Copyright International Business Machines Corporation,  1997-1998      *
  7. *   Licensed Material - Program-Property of IBM - All Rights Reserved.         *
  8. *   US Government Users Restricted Rights - Use, duplication, or disclosure    *
  9. *   restricted by GSA ADP Schedule Contract with IBM Corp.                     *
  10. *                                                                              *
  11. ********************************************************************************
  12. *
  13. * File MSGFMT.CPP
  14. *
  15. * Modification History:
  16. *
  17. *   Date        Name        Description
  18. *   02/19/97    aliu        Converted from java.
  19. *   03/20/97    helena      Finished first cut of implementation.
  20. *   04/10/97    aliu        Made to work on AIX.  Added stoi to replace wtoi.
  21. *   06/11/97    helena      Fixed addPattern to take the pattern correctly.
  22. *   06/17/97    helena      Fixed the getPattern to return the correct pattern.
  23. *   07/09/97    helena      Made ParsePosition into a class.
  24. *   02/22/99    stephen     Removed character literals for EBCDIC safety
  25. ********************************************************************************
  26. */
  27.  
  28. #include "msgfmt.h"
  29. #include "decimfmt.h"
  30. #include "datefmt.h"
  31. #include "smpdtfmt.h"
  32. #include "choicfmt.h"
  33. #include "mutex.h"
  34.  
  35. // *****************************************************************************
  36. // class MessageFormat
  37. // *****************************************************************************
  38.  
  39. // -------------------------------------
  40. char MessageFormat::fgClassID = 0; // Value is irrelevant
  41.  
  42. // This global NumberFormat instance is shared by all MessageFormat to 
  43. // convert a number to(format)/from(parse) a string.
  44. NumberFormat* MessageFormat::fgNumberFormat = 0;
  45.  
  46. // -------------------------------------
  47. // Creates a MessageFormat instance based on the pattern.
  48.  
  49. MessageFormat::MessageFormat(const UnicodeString& pattern,
  50.                              UErrorCode& success)
  51. : fOffsets(NULL),
  52.   fArgumentNumbers(NULL),
  53.   fLocale(Locale::getDefault()),  // Uses the default locale
  54.   fCount(0)
  55. {
  56.     fCount = kMaxFormat;
  57.     fOffsets = new int32_t[fCount];
  58.     fArgumentNumbers = new int32_t[fCount];
  59.     for (int32_t i = 0; i < fCount; i++) {
  60.         fFormats[i] = NULL;       // Format instances
  61.         fOffsets[i] = 0;          // Starting offset
  62.         fArgumentNumbers[i] = 0;  // Argument numbers.
  63.     }
  64.     applyPattern(pattern, success);
  65. }
  66.  
  67. MessageFormat::MessageFormat(const UnicodeString& pattern,
  68.                              const Locale& newLocale,
  69.                              UErrorCode& success)
  70. : fOffsets(NULL),
  71.   fArgumentNumbers(NULL),
  72.   fLocale(newLocale),  // Uses the default locale
  73.   fCount(0)
  74. {
  75.     fCount = kMaxFormat;
  76.     fOffsets = new int32_t[fCount];
  77.     fArgumentNumbers = new int32_t[fCount];
  78.     for (int32_t i = 0; i < fCount; i++) {
  79.         fFormats[i] = NULL;       // Format instances
  80.         fOffsets[i] = 0;          // Starting offset
  81.         fArgumentNumbers[i] = 0;  // Argument numbers.
  82.     }
  83.     applyPattern(pattern, success);
  84. }
  85.  
  86. MessageFormat::~MessageFormat()
  87. {
  88.     for (int32_t i = 0; i < fCount; i++)
  89.         delete fFormats[i];
  90.     delete [] fOffsets;
  91.     delete [] fArgumentNumbers;
  92.     fCount = 0;
  93. }
  94.  
  95. // -------------------------------------
  96. // copy constructor
  97.  
  98. MessageFormat::MessageFormat(const MessageFormat& that)
  99.     : Format(that),
  100.       fOffsets(NULL),
  101.       fCount(that.fCount),
  102.       fLocale(that.fLocale),
  103.       fMaxOffset(that.fMaxOffset),
  104.       fArgumentNumbers(NULL),
  105.       fPattern(that.fPattern)
  106. {
  107.     fOffsets = new int32_t[fCount];
  108.     fArgumentNumbers = new int32_t[fCount];
  109.     // Sets up the format instance array, offsets and argument numbers.
  110.     for (int32_t i = 0; i < fCount; i++) {
  111.         fFormats[i] = NULL; // init since delete may be called
  112.         if (that.fFormats[i] != NULL) {
  113.             setFormat(i, *(that.fFormats[i]) );  // setFormat clones the format
  114.         }
  115.         fOffsets[i] = that.fOffsets[i];
  116.         fArgumentNumbers[i] = that.fArgumentNumbers[i];
  117.     }
  118. }
  119.  
  120. // -------------------------------------
  121. // assignment operator
  122.  
  123. const MessageFormat&
  124. MessageFormat::operator=(const MessageFormat& that)
  125. {
  126.     if (this != &that) {
  127.         // Calls the super class for assignment first.
  128.         Format::operator=(that);
  129.         // Cleans up the format array and the offsets, argument numbers.
  130.         for (int32_t j = 0; j < fCount; j++) {
  131.             delete fFormats[j];
  132.             fFormats[j] = NULL;
  133.         }
  134.         delete [] fOffsets; fOffsets = NULL;
  135.         delete [] fArgumentNumbers; fArgumentNumbers = NULL;
  136.         fPattern = that.fPattern;
  137.         fLocale = that.fLocale;
  138.         fCount = that.fCount;
  139.         fMaxOffset = that.fMaxOffset;
  140.         fOffsets = new int32_t[fCount];
  141.         fArgumentNumbers = new int32_t[fCount];
  142.         // Sets up the format instance array, offsets and argument numbers.
  143.         for (int32_t i = 0; i < fCount; i++) {
  144.             if (that.fFormats[i] == NULL) {
  145.                 fFormats[i] = NULL;
  146.             }else{
  147.                 adoptFormat(i, that.fFormats[i]->clone());
  148.             }
  149.             fOffsets[i] = that.fOffsets[i];
  150.             fArgumentNumbers[i] = that.fArgumentNumbers[i];
  151.         }
  152.     }
  153.     return *this;
  154. }
  155.  
  156. bool_t
  157. MessageFormat::operator==(const Format& that) const 
  158. {
  159.     if (this == &that) return TRUE;
  160.     // Are the instances derived from the same Format class?
  161.     if (getStaticClassID() != that.getDynamicClassID()) return FALSE;  // not the same class
  162.     // Calls the super class for equality check first.
  163.     if (!Format::operator==(that)) return FALSE;
  164.     MessageFormat& thatAlias = (MessageFormat&)that;
  165.     // Checks the pattern, locale and array count of this MessageFormat object.
  166.     if (fMaxOffset != thatAlias.fMaxOffset) return FALSE;
  167.     if (fPattern != thatAlias.fPattern) return FALSE;
  168.     if (fLocale != thatAlias.fLocale) return FALSE;
  169.     if (fCount != thatAlias.fCount) return FALSE;
  170.     // Checks each element in the arrays for equality last.
  171.     for (int32_t i = 0; i < fCount; i++) {
  172.         if ((fFormats[i] != thatAlias.fFormats[i]) ||
  173.             (fOffsets[i] != thatAlias.fOffsets[i]) ||
  174.             (fArgumentNumbers[i] != thatAlias.fArgumentNumbers[i]))
  175.             return FALSE;
  176.     }
  177.     return TRUE;
  178. }
  179.  
  180. // -------------------------------------
  181. // Creates a copy of this MessageFormat, the caller owns the copy.
  182.  
  183. Format*
  184. MessageFormat::clone() const
  185. {
  186.     MessageFormat *aCopy = new MessageFormat(*this);
  187.     return aCopy;
  188. }
  189.  
  190. // -------------------------------------
  191. // Sets the locale of this MessageFormat object to theLocale.
  192.  
  193. void
  194. MessageFormat::setLocale(const Locale& theLocale)
  195. {
  196.     fLocale = theLocale;
  197. }
  198.  
  199. // -------------------------------------
  200. // Gets the locale of this MessageFormat object.
  201.  
  202. const Locale&
  203. MessageFormat::getLocale() const
  204. {
  205.     return fLocale;
  206. }
  207.  
  208. // -------------------------------------
  209. // Applies the new pattern and returns an error if the pattern
  210. // is not correct.
  211. // For example, consider the pattern, 
  212. // "There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files}"
  213. // The segments would look like the following,
  214. // segments[0] == "There "
  215. // segments[1] == "0"
  216. // segments[2] == "{0,choice,0#are no files|1#is one file|1<are {0,number,integer}"
  217. // segments[3] == " files"
  218.  
  219. void
  220. MessageFormat::applyPattern(const UnicodeString& newPattern, 
  221.                             UErrorCode& success)
  222. {
  223.     UnicodeString segments[4];
  224.     int32_t part = 0;
  225.     int32_t formatNumber = 0;
  226.     bool_t inQuote = FALSE;
  227.     int32_t braceStack = 0;
  228.     fMaxOffset = -1;
  229.     for (int i = 0; i < newPattern.size(); ++i) {
  230.         UChar ch = newPattern[i];
  231.         if (part == 0) {
  232.             if (ch == 0x0027 /*'\''*/) {
  233.                 if (i + 1 < newPattern.size()
  234.                     && newPattern[i+1] == 0x0027 /*'\''*/) {
  235.                     segments[part] += ch;  // handle doubles
  236.                     ++i;
  237.                 } else {
  238.                     inQuote = !inQuote;
  239.                 }
  240.             } else if (ch == 0x007B /*'{'*/ && !inQuote) {
  241.                 part = 1;
  242.             } else {
  243.                 segments[part] += ch;
  244.             }
  245.         } else  if (inQuote) {              // just copy quotes in parts
  246.             segments[part] += ch;
  247.             if (ch == 0x0027 /*'\''*/) {
  248.                 inQuote = FALSE;
  249.             }
  250.         } else {
  251.             switch (ch) {
  252.             case 0x002C /*','*/:
  253.                 if (part < 3)
  254.                     part += 1;
  255.                 else
  256.                     segments[part] += ch;
  257.                 break;
  258.             case 0x007B /*'{'*/:
  259.                 ++braceStack;
  260.                 segments[part] += ch;
  261.                 break;
  262.             case 0x007D /*'}'*/:
  263.                 if (braceStack == 0) {
  264.                     part = 0;
  265.                     makeFormat(i, formatNumber, segments, success);
  266.                     if(U_FAILURE(success))
  267.                         return;
  268.                     formatNumber++;
  269.                 } else {
  270.                     --braceStack;
  271.                     segments[part] += ch;
  272.                 }
  273.                 break;
  274.             case 0x0027 /*'\''*/:
  275.                 inQuote = TRUE;
  276.                 // fall through, so we keep quotes in other parts
  277.             default:
  278.                 segments[part] += ch;
  279.                 break;
  280.             }
  281.         }
  282.     }
  283.     if (braceStack == 0 && part != 0) {
  284.         fMaxOffset = -1;
  285.         success = U_INVALID_FORMAT_ERROR;
  286.         return;
  287.         //throw new IllegalArgumentException("Unmatched braces in the pattern.");
  288.     }
  289.     fPattern = segments[0];
  290. }
  291.  
  292. // -------------------------------------
  293. // Converts this MessageFormat instance to a pattern. 
  294. UnicodeString&
  295. MessageFormat::toPattern(UnicodeString& result) const
  296. {
  297.   // later, make this more extensible
  298.   int32_t lastOffset = 0;
  299.   for (int i = 0; i <= fMaxOffset; ++i) {
  300.     copyAndFixQuotes(fPattern, lastOffset, fOffsets[i], result);
  301.     lastOffset = fOffsets[i];
  302.     result += 0x007B /*'{'*/;
  303.     // {sfb} check this later
  304.     //result += (UChar) (fArgumentNumbers[i] + '0');
  305.     UnicodeString temp;
  306.     result += itos(fArgumentNumbers[i], temp);
  307.     if (fFormats[i] == NULL) {
  308.       // do nothing, string format
  309.     } 
  310.     else if (fFormats[i]->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
  311.       
  312.       UErrorCode status = U_ZERO_ERROR;
  313.       NumberFormat& formatAlias = *(NumberFormat*)fFormats[i];
  314.       NumberFormat *numberTemplate = NumberFormat::createInstance(fLocale, status);
  315.       NumberFormat *currencyTemplate = NumberFormat::createCurrencyInstance(fLocale, status);
  316.       NumberFormat *percentTemplate = NumberFormat::createPercentInstance(fLocale, status);
  317.       NumberFormat *integerTemplate = createIntegerFormat(fLocale, status);
  318.       
  319.       if (formatAlias == *numberTemplate) {
  320.     result += ",number";
  321.       } 
  322.       else if (formatAlias == *currencyTemplate) {
  323.     result += ",number,currency";
  324.       } 
  325.       else if (formatAlias == *percentTemplate) {
  326.     result += ",number,percent";
  327.       } 
  328.       else if (formatAlias == *integerTemplate) {
  329.     result += ",number,integer";
  330.       } 
  331.       else {
  332.     UnicodeString buffer;
  333.     result += ",number,";
  334.     result += ((DecimalFormat*)fFormats[i])->toPattern(buffer);
  335.       }
  336.       
  337.       delete numberTemplate;
  338.       delete currencyTemplate;
  339.       delete percentTemplate;
  340.       delete integerTemplate;
  341.     } 
  342.     else if (fFormats[i]->getDynamicClassID() == SimpleDateFormat::getStaticClassID()) {
  343.       UErrorCode success = U_ZERO_ERROR;
  344.       DateFormat& formatAlias = *(DateFormat*)fFormats[i];
  345.       DateFormat *defaultDateTemplate = DateFormat::createDateInstance(DateFormat::kDefault, fLocale);
  346.       DateFormat *shortDateTemplate = DateFormat::createDateInstance(DateFormat::kShort, fLocale);
  347.       DateFormat *longDateTemplate = DateFormat::createDateInstance(DateFormat::kLong, fLocale);
  348.       DateFormat *fullDateTemplate = DateFormat::createDateInstance(DateFormat::kFull, fLocale);
  349.       DateFormat *defaultTimeTemplate = DateFormat::createTimeInstance(DateFormat::kDefault, fLocale);
  350.       DateFormat *shortTimeTemplate = DateFormat::createTimeInstance(DateFormat::kShort, fLocale);
  351.       DateFormat *longTimeTemplate = DateFormat::createTimeInstance(DateFormat::kLong, fLocale);
  352.       DateFormat *fullTimeTemplate = DateFormat::createTimeInstance(DateFormat::kFull, fLocale);
  353.       
  354.       
  355.       if (formatAlias == *defaultDateTemplate) {
  356.     result += ",date";
  357.       } 
  358.       else if (formatAlias == *shortDateTemplate) {
  359.     result += ",date,short";
  360.       } 
  361.       else if (formatAlias == *defaultDateTemplate) {
  362.     result += ",date,medium";
  363.       } 
  364.       else if (formatAlias == *longDateTemplate) {
  365.     result += ",date,long";
  366.       } 
  367.       else if (formatAlias == *fullDateTemplate) {
  368.     result += ",date,full";
  369.       } 
  370.       else if (formatAlias == *defaultTimeTemplate) {
  371.     result += ",time";
  372.       } 
  373.       else if (formatAlias == *shortTimeTemplate) {
  374.     result += ",time,short";
  375.       } 
  376.       else if (formatAlias == *defaultTimeTemplate) {
  377.     result += ",time,medium";
  378.       } 
  379.       else if (formatAlias == *longTimeTemplate) {
  380.     result += ",time,long";
  381.       } 
  382.       else if (formatAlias == *fullTimeTemplate) {
  383.     result += ",time,full";
  384.       } 
  385.       else {
  386.     UnicodeString buffer;
  387.     result += ",date,";
  388.     result += ((SimpleDateFormat*)fFormats[i])->toPattern(buffer);
  389.       }
  390.       
  391.       delete defaultDateTemplate;
  392.       delete shortDateTemplate;
  393.       delete longDateTemplate;
  394.       delete fullDateTemplate;
  395.       delete defaultTimeTemplate;
  396.       delete shortTimeTemplate;
  397.       delete longTimeTemplate;
  398.       delete fullTimeTemplate;
  399.       // {sfb} there should be a more efficient way to do this!
  400.     } 
  401.     else if (fFormats[i]->getDynamicClassID() == ChoiceFormat::getStaticClassID()) {
  402.       UnicodeString buffer;
  403.       result += ",choice,";
  404.       result += ((ChoiceFormat*)fFormats[i])->toPattern(buffer);
  405.     } 
  406.     else {
  407.       //result += ", unknown";
  408.     }
  409.     result += 0x007D /*'}'*/;
  410.   }
  411.   copyAndFixQuotes(fPattern, lastOffset, fPattern.size(), result);
  412.   return result;
  413. }
  414.  
  415. // -------------------------------------
  416. // Adopts the new formats array and updates the array count.
  417. // This MessageFormat instance owns the new formats.
  418.  
  419. void
  420. MessageFormat::adoptFormats(Format** newFormats,
  421.                             int32_t cnt)
  422. {
  423.     if(newFormats == NULL || cnt < 0)
  424.         return;
  425.     
  426.     int32_t i;
  427.     // Cleans up first.
  428.     for (i = 0; i < fCount; i++)
  429.         delete fFormats[i];
  430.     fCount = (cnt > kMaxFormat) ? kMaxFormat : cnt;
  431.     for (i = 0; i < fCount; i++)
  432.         fFormats[i] = newFormats[i];
  433.     for (i = kMaxFormat; i < cnt; i++) 
  434.         delete newFormats[i];
  435. }   
  436. // -------------------------------------
  437. // Sets the new formats array and updates the array count.
  438. // This MessageFormat instance maks a copy of the new formats.
  439.  
  440. void
  441. MessageFormat::setFormats(const Format** newFormats,
  442.                             int32_t cnt)
  443. {
  444.     if(newFormats == NULL || cnt < 0)
  445.         return;
  446.  
  447.     int32_t i;
  448.     // Cleans up first.
  449.     for (i = 0; i < fCount; i++)
  450.         delete fFormats[i];
  451.     fCount = (cnt > kMaxFormat) ? kMaxFormat : cnt;
  452.     for (i = 0; i < fCount; i++)
  453.         if (newFormats[i] == NULL) {
  454.             fFormats[i] = NULL;
  455.         }
  456.         else{
  457.             fFormats[i] = newFormats[i]->clone();
  458.         }
  459. }   
  460.  
  461. // -------------------------------------
  462. // Adopts the first *variable* formats in the format array.
  463. // This MessageFormat instance owns the new formats.
  464. // Do nothing is the variable is not less than the array count.
  465.  
  466. void
  467. MessageFormat::adoptFormat(int32_t variable, Format *newFormat)
  468. {
  469.     if(variable < 0)
  470.         return;
  471.         
  472.     if (variable < fCount) {
  473.         // Deletes the old formats.
  474.         delete fFormats[variable];
  475.         fFormats[variable] = newFormat;
  476.     }
  477. }
  478.  
  479. // -------------------------------------
  480. // Sets the first *variable* formats in the format array, this
  481. // MessageFormat instance makes copies of the new formats.
  482. // Do nothing is the variable is not less than the array count.
  483.  
  484. void
  485. MessageFormat::setFormat(int32_t variable, const Format& newFormat)
  486. {
  487.     if (variable < fCount) {
  488.         delete fFormats[variable];
  489.         if (&(newFormat) == NULL) {
  490.             fFormats[variable] = NULL;
  491.         }
  492.         else{
  493.             fFormats[variable] = newFormat.clone();
  494.         }
  495.     }
  496. }
  497.  
  498. // -------------------------------------
  499. // Gets the format array.
  500.  
  501. const Format**
  502. MessageFormat::getFormats(int32_t& cnt) const
  503. {
  504.     cnt = fCount;
  505.     return (const Format**)fFormats;
  506. }
  507.  
  508. // -------------------------------------
  509. // Formats the source Formattable array and copy into the result buffer.
  510. // Ignore the FieldPosition result for error checking.
  511.  
  512. UnicodeString&
  513. MessageFormat::format(const Formattable* source,
  514.                       int32_t cnt, 
  515.                       UnicodeString& result, 
  516.                       FieldPosition& ignore, 
  517.                       UErrorCode& success) const
  518. {
  519.     if (U_FAILURE(success)) 
  520.         return result;
  521.     
  522.     return format(source, cnt, result, ignore, 0, success);
  523. }
  524.  
  525. // -------------------------------------
  526. // Internally creates a MessageFormat instance based on the
  527. // pattern and formats the arguments Formattable array and 
  528. // copy into the result buffer.
  529.  
  530. UnicodeString&
  531. MessageFormat::format(  const UnicodeString& pattern,
  532.                         const Formattable* arguments,
  533.                         int32_t cnt,
  534.                         UnicodeString& result, 
  535.                         UErrorCode& success)
  536. {
  537.     // {sfb} why does this use a local when so many other places use a static?
  538.     MessageFormat *temp = new MessageFormat(pattern, success);
  539.     if (U_FAILURE(success)) 
  540.         return result;
  541.     FieldPosition ignore(0);
  542.     temp->format(arguments, cnt, result, ignore, success);
  543.     delete temp;
  544.     return result;
  545. }
  546.  
  547. // -------------------------------------
  548. // Formats the source Formattable object and copy into the 
  549. // result buffer.  The Formattable object must be an array
  550. // of Formattable instances, returns error otherwise.
  551.  
  552. UnicodeString&
  553. MessageFormat::format(const Formattable& source, 
  554.                       UnicodeString& result, 
  555.                       FieldPosition& ignore, 
  556.                       UErrorCode& success) const
  557. {
  558.     int32_t cnt;
  559.  
  560.     if (U_FAILURE(success)) 
  561.         return result;
  562.     if (source.getType() != Formattable::kArray) {
  563.         success = U_ILLEGAL_ARGUMENT_ERROR;
  564.         return result;
  565.     }
  566.     const Formattable* tmpPtr = source.getArray(cnt);
  567.     
  568.     return format(tmpPtr, cnt, result, ignore, 0, success);
  569. }
  570.  
  571. // -------------------------------------
  572. // Formats the arguments Formattable array and copy into the result buffer.
  573. // Ignore the FieldPosition result for error checking.
  574.  
  575. UnicodeString&
  576. MessageFormat::format(const Formattable* arguments, 
  577.                       int32_t cnt, 
  578.                       UnicodeString& result, 
  579.                       FieldPosition& status, 
  580.                       int32_t recursionProtection,
  581.                       UErrorCode& success) const 
  582. {
  583.     if(/*arguments == NULL ||*/ cnt < 0) {
  584.         success = U_ILLEGAL_ARGUMENT_ERROR;
  585.         return result;
  586.     }
  587.     
  588.     UnicodeString buffer;
  589.     
  590.     int32_t lastOffset = 0;
  591.     for (int32_t i = 0; i <= fMaxOffset;++i) {
  592.         // Cleans up the temp buffer for each formattable arguments.
  593.         buffer.remove();
  594.         // Append the prefix of current format element.
  595.         fPattern.extract(lastOffset, fOffsets[i] - lastOffset, buffer);
  596.     result += buffer;
  597.         lastOffset = fOffsets[i];
  598.         int32_t argumentNumber = fArgumentNumbers[i];
  599.         // Checks the scope of the argument number.
  600.         if (argumentNumber >= cnt) {
  601.             /*success = U_ILLEGAL_ARGUMENT_ERROR;
  602.             return result;*/
  603.             result += "{";
  604.             UnicodeString temp;
  605.             result += itos(argumentNumber, temp);
  606.             result += "}";
  607.             continue;
  608.         }
  609.  
  610.         Formattable obj = arguments[argumentNumber];
  611.         UnicodeString arg;
  612.         bool_t tryRecursion = FALSE;
  613.         // Recursively calling the format process only if the current format argument
  614.         // refers to a ChoiceFormat object.
  615.         if (fFormats[i] != NULL) {
  616.             fFormats[i]->format(obj, arg, success);
  617.             tryRecursion = (fFormats[i]->getDynamicClassID() == ChoiceFormat::getStaticClassID());
  618.         }
  619.         // If the obj data type if a number, use a NumberFormat instance.
  620.         else if ((obj.getType() == Formattable::kDouble) ||
  621.                  (obj.getType() == Formattable::kLong)) {
  622.             NumberFormat *numTemplate = NULL;
  623.             numTemplate = NumberFormat::createInstance(fLocale, success);
  624.             if (U_FAILURE(success)) { 
  625.                 delete numTemplate; 
  626.                 return result; 
  627.             }
  628.             numTemplate->format((obj.getType() == Formattable::kDouble) ? obj.getDouble() : obj.getLong(), arg);
  629.             delete numTemplate;
  630.             if (U_FAILURE(success)) 
  631.                 return result;
  632.         }
  633.         // If the obj data type is a Date instance, use a DateFormat instance.
  634.         else if (obj.getType() == Formattable::kDate) {
  635.             DateFormat *dateTemplate = NULL;
  636.             dateTemplate = DateFormat::createDateTimeInstance(DateFormat::kShort, DateFormat::kShort, fLocale);
  637.             dateTemplate->format(obj.getDate(), arg);
  638.             delete dateTemplate;
  639.         }
  640.         else if (obj.getType() == Formattable::kString) {
  641.             obj.getString(arg);
  642.         }
  643.         else {
  644. #ifdef LIUDEBUG  
  645.             cerr << "Unknown object of type:" << obj.getType() << endl;
  646. #endif
  647.             success = U_ILLEGAL_ARGUMENT_ERROR;
  648.             return result;
  649.         }
  650.         // Needs to reprocess the ChoiceFormat option by using the MessageFormat
  651.         // pattern application.
  652.         if (tryRecursion && arg.indexOf("{") >= 0) {
  653.             MessageFormat *temp = NULL;
  654.             temp = new MessageFormat(arg, fLocale, success);
  655.             if (U_FAILURE(success)) 
  656.                 return result;
  657.             temp->format(arguments, cnt, result, status, recursionProtection, success);
  658.             if (U_FAILURE(success)) { 
  659.                 delete temp; 
  660.                 return result; 
  661.             }
  662.             delete temp;
  663.         }
  664.         else {
  665.             result += arg;
  666.         }
  667.     }
  668.     buffer.remove();
  669.     // Appends the rest of the pattern characters after the real last offset.
  670.     fPattern.extract(lastOffset, fPattern.size(), buffer);
  671.     result += buffer;
  672.     return result;
  673. }
  674.  
  675. // MessageFormat Type List  Number, Date, Time or Choice
  676. const UnicodeString MessageFormat::fgTypeList[] = {
  677.     "", "", "number", "", "date", "", "time", "", "choice"
  678. };
  679.  
  680. // NumberFormat modifier list, default, currency, percent or integer
  681. const UnicodeString MessageFormat::fgModifierList[] = {
  682.     "", "", "currency", "", "percent", "", "integer", "", ""
  683. };
  684.  
  685. // DateFormat modifier list, default, short, medium, long or full
  686. const UnicodeString MessageFormat::fgDateModifierList[] = {
  687.     "", "", "short", "", "medium", "", "long", "", "full"
  688. };
  689.  
  690. const int32_t MessageFormat::fgListLength= 9;
  691.  
  692. // -------------------------------------
  693. // Parses the source pattern and returns the Formattable objects array,
  694. // the array count and the ending parse position.  The caller of this method 
  695. // owns the array.
  696.  
  697. Formattable*
  698. MessageFormat::parse(const UnicodeString& source, 
  699.                      ParsePosition& status,
  700.                      int32_t& count) const
  701. {
  702.   Formattable *resultArray = new Formattable[kMaxFormat];
  703.   int32_t patternOffset = 0;
  704.   int32_t sourceOffset = status.getIndex();
  705.   ParsePosition tempStatus(0);
  706.   count = 0; // {sfb} reset to zero
  707.   for (int32_t i = 0; i <= fMaxOffset; ++i) {
  708.     // match up to format
  709.     int32_t len = fOffsets[i] - patternOffset;
  710.     if (len == 0 || 
  711.     fPattern.compare(patternOffset, len, source, sourceOffset, len) == 0) {
  712.       sourceOffset += len;
  713.       patternOffset += len;
  714.     } 
  715.     else {
  716.       status.setErrorIndex(sourceOffset);
  717.       delete [] resultArray;
  718.       count = 0;
  719.       return NULL; // leave index as is to signal error
  720.     }
  721.  
  722.     // now use format
  723.     if (fFormats[i] == NULL) {   // string format
  724.       // if at end, use longest possible match
  725.       // otherwise uses first match to intervening string
  726.       // does NOT recursively try all possibilities
  727.       int32_t tempLength = (i != fMaxOffset) ? fOffsets[i+1] : fPattern.size();
  728.  
  729.       int32_t next;
  730.       if (patternOffset >= tempLength) {
  731.     next = source.size();
  732.       }
  733.       else {
  734.     UnicodeString buffer;
  735.     fPattern.extract(patternOffset,tempLength - patternOffset, buffer);
  736.     next = source.indexOf(buffer, sourceOffset);
  737.       }
  738.  
  739.       if (next < 0) {
  740.     status.setErrorIndex(sourceOffset);
  741.     delete [] resultArray;
  742.     count = 0;
  743.     return NULL; // leave index as is to signal error
  744.       } 
  745.       else {
  746.     UnicodeString buffer;
  747.     source.extract(sourceOffset,next - sourceOffset, buffer);
  748.     UnicodeString strValue = buffer;
  749.     UnicodeString temp("{");
  750.                 // {sfb} check this later
  751.     UnicodeString temp1;
  752.     temp += itos(fArgumentNumbers[i], temp1);
  753.     temp += "}";
  754.     if (strValue != temp) {
  755.       source.extract(sourceOffset,next - sourceOffset, buffer);
  756.       resultArray[fArgumentNumbers[i]].setString(buffer);
  757.       // {sfb} not sure about this
  758.       if ((fArgumentNumbers[i] + 1) > count) 
  759.         count = (fArgumentNumbers[i] + 1);
  760.     }
  761.     sourceOffset = next;
  762.       }
  763.     } 
  764.     else {
  765.       tempStatus.setIndex(sourceOffset);
  766.       fFormats[i]->parseObject(source, resultArray[fArgumentNumbers[i]], tempStatus);
  767.       if (tempStatus.getIndex() == sourceOffset) {
  768.     status.setErrorIndex(sourceOffset);
  769.     delete [] resultArray;
  770.     count = 0;
  771.     return NULL; // leave index as is to signal error
  772.       }
  773.  
  774.       if ((fArgumentNumbers[i] + 1) > count)
  775.     count = (fArgumentNumbers[i] + 1);
  776.             
  777.       sourceOffset = tempStatus.getIndex(); // update
  778.     }
  779.   }
  780.   int32_t len = fPattern.size() - patternOffset;
  781.   if (len == 0 || 
  782.       fPattern.compare(patternOffset, len, source, sourceOffset, len) == 0) {
  783.     status.setIndex(sourceOffset + len);
  784.   } 
  785.   else {
  786.     status.setErrorIndex(sourceOffset);
  787.     delete [] resultArray;
  788.     count = 0;
  789.     return NULL; // leave index as is to signal error
  790.   }
  791.     
  792.   return resultArray;
  793. }
  794.  
  795. // -------------------------------------
  796. // Parses the source string and returns the array of 
  797. // Formattable objects and the array count.  The caller 
  798. // owns the returned array.
  799.  
  800. Formattable*
  801. MessageFormat::parse(const UnicodeString& source, 
  802.                      int32_t& cnt,
  803.                      UErrorCode& success) const
  804. {
  805.     ParsePosition status(0);
  806.     // Calls the actual implementation method and starts
  807.     // from zero offset of the source text.
  808.     Formattable* result = parse(source, status, cnt);
  809.     if (status.getIndex() == 0) {
  810.         success = U_MESSAGE_PARSE_ERROR;
  811.         return NULL;
  812.     }
  813.     return result;
  814. }
  815.  
  816. // -------------------------------------
  817. // Parses the source text and copy into the result buffer.
  818.  
  819. void
  820. MessageFormat::parseObject( const UnicodeString& source,
  821.                             Formattable& result,
  822.                             ParsePosition& status) const
  823. {
  824.     int32_t cnt = 0;
  825.     Formattable* tmpResult = parse(source, status, cnt);
  826.     if (tmpResult != NULL) 
  827.         result.adoptArray(tmpResult, cnt);
  828. }
  829.   
  830. // -------------------------------------
  831. // NumberFormat cache management
  832.  
  833. NumberFormat* 
  834. MessageFormat::getNumberFormat(UErrorCode &status)
  835. {
  836.     NumberFormat *theFormat = 0;
  837.  
  838.     if (fgNumberFormat != 0) // if there's something in the cache
  839.     {
  840.         Mutex lock;
  841.  
  842.         if (fgNumberFormat != 0) // Someone might have grabbed it.
  843.         {
  844.             theFormat = fgNumberFormat;
  845.             fgNumberFormat = 0; // We have exclusive right to this formatter.
  846.         }
  847.     }
  848.  
  849.     if(theFormat == 0) // If we weren't able to pull it out of the cache, then we have to create it.
  850.     {
  851.         theFormat = NumberFormat::createInstance(Locale::US, status);
  852.         if(U_FAILURE(status))
  853.             return 0;
  854.         theFormat->setParseIntegerOnly(TRUE);
  855.     }
  856.  
  857.     return theFormat;
  858. }
  859.  
  860. void          
  861. MessageFormat::releaseNumberFormat(NumberFormat *adopt)
  862. {
  863.     if(fgNumberFormat == 0) // If the cache is empty we must add it back.
  864.     {
  865.         Mutex lock;
  866.  
  867.         if(fgNumberFormat == 0)
  868.         {
  869.             fgNumberFormat = adopt;
  870.             adopt = 0;
  871.         }
  872.     }
  873.  
  874.     delete adopt;
  875. }
  876.  
  877.  
  878. /**
  879.  * Converts a string to an integer value using a default NumberFormat object
  880.  * which is static (shared by all MessageFormat instances).  This replaces
  881.  * a call to wtoi().
  882.  */
  883. int32_t
  884. MessageFormat::stoi(const UnicodeString& string,
  885.                     UErrorCode& status)
  886. {
  887.     NumberFormat *myFormat = getNumberFormat(status);
  888.  
  889.     if(U_FAILURE(status))
  890.         return -1; // OK?
  891.  
  892.     Formattable result;
  893.     // Uses the global number formatter to parse the string.
  894.     // Note: We assume here that parse() is thread-safe.
  895.     myFormat->parse(string, result, status);
  896.     releaseNumberFormat(myFormat);
  897.  
  898.     int32_t value = 0;
  899.     if (U_SUCCESS(status) && result.getType() == Formattable::kLong)
  900.         value = result.getLong();
  901.  
  902.  
  903.     return value;
  904. }
  905.  
  906. // -------------------------------------
  907.  
  908. /**
  909.  * Converts an integer value to a string using a default NumberFormat object
  910.  * which is static (shared by all MessageFormat instances).  This replaces
  911.  * a call to wtoi().
  912.  */
  913. UnicodeString&
  914. MessageFormat::itos(int32_t i,
  915.                     UnicodeString& string)
  916. {
  917.     UErrorCode status = U_ZERO_ERROR;
  918.     NumberFormat *myFormat = getNumberFormat(status);
  919.  
  920.     if(U_FAILURE(status))
  921.         return (string = "<ERROR>"); // _REVISIT_ maybe toPattern should take an errorcode.
  922.  
  923.     UnicodeString &retval = myFormat->format(i, string);
  924.  
  925.     releaseNumberFormat(myFormat);
  926.  
  927.     return retval;
  928. }
  929.  
  930. // -------------------------------------
  931. // Checks which format instance we are really using based on the segments.
  932.  
  933. void
  934. MessageFormat::makeFormat(int32_t position, 
  935.                           int32_t offsetNumber, 
  936.                           UnicodeString* segments,
  937.                           UErrorCode& success)
  938. {
  939.     if(U_FAILURE(success))
  940.         return;
  941.  
  942.     // get the number
  943.     int32_t argumentNumber;
  944.     int32_t oldMaxOffset = fMaxOffset;
  945.     argumentNumber = stoi(segments[1], success); // always unlocalized!
  946.     if (argumentNumber < 0 || argumentNumber > 9) {
  947.         success = U_INVALID_FORMAT_ERROR;
  948.         return;
  949.     }
  950.     fMaxOffset = offsetNumber;
  951.     fOffsets[offsetNumber] = segments[0].size();
  952.     fArgumentNumbers[offsetNumber] = argumentNumber;
  953.  
  954.     // now get the format
  955.     Format *newFormat = NULL;
  956.     switch (findKeyword(segments[2], fgTypeList)) {
  957.     case 0:
  958.         break;
  959.     case 1: case 2:// number
  960.         switch (findKeyword(segments[3], fgModifierList)) {
  961.         case 0: // default;
  962.             newFormat = NumberFormat::createInstance(fLocale, success);
  963.             break;
  964.         case 1: case 2:// currency
  965.             newFormat = NumberFormat::createCurrencyInstance(fLocale, success);
  966.             break;
  967.         case 3: case 4:// percent
  968.             newFormat = NumberFormat::createPercentInstance(fLocale, success);
  969.             break;
  970.         case 5: case 6:// integer
  971.             newFormat = createIntegerFormat(fLocale, success);
  972.             break;
  973.         default: // pattern
  974.             newFormat = NumberFormat::createInstance(fLocale, success);
  975.             if(U_FAILURE(success)) {
  976.                 newFormat = NULL;
  977.                 return;
  978.             }
  979.             if(newFormat->getDynamicClassID() == DecimalFormat::getStaticClassID())
  980.                 ((DecimalFormat*)newFormat)->applyPattern(segments[3], success);
  981.             if(U_FAILURE(success)) {
  982.                 fMaxOffset = oldMaxOffset;
  983.                 success = U_ILLEGAL_ARGUMENT_ERROR;
  984.                 return;
  985.             }
  986.             break;
  987.         }
  988.         break;
  989.  
  990.     case 3: case 4: // date
  991.         switch (findKeyword(segments[3], fgDateModifierList)) {
  992.         case 0: // default
  993.             newFormat = DateFormat::createDateInstance(DateFormat::kDefault, fLocale);
  994.             break;
  995.         case 1: case 2: // short
  996.             newFormat = DateFormat::createDateInstance(DateFormat::kShort, fLocale);
  997.             break;
  998.         case 3: case 4: // medium
  999.             newFormat = DateFormat::createDateInstance(DateFormat::kDefault, fLocale);
  1000.             break;
  1001.         case 5: case 6: // long
  1002.             newFormat = DateFormat::createDateInstance(DateFormat::kLong, fLocale);
  1003.             break;
  1004.         case 7: case 8: // full
  1005.             newFormat = DateFormat::createDateInstance(DateFormat::kFull, fLocale);
  1006.             break;
  1007.         default:
  1008.             newFormat = DateFormat::createDateInstance(DateFormat::kDefault, fLocale);
  1009.                 if(newFormat->getDynamicClassID() == SimpleDateFormat::getStaticClassID())
  1010.                     ((SimpleDateFormat*)newFormat)->applyPattern(segments[3]);
  1011.                 if(U_FAILURE(success)) {
  1012.                     fMaxOffset = oldMaxOffset;
  1013.                     success = U_ILLEGAL_ARGUMENT_ERROR;
  1014.                     return;
  1015.                 }
  1016.             break;
  1017.         }
  1018.         break;
  1019.     case 5: case 6:// time
  1020.         switch (findKeyword(segments[3], fgDateModifierList)) {
  1021.         case 0: // default
  1022.             newFormat = DateFormat::createTimeInstance(DateFormat::kDefault, fLocale);
  1023.             break;
  1024.         case 1: case 2: // short
  1025.             newFormat = DateFormat::createTimeInstance(DateFormat::kShort, fLocale);
  1026.             break;
  1027.         case 3: case 4: // medium
  1028.             newFormat = DateFormat::createTimeInstance(DateFormat::kDefault, fLocale);
  1029.             break;
  1030.         case 5: case 6: // long
  1031.             newFormat = DateFormat::createTimeInstance(DateFormat::kLong, fLocale);
  1032.             break;
  1033.         case 7: case 8: // full
  1034.             newFormat = DateFormat::createTimeInstance(DateFormat::kFull, fLocale);
  1035.             break;
  1036.         default:
  1037.             newFormat = DateFormat::createTimeInstance(DateFormat::kDefault, fLocale);
  1038.                 if(newFormat->getDynamicClassID() == SimpleDateFormat::getStaticClassID())
  1039.                     ((SimpleDateFormat*)newFormat)->applyPattern(segments[3]);
  1040.                 if(U_FAILURE(success)) {
  1041.                     fMaxOffset = oldMaxOffset;
  1042.                     success = U_ILLEGAL_ARGUMENT_ERROR;
  1043.                     return;
  1044.                 }
  1045.             break;
  1046.         }
  1047.         break;
  1048.     case 7: case 8:// choice
  1049.             newFormat = new ChoiceFormat(segments[3], success);
  1050.         if(U_FAILURE(success)) {
  1051.             fMaxOffset = oldMaxOffset;
  1052.             success = U_ILLEGAL_ARGUMENT_ERROR;
  1053.             return;
  1054.         }
  1055.         break;
  1056.     default:
  1057.         fMaxOffset = oldMaxOffset;
  1058.         success = U_ILLEGAL_ARGUMENT_ERROR;
  1059.         return;
  1060.     }
  1061.  
  1062.     if(newFormat != NULL) {
  1063.          delete fFormats[offsetNumber];
  1064.         fFormats[offsetNumber] = newFormat;
  1065.     }
  1066.     segments[1].remove();   // throw away other segments
  1067.     segments[2].remove();
  1068.     segments[3].remove();
  1069.  
  1070. }
  1071.  
  1072. // -------------------------------------
  1073. // Finds the string, s, in the string array, list. 
  1074. int32_t MessageFormat::findKeyword(const UnicodeString& s, 
  1075.                            const UnicodeString* list)
  1076. {
  1077.   UnicodeString buffer = s;
  1078.   // Trims the space characters and turns all characters
  1079.   // in s to lower case.
  1080.   buffer.trim().toLower();
  1081.   for (int32_t i = 0; i < fgListLength; ++i) {
  1082.     if (buffer == list[i]) 
  1083.       return i;
  1084.   }
  1085.   return - 1;
  1086. }
  1087.   
  1088. // -------------------------------------
  1089. // Checks the range of the source text to quote the special
  1090. // characters, { and ' and copy to target buffer.
  1091.  
  1092. void
  1093. MessageFormat::copyAndFixQuotes(const UnicodeString& source, 
  1094.                                 int32_t start, 
  1095.                                 int32_t end, 
  1096.                                 UnicodeString& target)
  1097. {
  1098.   bool_t gotLB = FALSE;
  1099.   
  1100.   for (UTextOffset i = start; i < end; ++i) {
  1101.     UChar ch = source[i];
  1102.     if (ch == 0x007B /*'{'*/) {
  1103.       target += "'{'";
  1104.       gotLB = TRUE;
  1105.     } 
  1106.     else if (ch == 0x007D /*'}'*/) {
  1107.       if(gotLB) {
  1108.     target += "}";
  1109.     gotLB = FALSE;
  1110.       }
  1111.       else
  1112.     // orig code.
  1113.     target += "'}'";
  1114.     } 
  1115.     else if (ch == 0x0027 /*'\''*/) {
  1116.       target += "''";
  1117.     } 
  1118.     else {
  1119.       target += ch;
  1120.     }
  1121.   }
  1122. }
  1123.  
  1124. /**
  1125.  * Convenience method that ought to be in NumberFormat
  1126.  */
  1127. NumberFormat* 
  1128. MessageFormat::createIntegerFormat(const Locale& locale, UErrorCode& status) const {
  1129.   NumberFormat *temp = NumberFormat::createInstance(locale, status);
  1130.   if (temp->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
  1131.     DecimalFormat *temp2 = (DecimalFormat*) temp;
  1132.     temp2->setMaximumFractionDigits(0);
  1133.     temp2->setDecimalSeparatorAlwaysShown(FALSE);
  1134.     temp2->setParseIntegerOnly(TRUE);
  1135.   }
  1136.   
  1137.   return temp;
  1138. }
  1139.  
  1140. //eof
  1141.