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

  1. /******************************************************************************
  2.  * COPYRIGHT:                                                               
  3.  *  (C) Copyright Taligent, Inc., 1996
  4.  *  (C) Copyright IBM Corp. 1996-1998
  5.  *  Licensed Material - Program-Property of IBM - All Rights Reserved.
  6.  *  US Government Users Restricted Rights - Use, duplication, or disclosure
  7.  *  restricted by GSA ADP Schedule Contact with IBM Corp.
  8.  *
  9.  ******************************************************************************
  10.  */
  11. //=============================================================================
  12. //
  13. // File ptnentry.cpp
  14. //
  15. // Contains PatternEntry, an internal class used by MergeCollation to store
  16. // one collation element from a pattern.
  17. //
  18. // Created by: Helena Shih
  19. //
  20. // Modification History:
  21. //
  22. //  Date         Name          Description
  23. // 04/23/99      stephen       Removed EDecompositionMode, merged with
  24. //                             Normalizer::EMode
  25. //                             Removed character literals.
  26. //=============================================================================
  27.  
  28. #include "ptnentry.h"
  29.  
  30. #include "unicode.h"
  31. #include "coll.h"
  32. #include "normlzr.h"
  33.  
  34.  
  35. // static member initialization
  36. const int32_t PatternEntry::RESET = -2;
  37. const int32_t PatternEntry::UNSET = -1;
  38.  
  39. // ===== privates =====
  40.  
  41. PatternEntry::PatternEntry() 
  42.   : strength(PatternEntry::UNSET)
  43. {
  44. }
  45.  
  46. PatternEntry::PatternEntry(const    PatternEntry&   other)
  47.   : strength(other.strength), chars(other.chars), extension(other.extension)
  48. {
  49. }
  50.  
  51. PatternEntry::PatternEntry(int32_t newStrength,
  52.                const UnicodeString& newChars,
  53.                const UnicodeString& newExtensions, 
  54.                Normalizer::EMode decompMode)
  55.   : strength(newStrength), extension(newExtensions)
  56. {
  57.   // Normalize the characters in the new entry.  Find occurances of all 
  58.   // decomposed characters and normalize them.  By "normalize",
  59.   // we mean that all precomposed Unicode characters must be converted into
  60.   // a base character and one or more combining characters (such as accents).
  61.   // When there are multiple combining characters attached to a base character,
  62.   // the combining characters must be in their canonical order
  63.   //
  64.   UErrorCode status = U_ZERO_ERROR;
  65.   Normalizer::normalize(newChars, decompMode, 0, chars, status);
  66.   if (U_FAILURE(status)) {
  67.     chars = newChars;
  68.   }
  69. }
  70.  
  71. PatternEntry::~PatternEntry() {
  72. }
  73.  
  74. const PatternEntry&
  75. PatternEntry::operator=(const   PatternEntry& other)
  76. {
  77.   if (this != &other) {
  78.     strength = other.strength;        
  79.     chars = other.chars;
  80.     extension = other.extension;
  81.   }
  82.   return *this;
  83. }
  84.  
  85. /**
  86.  * Gets the current extension, quoted
  87.  * This is useful when constructing a user-readable string representing
  88.  * a pattern.
  89.  */
  90. void PatternEntry::appendQuotedExtension(UnicodeString& toAddTo) const {
  91.   appendQuoted(extension,toAddTo);
  92. }
  93.  
  94. /**
  95.  * Gets the current chars, quoted
  96.  * This is useful when constructing a user-readable string representing
  97.  * a pattern.
  98.  */
  99. void PatternEntry::appendQuotedChars(UnicodeString& toAddTo) const {
  100.   appendQuoted(chars,toAddTo);
  101. }
  102.  
  103. bool_t PatternEntry::equals(const PatternEntry& other) const {
  104.   bool_t result = ((strength == other.strength) &&
  105.                    (chars == other.chars) &&
  106.                    (extension == other.extension));
  107.   return result;
  108. }
  109.  
  110. /**
  111.  * For debugging.
  112.  */
  113. UnicodeString& 
  114. PatternEntry::toString(UnicodeString& result) const 
  115. {
  116.   addToBuffer(result, TRUE, FALSE, NULL);
  117.   return result;
  118. }
  119.  
  120. int32_t 
  121. PatternEntry::getStrength() const
  122. {
  123.   return strength;
  124. }
  125.  
  126. const UnicodeString&    
  127. PatternEntry::getExtension(UnicodeString& ext) const
  128. {
  129.   ext = extension;
  130.   return ext;
  131. }
  132.  
  133. const UnicodeString&    
  134. PatternEntry::getChars(UnicodeString& result) const
  135. {
  136.   result = chars;
  137.   return result;
  138. }
  139.  
  140. /*
  141.  Add the entry in textual form into the toAddTo buffer.
  142.  */
  143. void PatternEntry::addToBuffer(UnicodeString& toAddTo,
  144.                    bool_t showExtension,
  145.                    bool_t showWhiteSpace,
  146.                    const PatternEntry* lastEntry) const
  147. {
  148.   if (showWhiteSpace && toAddTo.size() > 0)
  149.     // Adds new line before each primary strength entry.
  150.     if (strength == Collator::PRIMARY || lastEntry != NULL)
  151.       toAddTo += 0x000A/*'\n'*/;
  152.     else
  153.       toAddTo += 0x0020/*' '*/;
  154.   if (lastEntry != NULL) {
  155.     toAddTo += 0x0026/*'&'*/;
  156.     if (showWhiteSpace)
  157.       toAddTo += 0x0020/*' '*/;
  158.     lastEntry->appendQuotedChars(toAddTo);
  159.     appendQuotedExtension(toAddTo);
  160.     if (showWhiteSpace)
  161.       toAddTo += 0x0020/*' '*/;
  162.   }
  163.   // Check the strength for the correct symbol to append
  164.   switch (strength) {
  165.   case Collator::IDENTICAL:   toAddTo += 0x003D/*'='*/; break;
  166.   case Collator::TERTIARY:    toAddTo += 0x002C/*','*/; break;
  167.   case Collator::SECONDARY:   toAddTo += 0x003B/*';'*/; break;
  168.   case Collator::PRIMARY:     toAddTo += 0x003C/*'<'*/; break;
  169.   case PatternEntry::RESET:   toAddTo += 0x0026/*'&'*/; break;
  170.   case PatternEntry::UNSET:   toAddTo += 0x003F/*'?'*/; break;
  171.   }
  172.   if (showWhiteSpace)
  173.     toAddTo += 0x0020/*' '*/;
  174.   appendQuoted(chars,toAddTo);
  175.   // If there's an expending char and needs to be shown, 
  176.   // append that after the entry
  177.   if (showExtension && extension.size() != 0) {
  178.     toAddTo += 0x002F/*'/'*/;
  179.     appendQuoted(extension,toAddTo);
  180.   }
  181. }
  182.  
  183. // Append a string to a pattern buffer, adding quotes if necessary
  184. void PatternEntry::appendQuoted(const UnicodeString& chars, UnicodeString& toAddTo) {
  185.   bool_t inQuote = FALSE;
  186.   UChar ch = chars[T_INT32(0)];
  187.   if (Unicode::isSpaceChar(ch)) {
  188.     inQuote = TRUE;
  189.     toAddTo += 0x0027/*'\''*/;
  190.   } else if (isSpecialChar(ch)) {
  191.     inQuote = TRUE;
  192.     toAddTo += 0x0027/*'\''*/;
  193.   } else {
  194.     switch (ch) {
  195.     case 0x0010: case 0x000C/*'\f'*/: 
  196.     case 0x000D/*'\r'*/: case 0x0009/*'\t'*/: 
  197.     case 0x000A/*'\n'*/: case 0x0040/*'@'*/:
  198.       inQuote = TRUE;
  199.       toAddTo += 0x0027/*'\''*/;
  200.       break;
  201.     case 0x0027/*'\''*/:
  202.       inQuote = TRUE;
  203.       toAddTo += 0x0027/*'\''*/;
  204.       break;
  205.     default:
  206.       if (inQuote) {
  207.     inQuote = FALSE; toAddTo += 0x0027/*'\''*/;
  208.       }
  209.       break;
  210.     }
  211.   }
  212.   toAddTo += chars;
  213.   if (inQuote)
  214.     toAddTo += 0x0027/*'\''*/;
  215. }
  216.  
  217. PatternEntry::Parser::Parser(const UnicodeString &pattern, 
  218.                              Normalizer::EMode decompMode)
  219.   : pattern(pattern), index(0), 
  220.     fDecompMode(decompMode), newChars(), newExtensions()
  221. {
  222. }
  223.  
  224. PatternEntry::Parser::Parser(const Parser &that)
  225.   : pattern(that.pattern), index(that.index), fDecompMode(that.fDecompMode),
  226.     newChars(that.newChars), newExtensions(that.newExtensions)
  227. {
  228. }
  229.  
  230. PatternEntry::Parser::~Parser()
  231. {
  232. }
  233.  
  234. PatternEntry::Parser &PatternEntry::Parser::operator=(const Parser &that)
  235. {
  236.   if (this != &that)
  237.   {
  238.     this->pattern = that.pattern;
  239.     this->index = that.index;
  240.     this->fDecompMode = that.fDecompMode;
  241.     this->newChars = that.newChars;
  242.     this->newExtensions = that.newExtensions;
  243.   }
  244.     
  245.   return *this;
  246. }
  247.  
  248. PatternEntry *PatternEntry::Parser::next(UErrorCode &status)
  249. {
  250.   int32_t newStrength = PatternEntry::UNSET;
  251.   bool_t inChars = TRUE;
  252.   bool_t inQuote = FALSE;
  253.  
  254.   newChars.remove();
  255.   newExtensions.remove();
  256.  
  257.   while (index < pattern.size())
  258.     {
  259.       UChar ch = pattern[index];
  260.  
  261.       if (inQuote)
  262.     {
  263.       if (ch == 0x0027/*'\''*/)
  264.         {
  265.           inQuote = FALSE;
  266.         }
  267.       else
  268.         {
  269.           if ((newChars.size() == 0) || inChars)
  270.         {
  271.           newChars += ch;
  272.         }
  273.           else
  274.         {
  275.           newExtensions += ch;
  276.         }
  277.             }
  278.         }
  279.       else
  280.     {
  281.       // Sets the strength for this entry
  282.       switch (ch)
  283.         {
  284.         case 0x003D/*'='*/ : 
  285.           if (newStrength != PatternEntry::UNSET)
  286.         {
  287.           goto EndOfLoop;
  288.         }
  289.  
  290.           newStrength = Collator::IDENTICAL;
  291.           break;
  292.  
  293.         case 0x002C/*','*/:  
  294.           if (newStrength != PatternEntry::UNSET)
  295.         {
  296.           goto EndOfLoop;
  297.         }
  298.  
  299.           newStrength = Collator::TERTIARY;
  300.           break;
  301.  
  302.         case  0x003B/*';'*/:
  303.           if (newStrength != PatternEntry::UNSET)
  304.         {
  305.           goto EndOfLoop;
  306.         }
  307.  
  308.           newStrength = Collator::SECONDARY;
  309.           break;
  310.  
  311.         case 0x003C/*'<'*/:  
  312.           if (newStrength != PatternEntry::UNSET)
  313.         {
  314.           goto EndOfLoop;
  315.         }
  316.  
  317.           newStrength = Collator::PRIMARY;
  318.           break;
  319.  
  320.         case 0x0026/*'&'*/:  
  321.           if (newStrength != PatternEntry::UNSET)
  322.         {
  323.           goto EndOfLoop;
  324.         }
  325.  
  326.           newStrength = PatternEntry::RESET;
  327.           break;
  328.  
  329.           // Ignore the white spaces
  330.         case 0x0009/*'\t'*/:
  331.         case 0x000C/*'\f'*/:
  332.         case 0x000D/*'\r'*/:
  333.         case 0x000A/*'\n'*/:
  334.         case 0x0020/*' '*/:  
  335.           break; // skip whitespace TODO use Unicode
  336.  
  337.         case 0x002F/*'/'*/:
  338.                 // This entry has an extension.
  339.           inChars = FALSE;
  340.           break;
  341.  
  342.         case 0x0027/*'\''*/:
  343.           inQuote = TRUE;
  344.           ch = pattern[++index];
  345.  
  346.           if (newChars.size() == 0)
  347.         {
  348.           newChars += ch;
  349.         }
  350.           else if (inChars)
  351.         {
  352.           newChars += ch;
  353.         }
  354.           else
  355.         {
  356.           newExtensions += ch;
  357.         }
  358.  
  359.           break;
  360.  
  361.         default:
  362.           if (newStrength == PatternEntry::UNSET)
  363.         {
  364.           status = U_INVALID_FORMAT_ERROR;
  365.           return NULL;
  366.         }
  367.  
  368.           if (isSpecialChar(ch) && (inQuote == FALSE))
  369.         {
  370.           status = U_INVALID_FORMAT_ERROR;
  371.           return NULL;
  372.         }
  373.  
  374.           if (inChars)
  375.         {
  376.           newChars += ch;
  377.         }
  378.           else
  379.         {
  380.           newExtensions += ch;
  381.         }
  382.  
  383.           break;
  384.         }
  385.     }
  386.  
  387.       if (newChars.isBogus() || newExtensions.isBogus())
  388.     {
  389.       status = U_MEMORY_ALLOCATION_ERROR;
  390.       return NULL;
  391.         }
  392.  
  393.       index += 1;
  394.     }
  395.  
  396.  EndOfLoop:
  397.   if (newStrength == PatternEntry::UNSET)
  398.     {
  399.       return NULL;
  400.     }
  401.  
  402.   if (newChars.size() == 0)
  403.     {
  404.       status = U_INVALID_FORMAT_ERROR;
  405.       return NULL;
  406.     }
  407.  
  408.   return new PatternEntry(newStrength, newChars, newExtensions, fDecompMode);
  409. }
  410.  
  411. // Check if the character is a special character.  A special character
  412. // would be meaningful in the rule only if quoted, otherwise it's used
  413. // as a denotation for strength or merging symbols.
  414. bool_t PatternEntry::isSpecialChar(UChar ch)
  415. {
  416.   return (((ch <= 0x002F) && (ch >= 0x0020)) ||
  417.       ((ch <= 0x003F) && (ch >= 0x003A)) ||
  418.       ((ch <= 0x0060) && (ch >= 0x005B)) ||
  419.       ((ch <= 0x007E) && (ch >= 0x007B)));
  420. }
  421.