(*aTextCallback)(this, Substring(aAttributeValue, mark, backup), aClosure);
(*aTextCallback)(this, Substring(mark, backup), aClosure);
nsXULTemplateBuilder::ParseAttribute(const nsAReadableString& aAttributeValue,                                     void (*aVariableCallback)(nsXULTemplateBuilder*, const nsAReadableString&, void*),                                     void (*aTextCallback)(nsXULTemplateBuilder*, const nsAReadableString&, void*),                                     void* aClosure){    nsAReadableString::const_iterator done_parsing;    aAttributeValue.EndReading(done_parsing);    nsAReadableString::const_iterator iter;    aAttributeValue.BeginReading(iter);    nsAReadableString::const_iterator mark(iter), backup(iter);    for (; iter != done_parsing; backup = ++iter) {        // A variable is either prefixed with '?' (in the extended        // syntax) or "rdf:" (in the simple syntax).        PRBool isvar;        if (*iter == PRUnichar('?') && (++iter != done_parsing)) {            isvar = PR_TRUE;        }        else if ((*iter == PRUnichar('r') && (++iter != done_parsing)) &&                 (*iter == PRUnichar('d') && (++iter != done_parsing)) &&                 (*iter == PRUnichar('f') && (++iter != done_parsing)) &&                 (*iter == PRUnichar(':') && (++iter != done_parsing))) {            isvar = PR_TRUE;        }        else {            isvar = PR_FALSE;        }        if (! isvar) {            // It's not a variable, or we ran off the end of the            // string after the initial variable prefix. Since we may            // have slurped down some characters before realizing that            // fact, back up to the point where we started.            iter = backup;            continue;        }        else if (backup != mark && aTextCallback) {            // Okay, we've found a variable, and there's some vanilla            // text that's been buffered up. Flush it.            (*aTextCallback)(this, Substring(aAttributeValue, mark, backup), aClosure);        }        // Construct a substring that is the symbol we need to look up        // in the rule's symbol table. The symbol is terminated by a        // space character, a caret, or the end of the string,        // whichever comes first.        nsAReadableString::const_iterator first(backup);        PRUnichar c = 0;        while (iter != done_parsing) {            c = *iter;            if ((c == PRUnichar(' ')) || (c == PRUnichar('^')))                break;            ++iter;        }        nsAReadableString::const_iterator last(iter);        // Back up so we don't consume the terminating character        // *unless* the terminating character was a caret: the caret        // means "concatenate with no space in between".        if (c != PRUnichar('^'))            --iter;        (*aVariableCallback)(this, Substring(aAttributeValue, first, last), aClosure);        mark = iter;        ++mark;    }    if (backup != mark && aTextCallback) {        // If there's any text left over, then fire the text callback        (*aTextCallback)(this, Substring(aAttributeValue, mark, backup), aClosure);    }}