// The ID will be of the form A, A(), A(B), or (B), where // A and B are filter IDs.
Specs* specsA = nullptr;
Specs* specsB = nullptr;
UBool sawParen = false;
// On the first pass, look for (B) or (). If this fails, then // on the second pass, look for A, A(B), or A(). for (int32_t pass=1; pass<=2; ++pass) { if (pass == 2) {
specsA = parseFilterID(id, pos, true); if (specsA == nullptr) {
pos = start; return nullptr;
}
} if (ICU_Utility::parseChar(id, pos, OPEN_REV)) {
sawParen = true; if (!ICU_Utility::parseChar(id, pos, CLOSE_REV)) {
specsB = parseFilterID(id, pos, true); // Must close with a ')' if (specsB == nullptr || !ICU_Utility::parseChar(id, pos, CLOSE_REV)) { delete specsA;
pos = start; return nullptr;
}
} break;
}
}
// Assemble return results
SingleID* single; if (sawParen) { if (dir == FORWARD) {
SingleID* b = specsToID(specsB, FORWARD);
single = specsToID(specsA, FORWARD); // Null pointers check if (b == nullptr || single == nullptr) { delete b; delete single;
status = U_MEMORY_ALLOCATION_ERROR; return nullptr;
}
single->canonID.append(OPEN_REV)
.append(b->canonID).append(CLOSE_REV); if (specsA != nullptr) {
single->filter = specsA->filter;
} delete b;
} else {
SingleID* a = specsToID(specsA, FORWARD);
single = specsToID(specsB, FORWARD); // Check for null pointer. if (a == nullptr || single == nullptr) { delete a; delete single;
status = U_MEMORY_ALLOCATION_ERROR; return nullptr;
}
single->canonID.append(OPEN_REV)
.append(a->canonID).append(CLOSE_REV); if (specsB != nullptr) {
single->filter = specsB->filter;
} delete a;
}
} else { // assert(specsA != nullptr); if (dir == FORWARD) {
single = specsToID(specsA, FORWARD);
} else {
single = specsToSpecialInverse(*specsA, status); if (single == nullptr) {
single = specsToID(specsA, REVERSE);
}
} // Check for nullptr pointer if (single == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR; return nullptr;
}
single->filter = specsA->filter;
}
// In the forward direction, append the pattern to the // canonID. In the reverse, insert it at zero, and invert // the presence of parens ("A" <-> "(A)"). if (canonID != nullptr) { if (dir == FORWARD) { if (withParens == 1) {
pattern.insert(0, OPEN_REV);
pattern.append(CLOSE_REV);
}
canonID->append(pattern).append(ID_DELIM);
} else { if (withParens == 0) {
pattern.insert(0, OPEN_REV);
pattern.append(CLOSE_REV);
}
canonID->insert(0, pattern);
canonID->insert(pattern.length(), ID_DELIM);
}
}
}
// Parse leading global filter, if any
withParens = 0; // parens disallowed
filter = parseGlobalFilter(id, pos, dir, withParens, &canonID); if (filter != nullptr) { if (!ICU_Utility::parseChar(id, pos, ID_DELIM)) { // Not a global filter; backup and resume
canonID.truncate(0);
pos = 0;
} if (dir == FORWARD) {
globalFilter = filter;
} else { delete filter;
}
filter = nullptr;
}
UBool sawDelimiter = true; for (;;) {
SingleID* single = parseSingleID(id, pos, dir, ec); if (single == nullptr) { break;
} if (dir == FORWARD) {
list.adoptElement(single, ec);
} else {
list.insertElementAt(single, 0, ec);
} if (U_FAILURE(ec)) { goto FAIL;
} if (!ICU_Utility::parseChar(id, pos, ID_DELIM)) {
sawDelimiter = false; break;
}
}
if (list.size() == 0) { goto FAIL;
}
// Construct canonical ID for (i=0; i<list.size(); ++i) {
SingleID* single = static_cast<SingleID*>(list.elementAt(i));
canonID.append(single->canonID); if (i != (list.size()-1)) {
canonID.append(ID_DELIM);
}
}
// Parse trailing global filter, if any, and only if we saw // a trailing delimiter after the IDs. if (sawDelimiter) {
withParens = 1; // parens required
filter = parseGlobalFilter(id, pos, dir, withParens, &canonID); if (filter != nullptr) { // Don't require trailing ';', but parse it if present
ICU_Utility::parseChar(id, pos, ID_DELIM);
Transliterator* t;
int32_t i; for (i=0; i<=list.size(); ++i) { // [sic]: i<=list.size() // We run the loop too long by one, so we can // do an insert after the last element if (i==list.size()) { break;
}
SingleID* single = static_cast<SingleID*>(list.elementAt(i)); if (single->basicID.length() != 0) {
t = single->createInstance(); if (t == nullptr) {
ec = U_INVALID_ID; gotoRETURN;
}
tlist.adoptElement(t, ec); if (U_FAILURE(ec)) { gotoRETURN;
}
}
}
// An empty list is equivalent to a nullptr transliterator. if (tlist.size() == 0) {
t = createBasicInstance(UnicodeString(true, ANY_NULL, 8), nullptr); if (t == nullptr) { // Should never happen
ec = U_INTERNAL_TRANSLITERATOR_ERROR;
}
tlist.adoptElement(t, ec);
}
// If target == inverseTarget then force bidirectional => false if (bidirectional && 0==target.caseCompare(inverseTarget, U_FOLD_CASE_DEFAULT)) {
bidirectional = false;
}
Mutex lock(&LOCK);
UnicodeString *tempus = new UnicodeString(inverseTarget); // Used for null pointer check before usage. if (tempus == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR; return;
}
SPECIAL_INVERSES->put(target, tempus, status); if (bidirectional) {
tempus = new UnicodeString(target); if (tempus == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR; return;
}
SPECIAL_INVERSES->put(inverseTarget, tempus, status);
}
}
// This loop parses one of the following things with each // pass: a filter, a delimiter character (either '-' or '/'), // or a spec (source, target, or variant). for (;;) {
ICU_Utility::skipWhitespace(id, pos, true); if (pos == id.length()) { break;
}
// We are about to try to parse a spec with no delimiter // when we can no longer do so (we can only do so at the // start); break. if (delimiter == 0 && specCount > 0) { break;
}
UnicodeString spec = ICU_Utility::parseUnicodeIdentifier(id, pos); if (spec.length() == 0) { // Note that if there was a trailing delimiter, we // consume it. So Foo-, Foo/, Foo-Bar/, and Foo/Bar- // are legal. break;
}
switch (delimiter) { case0:
first = spec; break; case TARGET_SEP:
target = spec; break; case VARIANT_SEP:
variant = spec; break;
}
++specCount;
delimiter = 0;
}
// A spec with no prior character is either source or target, // depending on whether an explicit "-target" was seen. if (first.length() != 0) { if (target.length() == 0) {
target = first;
} else {
source = first;
}
}
// Must have either source or target if (source.length() == 0 && target.length() == 0) {
pos = start; return nullptr;
}
// Empty source or target defaults to ANY
UBool sawSource = true; if (source.length() == 0) {
source.setTo(ANY, 3);
sawSource = false;
} if (target.length() == 0) {
target.setTo(ANY, 3);
}
if (inverseTarget != nullptr) { // If the original ID contained "Any-" then make the // special inverse "Any-Foo"; otherwise make it "Foo". // So "Any-NFC" => "Any-NFD" but "NFC" => "NFD".
UnicodeString buf; if (specs.filter.length() != 0) {
buf.append(specs.filter);
} if (specs.sawSource) {
buf.append(ANY, 3).append(TARGET_SEP);
}
buf.append(*inverseTarget);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.