Home | History | Annotate | Download | only in common
      1 /*
      2 *******************************************************************************
      3 *
      4 *   Copyright (C) 1999-2012, International Business Machines
      5 *   Corporation and others.  All Rights Reserved.
      6 *
      7 *******************************************************************************
      8 *   file name:  uniset_props.cpp
      9 *   encoding:   US-ASCII
     10 *   tab size:   8 (not used)
     11 *   indentation:4
     12 *
     13 *   created on: 2004aug25
     14 *   created by: Markus W. Scherer
     15 *
     16 *   Character property dependent functions moved here from uniset.cpp
     17 */
     18 
     19 #include "unicode/utypes.h"
     20 #include "unicode/uniset.h"
     21 #include "unicode/parsepos.h"
     22 #include "unicode/uchar.h"
     23 #include "unicode/uscript.h"
     24 #include "unicode/symtable.h"
     25 #include "unicode/uset.h"
     26 #include "unicode/locid.h"
     27 #include "unicode/brkiter.h"
     28 #include "uset_imp.h"
     29 #include "ruleiter.h"
     30 #include "cmemory.h"
     31 #include "ucln_cmn.h"
     32 #include "util.h"
     33 #include "uvector.h"
     34 #include "uprops.h"
     35 #include "propname.h"
     36 #include "normalizer2impl.h"
     37 #include "ucase.h"
     38 #include "ubidi_props.h"
     39 #include "uinvchar.h"
     40 #include "uprops.h"
     41 #include "charstr.h"
     42 #include "cstring.h"
     43 #include "mutex.h"
     44 #include "umutex.h"
     45 #include "uassert.h"
     46 #include "hash.h"
     47 
     48 U_NAMESPACE_USE
     49 
     50 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
     51 
     52 // initial storage. Must be >= 0
     53 // *** same as in uniset.cpp ! ***
     54 #define START_EXTRA 16
     55 
     56 // Define UChar constants using hex for EBCDIC compatibility
     57 // Used #define to reduce private static exports and memory access time.
     58 #define SET_OPEN        ((UChar)0x005B) /*[*/
     59 #define SET_CLOSE       ((UChar)0x005D) /*]*/
     60 #define HYPHEN          ((UChar)0x002D) /*-*/
     61 #define COMPLEMENT      ((UChar)0x005E) /*^*/
     62 #define COLON           ((UChar)0x003A) /*:*/
     63 #define BACKSLASH       ((UChar)0x005C) /*\*/
     64 #define INTERSECTION    ((UChar)0x0026) /*&*/
     65 #define UPPER_U         ((UChar)0x0055) /*U*/
     66 #define LOWER_U         ((UChar)0x0075) /*u*/
     67 #define OPEN_BRACE      ((UChar)123)    /*{*/
     68 #define CLOSE_BRACE     ((UChar)125)    /*}*/
     69 #define UPPER_P         ((UChar)0x0050) /*P*/
     70 #define LOWER_P         ((UChar)0x0070) /*p*/
     71 #define UPPER_N         ((UChar)78)     /*N*/
     72 #define EQUALS          ((UChar)0x003D) /*=*/
     73 
     74 //static const UChar POSIX_OPEN[]  = { SET_OPEN,COLON,0 };  // "[:"
     75 static const UChar POSIX_CLOSE[] = { COLON,SET_CLOSE,0 };  // ":]"
     76 //static const UChar PERL_OPEN[]   = { BACKSLASH,LOWER_P,0 }; // "\\p"
     77 //static const UChar PERL_CLOSE[]  = { CLOSE_BRACE,0 };    // "}"
     78 //static const UChar NAME_OPEN[]   = { BACKSLASH,UPPER_N,0 };  // "\\N"
     79 static const UChar HYPHEN_RIGHT_BRACE[] = {HYPHEN,SET_CLOSE,0}; /*-]*/
     80 
     81 // Special property set IDs
     82 static const char ANY[]   = "ANY";   // [\u0000-\U0010FFFF]
     83 static const char ASCII[] = "ASCII"; // [\u0000-\u007F]
     84 static const char ASSIGNED[] = "Assigned"; // [:^Cn:]
     85 
     86 // Unicode name property alias
     87 #define NAME_PROP "na"
     88 #define NAME_PROP_LENGTH 2
     89 
     90 /**
     91  * Delimiter string used in patterns to close a category reference:
     92  * ":]".  Example: "[:Lu:]".
     93  */
     94 //static const UChar CATEGORY_CLOSE[] = {COLON, SET_CLOSE, 0x0000}; /* ":]" */
     95 
     96 // Cached sets ------------------------------------------------------------- ***
     97 
     98 U_CDECL_BEGIN
     99 static UBool U_CALLCONV uset_cleanup();
    100 U_CDECL_END
    101 
    102 // Not a TriStateSingletonWrapper because we think the UnicodeSet constructor
    103 // can only fail with an out-of-memory error
    104 // if we have a correct pattern and the properties data is hardcoded and always available.
    105 class UnicodeSetSingleton : public SimpleSingletonWrapper<UnicodeSet> {
    106 public:
    107     UnicodeSetSingleton(SimpleSingleton &s, const char *pattern) :
    108             SimpleSingletonWrapper<UnicodeSet>(s), fPattern(pattern) {}
    109     UnicodeSet *getInstance(UErrorCode &errorCode) {
    110         return SimpleSingletonWrapper<UnicodeSet>::getInstance(createInstance, fPattern, errorCode);
    111     }
    112 private:
    113     static void *createInstance(const void *context, UErrorCode &errorCode) {
    114         UnicodeString pattern((const char *)context, -1, US_INV);
    115         UnicodeSet *set=new UnicodeSet(pattern, errorCode);
    116         if(set==NULL) {
    117             errorCode=U_MEMORY_ALLOCATION_ERROR;
    118             return NULL;
    119         }
    120         set->freeze();
    121         ucln_common_registerCleanup(UCLN_COMMON_USET, uset_cleanup);
    122         return set;
    123     }
    124 
    125     const char *fPattern;
    126 };
    127 
    128 U_CDECL_BEGIN
    129 
    130 static UnicodeSet *INCLUSIONS[UPROPS_SRC_COUNT] = { NULL }; // cached getInclusions()
    131 
    132 STATIC_SIMPLE_SINGLETON(uni32Singleton);
    133 
    134 //----------------------------------------------------------------
    135 // Inclusions list
    136 //----------------------------------------------------------------
    137 
    138 // USetAdder implementation
    139 // Does not use uset.h to reduce code dependencies
    140 static void U_CALLCONV
    141 _set_add(USet *set, UChar32 c) {
    142     ((UnicodeSet *)set)->add(c);
    143 }
    144 
    145 static void U_CALLCONV
    146 _set_addRange(USet *set, UChar32 start, UChar32 end) {
    147     ((UnicodeSet *)set)->add(start, end);
    148 }
    149 
    150 static void U_CALLCONV
    151 _set_addString(USet *set, const UChar *str, int32_t length) {
    152     ((UnicodeSet *)set)->add(UnicodeString((UBool)(length<0), str, length));
    153 }
    154 
    155 /**
    156  * Cleanup function for UnicodeSet
    157  */
    158 static UBool U_CALLCONV uset_cleanup(void) {
    159     int32_t i;
    160 
    161     for(i = UPROPS_SRC_NONE; i < UPROPS_SRC_COUNT; ++i) {
    162         if (INCLUSIONS[i] != NULL) {
    163             delete INCLUSIONS[i];
    164             INCLUSIONS[i] = NULL;
    165         }
    166     }
    167     UnicodeSetSingleton(uni32Singleton, NULL).deleteInstance();
    168     return TRUE;
    169 }
    170 
    171 U_CDECL_END
    172 
    173 U_NAMESPACE_BEGIN
    174 
    175 /*
    176 Reduce excessive reallocation, and make it easier to detect initialization
    177 problems.
    178 Usually you don't see smaller sets than this for Unicode 5.0.
    179 */
    180 #define DEFAULT_INCLUSION_CAPACITY 3072
    181 
    182 const UnicodeSet* UnicodeSet::getInclusions(int32_t src, UErrorCode &status) {
    183     UBool needInit;
    184     UMTX_CHECK(NULL, (INCLUSIONS[src] == NULL), needInit);
    185     if (needInit) {
    186         UnicodeSet* incl = new UnicodeSet();
    187         USetAdder sa = {
    188             (USet *)incl,
    189             _set_add,
    190             _set_addRange,
    191             _set_addString,
    192             NULL, // don't need remove()
    193             NULL // don't need removeRange()
    194         };
    195         if (incl != NULL) {
    196             incl->ensureCapacity(DEFAULT_INCLUSION_CAPACITY, status);
    197             switch(src) {
    198             case UPROPS_SRC_CHAR:
    199                 uchar_addPropertyStarts(&sa, &status);
    200                 break;
    201             case UPROPS_SRC_PROPSVEC:
    202                 upropsvec_addPropertyStarts(&sa, &status);
    203                 break;
    204             case UPROPS_SRC_CHAR_AND_PROPSVEC:
    205                 uchar_addPropertyStarts(&sa, &status);
    206                 upropsvec_addPropertyStarts(&sa, &status);
    207                 break;
    208 #if !UCONFIG_NO_NORMALIZATION
    209             case UPROPS_SRC_CASE_AND_NORM: {
    210                 const Normalizer2Impl *impl=Normalizer2Factory::getNFCImpl(status);
    211                 if(U_SUCCESS(status)) {
    212                     impl->addPropertyStarts(&sa, status);
    213                 }
    214                 ucase_addPropertyStarts(ucase_getSingleton(), &sa, &status);
    215                 break;
    216             }
    217             case UPROPS_SRC_NFC: {
    218                 const Normalizer2Impl *impl=Normalizer2Factory::getNFCImpl(status);
    219                 if(U_SUCCESS(status)) {
    220                     impl->addPropertyStarts(&sa, status);
    221                 }
    222                 break;
    223             }
    224             case UPROPS_SRC_NFKC: {
    225                 const Normalizer2Impl *impl=Normalizer2Factory::getNFKCImpl(status);
    226                 if(U_SUCCESS(status)) {
    227                     impl->addPropertyStarts(&sa, status);
    228                 }
    229                 break;
    230             }
    231             case UPROPS_SRC_NFKC_CF: {
    232                 const Normalizer2Impl *impl=Normalizer2Factory::getNFKC_CFImpl(status);
    233                 if(U_SUCCESS(status)) {
    234                     impl->addPropertyStarts(&sa, status);
    235                 }
    236                 break;
    237             }
    238             case UPROPS_SRC_NFC_CANON_ITER: {
    239                 const Normalizer2Impl *impl=Normalizer2Factory::getNFCImpl(status);
    240                 if(U_SUCCESS(status)) {
    241                     impl->addCanonIterPropertyStarts(&sa, status);
    242                 }
    243                 break;
    244             }
    245 #endif
    246             case UPROPS_SRC_CASE:
    247                 ucase_addPropertyStarts(ucase_getSingleton(), &sa, &status);
    248                 break;
    249             case UPROPS_SRC_BIDI:
    250                 ubidi_addPropertyStarts(ubidi_getSingleton(), &sa, &status);
    251                 break;
    252             default:
    253                 status = U_INTERNAL_PROGRAM_ERROR;
    254                 break;
    255             }
    256             if (U_SUCCESS(status)) {
    257                 // Compact for caching
    258                 incl->compact();
    259                 umtx_lock(NULL);
    260                 if (INCLUSIONS[src] == NULL) {
    261                     INCLUSIONS[src] = incl;
    262                     incl = NULL;
    263                     ucln_common_registerCleanup(UCLN_COMMON_USET, uset_cleanup);
    264                 }
    265                 umtx_unlock(NULL);
    266             }
    267             delete incl;
    268         } else {
    269             status = U_MEMORY_ALLOCATION_ERROR;
    270         }
    271     }
    272     return INCLUSIONS[src];
    273 }
    274 
    275 // Cache some sets for other services -------------------------------------- ***
    276 
    277 U_CFUNC UnicodeSet *
    278 uniset_getUnicode32Instance(UErrorCode &errorCode) {
    279     return UnicodeSetSingleton(uni32Singleton, "[:age=3.2:]").getInstance(errorCode);
    280 }
    281 
    282 // helper functions for matching of pattern syntax pieces ------------------ ***
    283 // these functions are parallel to the PERL_OPEN etc. strings above
    284 
    285 // using these functions is not only faster than UnicodeString::compare() and
    286 // caseCompare(), but they also make UnicodeSet work for simple patterns when
    287 // no Unicode properties data is available - when caseCompare() fails
    288 
    289 static inline UBool
    290 isPerlOpen(const UnicodeString &pattern, int32_t pos) {
    291     UChar c;
    292     return pattern.charAt(pos)==BACKSLASH && ((c=pattern.charAt(pos+1))==LOWER_P || c==UPPER_P);
    293 }
    294 
    295 /*static inline UBool
    296 isPerlClose(const UnicodeString &pattern, int32_t pos) {
    297     return pattern.charAt(pos)==CLOSE_BRACE;
    298 }*/
    299 
    300 static inline UBool
    301 isNameOpen(const UnicodeString &pattern, int32_t pos) {
    302     return pattern.charAt(pos)==BACKSLASH && pattern.charAt(pos+1)==UPPER_N;
    303 }
    304 
    305 static inline UBool
    306 isPOSIXOpen(const UnicodeString &pattern, int32_t pos) {
    307     return pattern.charAt(pos)==SET_OPEN && pattern.charAt(pos+1)==COLON;
    308 }
    309 
    310 /*static inline UBool
    311 isPOSIXClose(const UnicodeString &pattern, int32_t pos) {
    312     return pattern.charAt(pos)==COLON && pattern.charAt(pos+1)==SET_CLOSE;
    313 }*/
    314 
    315 // TODO memory debugging provided inside uniset.cpp
    316 // could be made available here but probably obsolete with use of modern
    317 // memory leak checker tools
    318 #define _dbgct(me)
    319 
    320 //----------------------------------------------------------------
    321 // Constructors &c
    322 //----------------------------------------------------------------
    323 
    324 /**
    325  * Constructs a set from the given pattern, optionally ignoring
    326  * white space.  See the class description for the syntax of the
    327  * pattern language.
    328  * @param pattern a string specifying what characters are in the set
    329  */
    330 UnicodeSet::UnicodeSet(const UnicodeString& pattern,
    331                        UErrorCode& status) :
    332     len(0), capacity(START_EXTRA), list(0), bmpSet(0), buffer(0),
    333     bufferCapacity(0), patLen(0), pat(NULL), strings(NULL), stringSpan(NULL),
    334     fFlags(0)
    335 {
    336     if(U_SUCCESS(status)){
    337         list = (UChar32*) uprv_malloc(sizeof(UChar32) * capacity);
    338         /* test for NULL */
    339         if(list == NULL) {
    340             status = U_MEMORY_ALLOCATION_ERROR;
    341         }else{
    342             allocateStrings(status);
    343             applyPattern(pattern, status);
    344         }
    345     }
    346     _dbgct(this);
    347 }
    348 
    349 //----------------------------------------------------------------
    350 // Public API
    351 //----------------------------------------------------------------
    352 
    353 UnicodeSet& UnicodeSet::applyPattern(const UnicodeString& pattern,
    354                                      UErrorCode& status) {
    355     // Equivalent to
    356     //   return applyPattern(pattern, USET_IGNORE_SPACE, NULL, status);
    357     // but without dependency on closeOver().
    358     ParsePosition pos(0);
    359     applyPatternIgnoreSpace(pattern, pos, NULL, status);
    360     if (U_FAILURE(status)) return *this;
    361 
    362     int32_t i = pos.getIndex();
    363     // Skip over trailing whitespace
    364     ICU_Utility::skipWhitespace(pattern, i, TRUE);
    365     if (i != pattern.length()) {
    366         status = U_ILLEGAL_ARGUMENT_ERROR;
    367     }
    368     return *this;
    369 }
    370 
    371 void
    372 UnicodeSet::applyPatternIgnoreSpace(const UnicodeString& pattern,
    373                                     ParsePosition& pos,
    374                                     const SymbolTable* symbols,
    375                                     UErrorCode& status) {
    376     if (U_FAILURE(status)) {
    377         return;
    378     }
    379     if (isFrozen()) {
    380         status = U_NO_WRITE_PERMISSION;
    381         return;
    382     }
    383     // Need to build the pattern in a temporary string because
    384     // _applyPattern calls add() etc., which set pat to empty.
    385     UnicodeString rebuiltPat;
    386     RuleCharacterIterator chars(pattern, symbols, pos);
    387     applyPattern(chars, symbols, rebuiltPat, USET_IGNORE_SPACE, NULL, status);
    388     if (U_FAILURE(status)) return;
    389     if (chars.inVariable()) {
    390         // syntaxError(chars, "Extra chars in variable value");
    391         status = U_MALFORMED_SET;
    392         return;
    393     }
    394     setPattern(rebuiltPat);
    395 }
    396 
    397 /**
    398  * Return true if the given position, in the given pattern, appears
    399  * to be the start of a UnicodeSet pattern.
    400  */
    401 UBool UnicodeSet::resemblesPattern(const UnicodeString& pattern, int32_t pos) {
    402     return ((pos+1) < pattern.length() &&
    403             pattern.charAt(pos) == (UChar)91/*[*/) ||
    404         resemblesPropertyPattern(pattern, pos);
    405 }
    406 
    407 //----------------------------------------------------------------
    408 // Implementation: Pattern parsing
    409 //----------------------------------------------------------------
    410 
    411 /**
    412  * A small all-inline class to manage a UnicodeSet pointer.  Add
    413  * operator->() etc. as needed.
    414  */
    415 class UnicodeSetPointer {
    416     UnicodeSet* p;
    417 public:
    418     inline UnicodeSetPointer() : p(0) {}
    419     inline ~UnicodeSetPointer() { delete p; }
    420     inline UnicodeSet* pointer() { return p; }
    421     inline UBool allocate() {
    422         if (p == 0) {
    423             p = new UnicodeSet();
    424         }
    425         return p != 0;
    426     }
    427 };
    428 
    429 /**
    430  * Parse the pattern from the given RuleCharacterIterator.  The
    431  * iterator is advanced over the parsed pattern.
    432  * @param chars iterator over the pattern characters.  Upon return
    433  * it will be advanced to the first character after the parsed
    434  * pattern, or the end of the iteration if all characters are
    435  * parsed.
    436  * @param symbols symbol table to use to parse and dereference
    437  * variables, or null if none.
    438  * @param rebuiltPat the pattern that was parsed, rebuilt or
    439  * copied from the input pattern, as appropriate.
    440  * @param options a bit mask of zero or more of the following:
    441  * IGNORE_SPACE, CASE.
    442  */
    443 void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
    444                               const SymbolTable* symbols,
    445                               UnicodeString& rebuiltPat,
    446                               uint32_t options,
    447                               UnicodeSet& (UnicodeSet::*caseClosure)(int32_t attribute),
    448                               UErrorCode& ec) {
    449     if (U_FAILURE(ec)) return;
    450 
    451     // Syntax characters: [ ] ^ - & { }
    452 
    453     // Recognized special forms for chars, sets: c-c s-s s&s
    454 
    455     int32_t opts = RuleCharacterIterator::PARSE_VARIABLES |
    456                    RuleCharacterIterator::PARSE_ESCAPES;
    457     if ((options & USET_IGNORE_SPACE) != 0) {
    458         opts |= RuleCharacterIterator::SKIP_WHITESPACE;
    459     }
    460 
    461     UnicodeString patLocal, buf;
    462     UBool usePat = FALSE;
    463     UnicodeSetPointer scratch;
    464     RuleCharacterIterator::Pos backup;
    465 
    466     // mode: 0=before [, 1=between [...], 2=after ]
    467     // lastItem: 0=none, 1=char, 2=set
    468     int8_t lastItem = 0, mode = 0;
    469     UChar32 lastChar = 0;
    470     UChar op = 0;
    471 
    472     UBool invert = FALSE;
    473 
    474     clear();
    475 
    476     while (mode != 2 && !chars.atEnd()) {
    477         U_ASSERT((lastItem == 0 && op == 0) ||
    478                  (lastItem == 1 && (op == 0 || op == HYPHEN /*'-'*/)) ||
    479                  (lastItem == 2 && (op == 0 || op == HYPHEN /*'-'*/ ||
    480                                     op == INTERSECTION /*'&'*/)));
    481 
    482         UChar32 c = 0;
    483         UBool literal = FALSE;
    484         UnicodeSet* nested = 0; // alias - do not delete
    485 
    486         // -------- Check for property pattern
    487 
    488         // setMode: 0=none, 1=unicodeset, 2=propertypat, 3=preparsed
    489         int8_t setMode = 0;
    490         if (resemblesPropertyPattern(chars, opts)) {
    491             setMode = 2;
    492         }
    493 
    494         // -------- Parse '[' of opening delimiter OR nested set.
    495         // If there is a nested set, use `setMode' to define how
    496         // the set should be parsed.  If the '[' is part of the
    497         // opening delimiter for this pattern, parse special
    498         // strings "[", "[^", "[-", and "[^-".  Check for stand-in
    499         // characters representing a nested set in the symbol
    500         // table.
    501 
    502         else {
    503             // Prepare to backup if necessary
    504             chars.getPos(backup);
    505             c = chars.next(opts, literal, ec);
    506             if (U_FAILURE(ec)) return;
    507 
    508             if (c == 0x5B /*'['*/ && !literal) {
    509                 if (mode == 1) {
    510                     chars.setPos(backup); // backup
    511                     setMode = 1;
    512                 } else {
    513                     // Handle opening '[' delimiter
    514                     mode = 1;
    515                     patLocal.append((UChar) 0x5B /*'['*/);
    516                     chars.getPos(backup); // prepare to backup
    517                     c = chars.next(opts, literal, ec);
    518                     if (U_FAILURE(ec)) return;
    519                     if (c == 0x5E /*'^'*/ && !literal) {
    520                         invert = TRUE;
    521                         patLocal.append((UChar) 0x5E /*'^'*/);
    522                         chars.getPos(backup); // prepare to backup
    523                         c = chars.next(opts, literal, ec);
    524                         if (U_FAILURE(ec)) return;
    525                     }
    526                     // Fall through to handle special leading '-';
    527                     // otherwise restart loop for nested [], \p{}, etc.
    528                     if (c == HYPHEN /*'-'*/) {
    529                         literal = TRUE;
    530                         // Fall through to handle literal '-' below
    531                     } else {
    532                         chars.setPos(backup); // backup
    533                         continue;
    534                     }
    535                 }
    536             } else if (symbols != 0) {
    537                 const UnicodeFunctor *m = symbols->lookupMatcher(c);
    538                 if (m != 0) {
    539                     const UnicodeSet *ms = dynamic_cast<const UnicodeSet *>(m);
    540                     if (ms == NULL) {
    541                         ec = U_MALFORMED_SET;
    542                         return;
    543                     }
    544                     // casting away const, but `nested' won't be modified
    545                     // (important not to modify stored set)
    546                     nested = const_cast<UnicodeSet*>(ms);
    547                     setMode = 3;
    548                 }
    549             }
    550         }
    551 
    552         // -------- Handle a nested set.  This either is inline in
    553         // the pattern or represented by a stand-in that has
    554         // previously been parsed and was looked up in the symbol
    555         // table.
    556 
    557         if (setMode != 0) {
    558             if (lastItem == 1) {
    559                 if (op != 0) {
    560                     // syntaxError(chars, "Char expected after operator");
    561                     ec = U_MALFORMED_SET;
    562                     return;
    563                 }
    564                 add(lastChar, lastChar);
    565                 _appendToPat(patLocal, lastChar, FALSE);
    566                 lastItem = 0;
    567                 op = 0;
    568             }
    569 
    570             if (op == HYPHEN /*'-'*/ || op == INTERSECTION /*'&'*/) {
    571                 patLocal.append(op);
    572             }
    573 
    574             if (nested == 0) {
    575                 // lazy allocation
    576                 if (!scratch.allocate()) {
    577                     ec = U_MEMORY_ALLOCATION_ERROR;
    578                     return;
    579                 }
    580                 nested = scratch.pointer();
    581             }
    582             switch (setMode) {
    583             case 1:
    584                 nested->applyPattern(chars, symbols, patLocal, options, caseClosure, ec);
    585                 break;
    586             case 2:
    587                 chars.skipIgnored(opts);
    588                 nested->applyPropertyPattern(chars, patLocal, ec);
    589                 if (U_FAILURE(ec)) return;
    590                 break;
    591             case 3: // `nested' already parsed
    592                 nested->_toPattern(patLocal, FALSE);
    593                 break;
    594             }
    595 
    596             usePat = TRUE;
    597 
    598             if (mode == 0) {
    599                 // Entire pattern is a category; leave parse loop
    600                 *this = *nested;
    601                 mode = 2;
    602                 break;
    603             }
    604 
    605             switch (op) {
    606             case HYPHEN: /*'-'*/
    607                 removeAll(*nested);
    608                 break;
    609             case INTERSECTION: /*'&'*/
    610                 retainAll(*nested);
    611                 break;
    612             case 0:
    613                 addAll(*nested);
    614                 break;
    615             }
    616 
    617             op = 0;
    618             lastItem = 2;
    619 
    620             continue;
    621         }
    622 
    623         if (mode == 0) {
    624             // syntaxError(chars, "Missing '['");
    625             ec = U_MALFORMED_SET;
    626             return;
    627         }
    628 
    629         // -------- Parse special (syntax) characters.  If the
    630         // current character is not special, or if it is escaped,
    631         // then fall through and handle it below.
    632 
    633         if (!literal) {
    634             switch (c) {
    635             case 0x5D /*']'*/:
    636                 if (lastItem == 1) {
    637                     add(lastChar, lastChar);
    638                     _appendToPat(patLocal, lastChar, FALSE);
    639                 }
    640                 // Treat final trailing '-' as a literal
    641                 if (op == HYPHEN /*'-'*/) {
    642                     add(op, op);
    643                     patLocal.append(op);
    644                 } else if (op == INTERSECTION /*'&'*/) {
    645                     // syntaxError(chars, "Trailing '&'");
    646                     ec = U_MALFORMED_SET;
    647                     return;
    648                 }
    649                 patLocal.append((UChar) 0x5D /*']'*/);
    650                 mode = 2;
    651                 continue;
    652             case HYPHEN /*'-'*/:
    653                 if (op == 0) {
    654                     if (lastItem != 0) {
    655                         op = (UChar) c;
    656                         continue;
    657                     } else {
    658                         // Treat final trailing '-' as a literal
    659                         add(c, c);
    660                         c = chars.next(opts, literal, ec);
    661                         if (U_FAILURE(ec)) return;
    662                         if (c == 0x5D /*']'*/ && !literal) {
    663                             patLocal.append(HYPHEN_RIGHT_BRACE, 2);
    664                             mode = 2;
    665                             continue;
    666                         }
    667                     }
    668                 }
    669                 // syntaxError(chars, "'-' not after char or set");
    670                 ec = U_MALFORMED_SET;
    671                 return;
    672             case INTERSECTION /*'&'*/:
    673                 if (lastItem == 2 && op == 0) {
    674                     op = (UChar) c;
    675                     continue;
    676                 }
    677                 // syntaxError(chars, "'&' not after set");
    678                 ec = U_MALFORMED_SET;
    679                 return;
    680             case 0x5E /*'^'*/:
    681                 // syntaxError(chars, "'^' not after '['");
    682                 ec = U_MALFORMED_SET;
    683                 return;
    684             case 0x7B /*'{'*/:
    685                 if (op != 0) {
    686                     // syntaxError(chars, "Missing operand after operator");
    687                     ec = U_MALFORMED_SET;
    688                     return;
    689                 }
    690                 if (lastItem == 1) {
    691                     add(lastChar, lastChar);
    692                     _appendToPat(patLocal, lastChar, FALSE);
    693                 }
    694                 lastItem = 0;
    695                 buf.truncate(0);
    696                 {
    697                     UBool ok = FALSE;
    698                     while (!chars.atEnd()) {
    699                         c = chars.next(opts, literal, ec);
    700                         if (U_FAILURE(ec)) return;
    701                         if (c == 0x7D /*'}'*/ && !literal) {
    702                             ok = TRUE;
    703                             break;
    704                         }
    705                         buf.append(c);
    706                     }
    707                     if (buf.length() < 1 || !ok) {
    708                         // syntaxError(chars, "Invalid multicharacter string");
    709                         ec = U_MALFORMED_SET;
    710                         return;
    711                     }
    712                 }
    713                 // We have new string. Add it to set and continue;
    714                 // we don't need to drop through to the further
    715                 // processing
    716                 add(buf);
    717                 patLocal.append((UChar) 0x7B /*'{'*/);
    718                 _appendToPat(patLocal, buf, FALSE);
    719                 patLocal.append((UChar) 0x7D /*'}'*/);
    720                 continue;
    721             case SymbolTable::SYMBOL_REF:
    722                 //         symbols  nosymbols
    723                 // [a-$]   error    error (ambiguous)
    724                 // [a$]    anchor   anchor
    725                 // [a-$x]  var "x"* literal '$'
    726                 // [a-$.]  error    literal '$'
    727                 // *We won't get here in the case of var "x"
    728                 {
    729                     chars.getPos(backup);
    730                     c = chars.next(opts, literal, ec);
    731                     if (U_FAILURE(ec)) return;
    732                     UBool anchor = (c == 0x5D /*']'*/ && !literal);
    733                     if (symbols == 0 && !anchor) {
    734                         c = SymbolTable::SYMBOL_REF;
    735                         chars.setPos(backup);
    736                         break; // literal '$'
    737                     }
    738                     if (anchor && op == 0) {
    739                         if (lastItem == 1) {
    740                             add(lastChar, lastChar);
    741                             _appendToPat(patLocal, lastChar, FALSE);
    742                         }
    743                         add(U_ETHER);
    744                         usePat = TRUE;
    745                         patLocal.append((UChar) SymbolTable::SYMBOL_REF);
    746                         patLocal.append((UChar) 0x5D /*']'*/);
    747                         mode = 2;
    748                         continue;
    749                     }
    750                     // syntaxError(chars, "Unquoted '$'");
    751                     ec = U_MALFORMED_SET;
    752                     return;
    753                 }
    754             default:
    755                 break;
    756             }
    757         }
    758 
    759         // -------- Parse literal characters.  This includes both
    760         // escaped chars ("\u4E01") and non-syntax characters
    761         // ("a").
    762 
    763         switch (lastItem) {
    764         case 0:
    765             lastItem = 1;
    766             lastChar = c;
    767             break;
    768         case 1:
    769             if (op == HYPHEN /*'-'*/) {
    770                 if (lastChar >= c) {
    771                     // Don't allow redundant (a-a) or empty (b-a) ranges;
    772                     // these are most likely typos.
    773                     // syntaxError(chars, "Invalid range");
    774                     ec = U_MALFORMED_SET;
    775                     return;
    776                 }
    777                 add(lastChar, c);
    778                 _appendToPat(patLocal, lastChar, FALSE);
    779                 patLocal.append(op);
    780                 _appendToPat(patLocal, c, FALSE);
    781                 lastItem = 0;
    782                 op = 0;
    783             } else {
    784                 add(lastChar, lastChar);
    785                 _appendToPat(patLocal, lastChar, FALSE);
    786                 lastChar = c;
    787             }
    788             break;
    789         case 2:
    790             if (op != 0) {
    791                 // syntaxError(chars, "Set expected after operator");
    792                 ec = U_MALFORMED_SET;
    793                 return;
    794             }
    795             lastChar = c;
    796             lastItem = 1;
    797             break;
    798         }
    799     }
    800 
    801     if (mode != 2) {
    802         // syntaxError(chars, "Missing ']'");
    803         ec = U_MALFORMED_SET;
    804         return;
    805     }
    806 
    807     chars.skipIgnored(opts);
    808 
    809     /**
    810      * Handle global flags (invert, case insensitivity).  If this
    811      * pattern should be compiled case-insensitive, then we need
    812      * to close over case BEFORE COMPLEMENTING.  This makes
    813      * patterns like /[^abc]/i work.
    814      */
    815     if ((options & USET_CASE_INSENSITIVE) != 0) {
    816         (this->*caseClosure)(USET_CASE_INSENSITIVE);
    817     }
    818     else if ((options & USET_ADD_CASE_MAPPINGS) != 0) {
    819         (this->*caseClosure)(USET_ADD_CASE_MAPPINGS);
    820     }
    821     if (invert) {
    822         complement();
    823     }
    824 
    825     // Use the rebuilt pattern (patLocal) only if necessary.  Prefer the
    826     // generated pattern.
    827     if (usePat) {
    828         rebuiltPat.append(patLocal);
    829     } else {
    830         _generatePattern(rebuiltPat, FALSE);
    831     }
    832     if (isBogus() && U_SUCCESS(ec)) {
    833         // We likely ran out of memory. AHHH!
    834         ec = U_MEMORY_ALLOCATION_ERROR;
    835     }
    836 }
    837 
    838 //----------------------------------------------------------------
    839 // Property set implementation
    840 //----------------------------------------------------------------
    841 
    842 static UBool numericValueFilter(UChar32 ch, void* context) {
    843     return u_getNumericValue(ch) == *(double*)context;
    844 }
    845 
    846 static UBool generalCategoryMaskFilter(UChar32 ch, void* context) {
    847     int32_t value = *(int32_t*)context;
    848     return (U_GET_GC_MASK((UChar32) ch) & value) != 0;
    849 }
    850 
    851 static UBool versionFilter(UChar32 ch, void* context) {
    852     static const UVersionInfo none = { 0, 0, 0, 0 };
    853     UVersionInfo v;
    854     u_charAge(ch, v);
    855     UVersionInfo* version = (UVersionInfo*)context;
    856     return uprv_memcmp(&v, &none, sizeof(v)) > 0 && uprv_memcmp(&v, version, sizeof(v)) <= 0;
    857 }
    858 
    859 typedef struct {
    860     UProperty prop;
    861     int32_t value;
    862 } IntPropertyContext;
    863 
    864 static UBool intPropertyFilter(UChar32 ch, void* context) {
    865     IntPropertyContext* c = (IntPropertyContext*)context;
    866     return u_getIntPropertyValue((UChar32) ch, c->prop) == c->value;
    867 }
    868 
    869 static UBool scriptExtensionsFilter(UChar32 ch, void* context) {
    870     return uscript_hasScript(ch, *(UScriptCode*)context);
    871 }
    872 
    873 /**
    874  * Generic filter-based scanning code for UCD property UnicodeSets.
    875  */
    876 void UnicodeSet::applyFilter(UnicodeSet::Filter filter,
    877                              void* context,
    878                              int32_t src,
    879                              UErrorCode &status) {
    880     if (U_FAILURE(status)) return;
    881 
    882     // Logically, walk through all Unicode characters, noting the start
    883     // and end of each range for which filter.contain(c) is
    884     // true.  Add each range to a set.
    885     //
    886     // To improve performance, use an inclusions set which
    887     // encodes information about character ranges that are known
    888     // to have identical properties.
    889     // getInclusions(src) contains exactly the first characters of
    890     // same-value ranges for the given properties "source".
    891     const UnicodeSet* inclusions = getInclusions(src, status);
    892     if (U_FAILURE(status)) {
    893         return;
    894     }
    895 
    896     clear();
    897 
    898     UChar32 startHasProperty = -1;
    899     int32_t limitRange = inclusions->getRangeCount();
    900 
    901     for (int j=0; j<limitRange; ++j) {
    902         // get current range
    903         UChar32 start = inclusions->getRangeStart(j);
    904         UChar32 end = inclusions->getRangeEnd(j);
    905 
    906         // for all the code points in the range, process
    907         for (UChar32 ch = start; ch <= end; ++ch) {
    908             // only add to this UnicodeSet on inflection points --
    909             // where the hasProperty value changes to false
    910             if ((*filter)(ch, context)) {
    911                 if (startHasProperty < 0) {
    912                     startHasProperty = ch;
    913                 }
    914             } else if (startHasProperty >= 0) {
    915                 add(startHasProperty, ch-1);
    916                 startHasProperty = -1;
    917             }
    918         }
    919     }
    920     if (startHasProperty >= 0) {
    921         add((UChar32)startHasProperty, (UChar32)0x10FFFF);
    922     }
    923     if (isBogus() && U_SUCCESS(status)) {
    924         // We likely ran out of memory. AHHH!
    925         status = U_MEMORY_ALLOCATION_ERROR;
    926     }
    927 }
    928 
    929 static UBool mungeCharName(char* dst, const char* src, int32_t dstCapacity) {
    930     /* Note: we use ' ' in compiler code page */
    931     int32_t j = 0;
    932     char ch;
    933     --dstCapacity; /* make room for term. zero */
    934     while ((ch = *src++) != 0) {
    935         if (ch == ' ' && (j==0 || (j>0 && dst[j-1]==' '))) {
    936             continue;
    937         }
    938         if (j >= dstCapacity) return FALSE;
    939         dst[j++] = ch;
    940     }
    941     if (j > 0 && dst[j-1] == ' ') --j;
    942     dst[j] = 0;
    943     return TRUE;
    944 }
    945 
    946 //----------------------------------------------------------------
    947 // Property set API
    948 //----------------------------------------------------------------
    949 
    950 #define FAIL(ec) {ec=U_ILLEGAL_ARGUMENT_ERROR; return *this;}
    951 
    952 UnicodeSet&
    953 UnicodeSet::applyIntPropertyValue(UProperty prop, int32_t value, UErrorCode& ec) {
    954     if (U_FAILURE(ec) || isFrozen()) return *this;
    955 
    956     if (prop == UCHAR_GENERAL_CATEGORY_MASK) {
    957         applyFilter(generalCategoryMaskFilter, &value, UPROPS_SRC_CHAR, ec);
    958     } else if (prop == UCHAR_SCRIPT_EXTENSIONS) {
    959         UScriptCode script = (UScriptCode)value;
    960         applyFilter(scriptExtensionsFilter, &script, UPROPS_SRC_PROPSVEC, ec);
    961     } else {
    962         IntPropertyContext c = {prop, value};
    963         applyFilter(intPropertyFilter, &c, uprops_getSource(prop), ec);
    964     }
    965     return *this;
    966 }
    967 
    968 UnicodeSet&
    969 UnicodeSet::applyPropertyAlias(const UnicodeString& prop,
    970                                const UnicodeString& value,
    971                                UErrorCode& ec) {
    972     if (U_FAILURE(ec) || isFrozen()) return *this;
    973 
    974     // prop and value used to be converted to char * using the default
    975     // converter instead of the invariant conversion.
    976     // This should not be necessary because all Unicode property and value
    977     // names use only invariant characters.
    978     // If there are any variant characters, then we won't find them anyway.
    979     // Checking first avoids assertion failures in the conversion.
    980     if( !uprv_isInvariantUString(prop.getBuffer(), prop.length()) ||
    981         !uprv_isInvariantUString(value.getBuffer(), value.length())
    982     ) {
    983         FAIL(ec);
    984     }
    985     CharString pname, vname;
    986     pname.appendInvariantChars(prop, ec);
    987     vname.appendInvariantChars(value, ec);
    988     if (U_FAILURE(ec)) return *this;
    989 
    990     UProperty p;
    991     int32_t v;
    992     UBool mustNotBeEmpty = FALSE, invert = FALSE;
    993 
    994     if (value.length() > 0) {
    995         p = u_getPropertyEnum(pname.data());
    996         if (p == UCHAR_INVALID_CODE) FAIL(ec);
    997 
    998         // Treat gc as gcm
    999         if (p == UCHAR_GENERAL_CATEGORY) {
   1000             p = UCHAR_GENERAL_CATEGORY_MASK;
   1001         }
   1002 
   1003         if ((p >= UCHAR_BINARY_START && p < UCHAR_BINARY_LIMIT) ||
   1004             (p >= UCHAR_INT_START && p < UCHAR_INT_LIMIT) ||
   1005             (p >= UCHAR_MASK_START && p < UCHAR_MASK_LIMIT)) {
   1006             v = u_getPropertyValueEnum(p, vname.data());
   1007             if (v == UCHAR_INVALID_CODE) {
   1008                 // Handle numeric CCC
   1009                 if (p == UCHAR_CANONICAL_COMBINING_CLASS ||
   1010                     p == UCHAR_TRAIL_CANONICAL_COMBINING_CLASS ||
   1011                     p == UCHAR_LEAD_CANONICAL_COMBINING_CLASS) {
   1012                     char* end;
   1013                     double value = uprv_strtod(vname.data(), &end);
   1014                     v = (int32_t) value;
   1015                     if (v != value || v < 0 || *end != 0) {
   1016                         // non-integral or negative value, or trailing junk
   1017                         FAIL(ec);
   1018                     }
   1019                     // If the resultant set is empty then the numeric value
   1020                     // was invalid.
   1021                     mustNotBeEmpty = TRUE;
   1022                 } else {
   1023                     FAIL(ec);
   1024                 }
   1025             }
   1026         }
   1027 
   1028         else {
   1029 
   1030             switch (p) {
   1031             case UCHAR_NUMERIC_VALUE:
   1032                 {
   1033                     char* end;
   1034                     double value = uprv_strtod(vname.data(), &end);
   1035                     if (*end != 0) {
   1036                         FAIL(ec);
   1037                     }
   1038                     applyFilter(numericValueFilter, &value, UPROPS_SRC_CHAR, ec);
   1039                     return *this;
   1040                 }
   1041             case UCHAR_NAME:
   1042                 {
   1043                     // Must munge name, since u_charFromName() does not do
   1044                     // 'loose' matching.
   1045                     char buf[128]; // it suffices that this be > uprv_getMaxCharNameLength
   1046                     if (!mungeCharName(buf, vname.data(), sizeof(buf))) FAIL(ec);
   1047                     UChar32 ch = u_charFromName(U_EXTENDED_CHAR_NAME, buf, &ec);
   1048                     if (U_SUCCESS(ec)) {
   1049                         clear();
   1050                         add(ch);
   1051                         return *this;
   1052                     } else {
   1053                         FAIL(ec);
   1054                     }
   1055                 }
   1056             case UCHAR_UNICODE_1_NAME:
   1057                 // ICU 49 deprecates the Unicode_1_Name property APIs.
   1058                 FAIL(ec);
   1059             case UCHAR_AGE:
   1060                 {
   1061                     // Must munge name, since u_versionFromString() does not do
   1062                     // 'loose' matching.
   1063                     char buf[128];
   1064                     if (!mungeCharName(buf, vname.data(), sizeof(buf))) FAIL(ec);
   1065                     UVersionInfo version;
   1066                     u_versionFromString(version, buf);
   1067                     applyFilter(versionFilter, &version, UPROPS_SRC_PROPSVEC, ec);
   1068                     return *this;
   1069                 }
   1070             case UCHAR_SCRIPT_EXTENSIONS:
   1071                 v = u_getPropertyValueEnum(UCHAR_SCRIPT, vname.data());
   1072                 if (v == UCHAR_INVALID_CODE) {
   1073                     FAIL(ec);
   1074                 }
   1075                 // fall through to calling applyIntPropertyValue()
   1076                 break;
   1077             default:
   1078                 // p is a non-binary, non-enumerated property that we
   1079                 // don't support (yet).
   1080                 FAIL(ec);
   1081             }
   1082         }
   1083     }
   1084 
   1085     else {
   1086         // value is empty.  Interpret as General Category, Script, or
   1087         // Binary property.
   1088         p = UCHAR_GENERAL_CATEGORY_MASK;
   1089         v = u_getPropertyValueEnum(p, pname.data());
   1090         if (v == UCHAR_INVALID_CODE) {
   1091             p = UCHAR_SCRIPT;
   1092             v = u_getPropertyValueEnum(p, pname.data());
   1093             if (v == UCHAR_INVALID_CODE) {
   1094                 p = u_getPropertyEnum(pname.data());
   1095                 if (p >= UCHAR_BINARY_START && p < UCHAR_BINARY_LIMIT) {
   1096                     v = 1;
   1097                 } else if (0 == uprv_comparePropertyNames(ANY, pname.data())) {
   1098                     set(MIN_VALUE, MAX_VALUE);
   1099                     return *this;
   1100                 } else if (0 == uprv_comparePropertyNames(ASCII, pname.data())) {
   1101                     set(0, 0x7F);
   1102                     return *this;
   1103                 } else if (0 == uprv_comparePropertyNames(ASSIGNED, pname.data())) {
   1104                     // [:Assigned:]=[:^Cn:]
   1105                     p = UCHAR_GENERAL_CATEGORY_MASK;
   1106                     v = U_GC_CN_MASK;
   1107                     invert = TRUE;
   1108                 } else {
   1109                     FAIL(ec);
   1110                 }
   1111             }
   1112         }
   1113     }
   1114 
   1115     applyIntPropertyValue(p, v, ec);
   1116     if(invert) {
   1117         complement();
   1118     }
   1119 
   1120     if (U_SUCCESS(ec) && (mustNotBeEmpty && isEmpty())) {
   1121         // mustNotBeEmpty is set to true if an empty set indicates
   1122         // invalid input.
   1123         ec = U_ILLEGAL_ARGUMENT_ERROR;
   1124     }
   1125 
   1126     if (isBogus() && U_SUCCESS(ec)) {
   1127         // We likely ran out of memory. AHHH!
   1128         ec = U_MEMORY_ALLOCATION_ERROR;
   1129     }
   1130     return *this;
   1131 }
   1132 
   1133 //----------------------------------------------------------------
   1134 // Property set patterns
   1135 //----------------------------------------------------------------
   1136 
   1137 /**
   1138  * Return true if the given position, in the given pattern, appears
   1139  * to be the start of a property set pattern.
   1140  */
   1141 UBool UnicodeSet::resemblesPropertyPattern(const UnicodeString& pattern,
   1142                                            int32_t pos) {
   1143     // Patterns are at least 5 characters long
   1144     if ((pos+5) > pattern.length()) {
   1145         return FALSE;
   1146     }
   1147 
   1148     // Look for an opening [:, [:^, \p, or \P
   1149     return isPOSIXOpen(pattern, pos) || isPerlOpen(pattern, pos) || isNameOpen(pattern, pos);
   1150 }
   1151 
   1152 /**
   1153  * Return true if the given iterator appears to point at a
   1154  * property pattern.  Regardless of the result, return with the
   1155  * iterator unchanged.
   1156  * @param chars iterator over the pattern characters.  Upon return
   1157  * it will be unchanged.
   1158  * @param iterOpts RuleCharacterIterator options
   1159  */
   1160 UBool UnicodeSet::resemblesPropertyPattern(RuleCharacterIterator& chars,
   1161                                            int32_t iterOpts) {
   1162     // NOTE: literal will always be FALSE, because we don't parse escapes.
   1163     UBool result = FALSE, literal;
   1164     UErrorCode ec = U_ZERO_ERROR;
   1165     iterOpts &= ~RuleCharacterIterator::PARSE_ESCAPES;
   1166     RuleCharacterIterator::Pos pos;
   1167     chars.getPos(pos);
   1168     UChar32 c = chars.next(iterOpts, literal, ec);
   1169     if (c == 0x5B /*'['*/ || c == 0x5C /*'\\'*/) {
   1170         UChar32 d = chars.next(iterOpts & ~RuleCharacterIterator::SKIP_WHITESPACE,
   1171                                literal, ec);
   1172         result = (c == 0x5B /*'['*/) ? (d == 0x3A /*':'*/) :
   1173                  (d == 0x4E /*'N'*/ || d == 0x70 /*'p'*/ || d == 0x50 /*'P'*/);
   1174     }
   1175     chars.setPos(pos);
   1176     return result && U_SUCCESS(ec);
   1177 }
   1178 
   1179 /**
   1180  * Parse the given property pattern at the given parse position.
   1181  */
   1182 UnicodeSet& UnicodeSet::applyPropertyPattern(const UnicodeString& pattern,
   1183                                              ParsePosition& ppos,
   1184                                              UErrorCode &ec) {
   1185     int32_t pos = ppos.getIndex();
   1186 
   1187     UBool posix = FALSE; // true for [:pat:], false for \p{pat} \P{pat} \N{pat}
   1188     UBool isName = FALSE; // true for \N{pat}, o/w false
   1189     UBool invert = FALSE;
   1190 
   1191     if (U_FAILURE(ec)) return *this;
   1192 
   1193     // Minimum length is 5 characters, e.g. \p{L}
   1194     if ((pos+5) > pattern.length()) {
   1195         FAIL(ec);
   1196     }
   1197 
   1198     // On entry, ppos should point to one of the following locations:
   1199     // Look for an opening [:, [:^, \p, or \P
   1200     if (isPOSIXOpen(pattern, pos)) {
   1201         posix = TRUE;
   1202         pos += 2;
   1203         pos = ICU_Utility::skipWhitespace(pattern, pos);
   1204         if (pos < pattern.length() && pattern.charAt(pos) == COMPLEMENT) {
   1205             ++pos;
   1206             invert = TRUE;
   1207         }
   1208     } else if (isPerlOpen(pattern, pos) || isNameOpen(pattern, pos)) {
   1209         UChar c = pattern.charAt(pos+1);
   1210         invert = (c == UPPER_P);
   1211         isName = (c == UPPER_N);
   1212         pos += 2;
   1213         pos = ICU_Utility::skipWhitespace(pattern, pos);
   1214         if (pos == pattern.length() || pattern.charAt(pos++) != OPEN_BRACE) {
   1215             // Syntax error; "\p" or "\P" not followed by "{"
   1216             FAIL(ec);
   1217         }
   1218     } else {
   1219         // Open delimiter not seen
   1220         FAIL(ec);
   1221     }
   1222 
   1223     // Look for the matching close delimiter, either :] or }
   1224     int32_t close;
   1225     if (posix) {
   1226       close = pattern.indexOf(POSIX_CLOSE, 2, pos);
   1227     } else {
   1228       close = pattern.indexOf(CLOSE_BRACE, pos);
   1229     }
   1230     if (close < 0) {
   1231         // Syntax error; close delimiter missing
   1232         FAIL(ec);
   1233     }
   1234 
   1235     // Look for an '=' sign.  If this is present, we will parse a
   1236     // medium \p{gc=Cf} or long \p{GeneralCategory=Format}
   1237     // pattern.
   1238     int32_t equals = pattern.indexOf(EQUALS, pos);
   1239     UnicodeString propName, valueName;
   1240     if (equals >= 0 && equals < close && !isName) {
   1241         // Equals seen; parse medium/long pattern
   1242         pattern.extractBetween(pos, equals, propName);
   1243         pattern.extractBetween(equals+1, close, valueName);
   1244     }
   1245 
   1246     else {
   1247         // Handle case where no '=' is seen, and \N{}
   1248         pattern.extractBetween(pos, close, propName);
   1249 
   1250         // Handle \N{name}
   1251         if (isName) {
   1252             // This is a little inefficient since it means we have to
   1253             // parse NAME_PROP back to UCHAR_NAME even though we already
   1254             // know it's UCHAR_NAME.  If we refactor the API to
   1255             // support args of (UProperty, char*) then we can remove
   1256             // NAME_PROP and make this a little more efficient.
   1257             valueName = propName;
   1258             propName = UnicodeString(NAME_PROP, NAME_PROP_LENGTH, US_INV);
   1259         }
   1260     }
   1261 
   1262     applyPropertyAlias(propName, valueName, ec);
   1263 
   1264     if (U_SUCCESS(ec)) {
   1265         if (invert) {
   1266             complement();
   1267         }
   1268 
   1269         // Move to the limit position after the close delimiter if the
   1270         // parse succeeded.
   1271         ppos.setIndex(close + (posix ? 2 : 1));
   1272     }
   1273 
   1274     return *this;
   1275 }
   1276 
   1277 /**
   1278  * Parse a property pattern.
   1279  * @param chars iterator over the pattern characters.  Upon return
   1280  * it will be advanced to the first character after the parsed
   1281  * pattern, or the end of the iteration if all characters are
   1282  * parsed.
   1283  * @param rebuiltPat the pattern that was parsed, rebuilt or
   1284  * copied from the input pattern, as appropriate.
   1285  */
   1286 void UnicodeSet::applyPropertyPattern(RuleCharacterIterator& chars,
   1287                                       UnicodeString& rebuiltPat,
   1288                                       UErrorCode& ec) {
   1289     if (U_FAILURE(ec)) return;
   1290     UnicodeString pattern;
   1291     chars.lookahead(pattern);
   1292     ParsePosition pos(0);
   1293     applyPropertyPattern(pattern, pos, ec);
   1294     if (U_FAILURE(ec)) return;
   1295     if (pos.getIndex() == 0) {
   1296         // syntaxError(chars, "Invalid property pattern");
   1297         ec = U_MALFORMED_SET;
   1298         return;
   1299     }
   1300     chars.jumpahead(pos.getIndex());
   1301     rebuiltPat.append(pattern, 0, pos.getIndex());
   1302 }
   1303 
   1304 U_NAMESPACE_END
   1305