예제 #1
0
CEList::CEList(UCollator *coll, const UnicodeString &string, UErrorCode &status)
    : ces(NULL), listMax(CELIST_BUFFER_SIZE), listSize(0)
{
    UCollationElements *elems = ucol_openElements(coll, string.getBuffer(), string.length(), &status);
    UCollationStrength strength = ucol_getStrength(coll);
    UBool toShift = ucol_getAttribute(coll, UCOL_ALTERNATE_HANDLING, &status) ==  UCOL_SHIFTED;
    uint32_t variableTop = ucol_getVariableTop(coll, &status);
    uint32_t strengthMask = 0;
    int32_t order;

    if (U_FAILURE(status)) {
        return;
    }

    // **** only set flag if string has Han(gul) ****
    // ucol_forceHanImplicit(elems, &status); -- removed for ticket #10476

    switch (strength)
    {
    default:
        strengthMask |= UCOL_TERTIARYORDERMASK;
        U_FALLTHROUGH;
    case UCOL_SECONDARY:
        strengthMask |= UCOL_SECONDARYORDERMASK;
        U_FALLTHROUGH;
    case UCOL_PRIMARY:
        strengthMask |= UCOL_PRIMARYORDERMASK;
    }

    ces = ceBuffer;

    while ((order = ucol_next(elems, &status)) != UCOL_NULLORDER) {
        UBool cont = isContinuation(order);

        order &= strengthMask;

        if (toShift && variableTop > (uint32_t)order && (order & UCOL_PRIMARYORDERMASK) != 0) {
            if (strength >= UCOL_QUATERNARY) {
                order &= UCOL_PRIMARYORDERMASK;
            } else {
                order = UCOL_IGNORABLE;
            }
        }

        if (order == UCOL_IGNORABLE) {
            continue;
        }

        if (cont) {
            order |= UCOL_CONTINUATION_MARKER;
        }

        add(order, status);
    }

    ucol_closeElements(elems);
}
예제 #2
0
const CEI *Target::nextCE(int32_t offset)
{
    UErrorCode status = U_ZERO_ERROR;
    int32_t low = -1, high = -1;
    uint32_t order;
    UBool cont = FALSE;

    if (offset >= bufferMin && offset < bufferMax) {
        return &ceb[offset];
    }

    if (bufferMax >= bufferSize || offset != bufferMax) {
        return NULL;
    }

    do {
        low   = ucol_getOffset(elements);
        order = ucol_next(elements, &status);
        high  = ucol_getOffset(elements);

        if (order == (uint32_t)UCOL_NULLORDER) {
          //high = low = -1;
            break;
        }

        cont = isContinuation(order);
        order &= strengthMask;

        if (toShift && variableTop > order && (order & UCOL_PRIMARYORDERMASK) != 0) {
            if (strength >= UCOL_QUATERNARY) {
                order &= UCOL_PRIMARYORDERMASK;
            } else {
                order = UCOL_IGNORABLE;
            }
        }
    } while (order == UCOL_IGNORABLE);

    if (cont) {
        order |= UCOL_CONTINUATION_MARKER;
    }

    ceb[offset].order = order;
    ceb[offset].lowOffset = low;
    ceb[offset].highOffset = high;

    bufferMax += 1;

    return &ceb[offset];
}
예제 #3
0
//------------------------------------------------------------------------------
std::string WebSocketFrame::toString() const
{
    std::stringstream ss;
    ss << "Flags:";
    ss << " CONT="    << (isContinuation() ? "Y" : "N");
    ss << ", TXT="    << (isText()         ? "Y" : "N");
    ss << ", BIN="    << (isBinary()       ? "Y" : "N");
    ss << ", CLOSE="  << (isClose()        ? "Y" : "N");
    ss << ", PING="   << (isPing()         ? "Y" : "N");
    ss << ", PONG="   << (isPong()         ? "Y" : "N");
    ss << ", FINAL="  << (isFinal()        ? "Y" : "N");
    ss << ", RSV1="   << (isRSV1()         ? "Y" : "N");
    ss << ", RSV2="   << (isRSV2()         ? "Y" : "N");
    ss << ", RSV3="   << (isRSV3()         ? "Y" : "N");
    ss << ", nBytes=" << size();
    ss << ", bytes="  << getText();
    
    return ss.str();
}
int Describe(char* str, int len, Object* object){
  if( isNil(object) )
    return DescribeNil(str, len, object);

  if( isConsCell(object) )
    return DescribeConsCell(str, len, object);

  if( isSymbol(object) )
    return DescribeSymbol(str, len, object);

  if( isInteger(object) )
    return DescribeInteger(str, len, object);

  if( isLambda(object) )
    return DescribeLambda(str, len, object);

  if( isPrimitiveFunc(object) )
    return DescribePrimitiveFunc(str, len, object);

  if( isContinuation(object) )
    return DescribeContinuation(str, len, object);

  if( isEnvironment(object) )
    return DescribeEnvironment(str, len, object);

  if( isBool(object) )
    return DescribeBool(str, len, object);

  if( isSpecialForm(object) )
    return DescribeSpecialForm(str, len, object);

  if( isCondition(object) )
    return DescribeCondition(str, len, object);

  if( isCharacter(object) )
    return DescribeCharacter(str, len, object);

  else
    return DescribeUnknown(str, len, object);
}
int Inspect(char* str, int len, Object* object){
  if( isNil(object) )
    return InspectNil(str, len, object);

  if( isConsCell(object) )
    return InspectConsCell(str, len, object);

  if( isSymbol(object) )
    return InspectSymbol(str, len, object);

  if( isInteger(object) )
    return InspectInteger(str, len, object);

  if( isLambda(object) )
    return InspectLambda(str, len, object);

  if( isPrimitiveFunc(object) )
    return InspectPrimitiveFunc(str, len, object);

  if( isContinuation(object) )
    return InspectContinuation(str, len, object);

  if( isEnvironment(object) )
    return InspectEnvironment(str, len, object);

  if( isBool(object) )
    return InspectBool(str, len, object);

  if( isSpecialForm(object) )
    return InspectSpecialForm(str, len, object);

  if( isCondition(object) )
    return InspectCondition(str, len, object);

  if( isCharacter(object) )
    return InspectCharacter(str, len, object);

  else
    return InspectUnknown(str, len, object);
}
예제 #6
0
int32_t CollData::minLengthInChars(const CEList *ceList, int32_t offset, int32_t *history) const
{
    // find out shortest string for the longest sequence of ces.
    // this can probably be folded with the minLengthCache...

    if (history[offset] >= 0) {
        return history[offset];
    }

    uint32_t ce = ceList->get(offset);
    int32_t maxOffset = ceList->size();
    int32_t shortestLength = INT32_MAX;
    const StringList *strings = ceToCharsStartingWith->getStringList(ce);

    if (strings != NULL) {
        int32_t stringCount = strings->size();

        for (int32_t s = 0; s < stringCount; s += 1) {
            const UnicodeString *string = strings->get(s);
            UErrorCode status = U_ZERO_ERROR;
            const CEList *ceList2 = new CEList(coll, *string, status);

            if (U_FAILURE(status)) {
                delete ceList2;
                ceList2 = NULL;
            }

            if (ceList->matchesAt(offset, ceList2)) {
                U_ASSERT(ceList2 != NULL);
                int32_t clength = ceList2->size();
                int32_t slength = string->length();
                int32_t roffset = offset + clength;
                int32_t rlength = 0;

                if (roffset < maxOffset) {
                    rlength = minLengthInChars(ceList, roffset, history);

                    if (rlength <= 0) {
                    // delete before continue to avoid memory leak.
                        delete ceList2;

                        // ignore any dead ends
                        continue;
                    }
                }

                if (shortestLength > slength + rlength) {
                    shortestLength = slength + rlength;
                }
            }

            delete ceList2;
        }
    }

    if (shortestLength == INT32_MAX) {
        // No matching strings at this offset. See if
        // the CE is in a range we can handle manually.
        if (ce >= minHan && ce < maxHan) {
            // all han have implicit orders which
            // generate two CEs.
            int32_t roffset = offset + 2;
            int32_t rlength = 0;

          //history[roffset++] = -1;
          //history[roffset++] = 1;

            if (roffset < maxOffset) {
                rlength = minLengthInChars(ceList, roffset, history);
            }

            if (rlength < 0) {
                return -1;
            }

            shortestLength = 1 + rlength;
            goto have_shortest;
        } else if (ce >= jamoLimits[0] && ce < jamoLimits[3]) {
            int32_t roffset = offset;
            int32_t rlength = 0;

            // **** this loop may not handle archaic Hangul correctly ****
            for (int32_t j = 0; roffset < maxOffset && j < 4; j += 1, roffset += 1) {
                uint32_t jce = ceList->get(roffset);

                // Some Jamo have 24-bit primary order; skip the
                // 2nd CE. This should always be OK because if
                // we're still in the loop all we've seen are
                // a series of Jamo in LVT order.
                if (isContinuation(jce)) {
                    continue;
                }

                if (j >= 3 || jce < jamoLimits[j] || jce >= jamoLimits[j + 1]) {
                    break;
                }
            }

            if (roffset == offset) {
                // we started with a non-L Jamo...
                // just say it comes from a single character
                roffset += 1;

                // See if the single Jamo has a 24-bit order.
                if (roffset < maxOffset && isContinuation(ceList->get(roffset))) {
                    roffset += 1;
                }
            }

            if (roffset < maxOffset) {
                rlength = minLengthInChars(ceList, roffset, history);
            }

            if (rlength < 0) {
                return -1;
            }

            shortestLength = 1 + rlength;
            goto have_shortest;
        }

        // Can't handle it manually either. Just move on.
        return -1;
    }

have_shortest:
    history[offset] = shortestLength;

    return shortestLength;
}
예제 #7
0
CollData::CollData(UCollator *collator, UErrorCode &status)
    : coll(NULL), ceToCharsStartingWith(NULL)
{
    // [:c:] == [[:cn:][:cc:][:co:][:cf:][:cs:]]
    // i.e. other, control, private use, format, surrogate
    U_STRING_DECL(test_pattern, "[[:assigned:]-[:c:]]", 20);
    U_STRING_INIT(test_pattern, "[[:assigned:]-[:c:]]", 20);
    USet *charsToTest = uset_openPattern(test_pattern, 20, &status);

    // Han ext. A, Han, Jamo, Hangul, Han Ext. B
    // i.e. all the characers we handle implicitly
    U_STRING_DECL(remove_pattern, "[[\\u3400-\\u9FFF][\\u1100-\\u11F9][\\uAC00-\\uD7AF][\\U00020000-\\U0002A6DF]]", 70);
    U_STRING_INIT(remove_pattern, "[[\\u3400-\\u9FFF][\\u1100-\\u11F9][\\uAC00-\\uD7AF][\\U00020000-\\U0002A6DF]]", 70);
    USet *charsToRemove = uset_openPattern(remove_pattern, 70, &status);

    if (U_FAILURE(status)) {
        return;
    }

    USet *expansions   = uset_openEmpty();
    USet *contractions = uset_openEmpty();
    int32_t itemCount;

    ceToCharsStartingWith = new CEToStringsMap(status);

    if (U_FAILURE(status)) {
        goto bail;
    }

#ifdef CLONE_COLLATOR
    coll = ucol_safeClone(collator, NULL, NULL, &status);

    if (U_FAILURE(status)) {
        goto bail;
    }
#else
    coll = collator;
#endif

    ucol_getContractionsAndExpansions(coll, contractions, expansions, FALSE, &status);

    uset_addAll(charsToTest, contractions);
    uset_addAll(charsToTest, expansions);
    uset_removeAll(charsToTest, charsToRemove);

    itemCount = uset_getItemCount(charsToTest);
    for(int32_t item = 0; item < itemCount; item += 1) {
        UChar32 start = 0, end = 0;
        UChar buffer[16];
        int32_t len = uset_getItem(charsToTest, item, &start, &end,
                                   buffer, 16, &status);

        if (len == 0) {
            for (UChar32 ch = start; ch <= end; ch += 1) {
                UnicodeString *st = new UnicodeString(ch);

                if (st == NULL) {
                    status = U_MEMORY_ALLOCATION_ERROR;
                    break;
                }

                CEList *ceList = new CEList(coll, *st, status);

                ceToCharsStartingWith->put(ceList->get(0), st, status);

                delete ceList;
                delete st;
            }
        } else if (len > 0) {
            UnicodeString *st = new UnicodeString(buffer, len);

            if (st == NULL) {
                status = U_MEMORY_ALLOCATION_ERROR;
                break;
            }

            CEList *ceList = new CEList(coll, *st, status);

            ceToCharsStartingWith->put(ceList->get(0), st, status);

            delete ceList;
            delete st;
        } else {
            // shouldn't happen...
        }

        if (U_FAILURE(status)) {
             break;
        }
    }

bail:
    uset_close(contractions);
    uset_close(expansions);
    uset_close(charsToRemove);
    uset_close(charsToTest);

    if (U_FAILURE(status)) {
        return;
    }

    UnicodeSet hanRanges(UNICODE_STRING_SIMPLE("[:Unified_Ideograph:]"), status);
    if (U_FAILURE(status)) {
        return;
    }
    UnicodeSetIterator hanIter(hanRanges);
    UnicodeString hanString;
    while(hanIter.nextRange()) {
        hanString.append(hanIter.getCodepoint());
        hanString.append(hanIter.getCodepointEnd());
    }
    // TODO: Why U+11FF? The old code had an outdated UCOL_LAST_T_JAMO=0x11F9,
    // but as of Unicode 6.3 the 11xx block is filled,
    // and there are also more Jamo T at U+D7CB..U+D7FB.
    // Maybe use [:HST=T:] and look for the end of the last range?
    // Maybe use script boundary mappings instead of this code??
    UChar  jamoRanges[] = {Hangul::JAMO_L_BASE, Hangul::JAMO_V_BASE, Hangul::JAMO_T_BASE + 1, 0x11FF};
     UnicodeString jamoString(FALSE, jamoRanges, UPRV_LENGTHOF(jamoRanges));
     CEList hanList(coll, hanString, status);
     CEList jamoList(coll, jamoString, status);
     int32_t j = 0;

     if (U_FAILURE(status)) {
         return;
     }

     for (int32_t c = 0; c < jamoList.size(); c += 1) {
         uint32_t jce = jamoList[c];

         if (! isContinuation(jce)) {
             jamoLimits[j++] = jce;
         }
     }

     jamoLimits[3] += (1 << UCOL_PRIMARYORDERSHIFT);

     minHan = 0xFFFFFFFF;
     maxHan = 0;

     for(int32_t h = 0; h < hanList.size(); h += 2) {
         uint32_t han = (uint32_t) hanList[h];

         if (han < minHan) {
             minHan = han;
         }

         if (han > maxHan) {
             maxHan = han;
         }
     }

     maxHan += (1 << UCOL_PRIMARYORDERSHIFT);
}
예제 #8
0
파일: ucoleitr.cpp 프로젝트: winlibs/icu4c
U_NAMESPACE_BEGIN

int64_t
UCollationPCE::previousProcessed(
                   int32_t            *ixLow,
                   int32_t            *ixHigh,
                   UErrorCode         *status)
{
    int64_t result = UCOL_IGNORABLE;
    int32_t  low = 0, high = 0;

    if (U_FAILURE(*status)) {
        return UCOL_PROCESSED_NULLORDER;
    }

    // pceBuffer.reset();

    while (pceBuffer.isEmpty()) {
        // buffer raw CEs up to non-ignorable primary
        RCEBuffer rceb;
        int32_t ce;
        
        // **** do we need to reset rceb, or will it always be empty at this point ****
        do {
            high = cei->getOffset();
            ce   = cei->previous(*status);
            low  = cei->getOffset();

            if (ce == UCOL_NULLORDER) {
                if (!rceb.isEmpty()) {
                    break;
                }

                goto finish;
            }

            rceb.put((uint32_t)ce, low, high, *status);
        } while (U_SUCCESS(*status) && ((ce & UCOL_PRIMARYORDERMASK) == 0 || isContinuation(ce)));

        // process the raw CEs
        while (U_SUCCESS(*status) && !rceb.isEmpty()) {
            const RCEI *rcei = rceb.get();

            result = processCE(rcei->ce);

            if (result != UCOL_IGNORABLE) {
                pceBuffer.put(result, rcei->low, rcei->high, *status);
            }
        }
        if (U_FAILURE(*status)) {
            return UCOL_PROCESSED_NULLORDER;
        }
    }

finish:
    if (pceBuffer.isEmpty()) {
        // **** Is -1 the right value for ixLow, ixHigh? ****
    	if (ixLow != NULL) {
    		*ixLow = -1;
    	}
    	
    	if (ixHigh != NULL) {
    		*ixHigh = -1
    		;
    	}
        return UCOL_PROCESSED_NULLORDER;
    }

    const PCEI *pcei = pceBuffer.get();

    if (ixLow != NULL) {
        *ixLow = pcei->low;
    }

    if (ixHigh != NULL) {
        *ixHigh = pcei->high;
    }

    return pcei->ce;
}
예제 #9
0
파일: inih.c 프로젝트: Namoshek/libelektra
/* See documentation in header file. */
int ini_parse_file (FILE * file, const struct IniConfig * config, void * user)
{
	/* Uses a fair bit of stack (use heap instead if you need to) */
	char * line;

	char section[MAX_SECTION] = "";
	char prev_name[MAX_NAME] = "";

	char * start;
	char * end;
	char * name;
	char * value;
	char delim = config->delim;
	int lineno = 0;
	int error = 0;

	line = (char *)malloc (INI_MAX_LINE);

	ELEKTRA_LOG_DEBUG ("Allocated memory for line");

	if (!line)
	{
		return -2;
	}

	/* Scan through file line by line */
	while (fgets (line, INI_MAX_LINE, file) != NULL)
	{
		lineno++;
		ELEKTRA_LOG_DEBUG ("Read line %d with content “%s”", lineno, line);

		start = line;
#if INI_ALLOW_BOM
		if (lineno == 1 && (unsigned char)start[0] == 0xEF && (unsigned char)start[1] == 0xBB && (unsigned char)start[2] == 0xBF)
		{
			start += 3;
			config->bomHandler (user, 1);
		}
		else
		{
			config->bomHandler (user, 0);
		}
#endif
		if (*start == '\n')
		{
			if (!config->commentHandler (user, "") && !error) error = lineno;
			continue;
		}
		start = lskip (line);
		if (*start == '\0')
		{
			if (!config->commentHandler (user, "") && !error) error = lineno;
			continue;
		}
		if (isContinuation (line, config) && config->supportMultiline && *prev_name)
		{
			start = line + strlen (config->continuationString);
			if (*start == '"') ++start;
			end = line + (strlen (line) - 1);
			while ((*end != '"') && (!isprint (*end)) && (end > start))
			{
				if (*end == '\n') *end = '\0';
				--end;
			}
			if (*end == '"') *end = '\0';

			if (!config->keyHandler (user, section, prev_name, start, 1) && !error) error = lineno;
		}
		else if (isSection (line))
		{
			ELEKTRA_LOG_DEBUG ("Line contains a section");
			end = line + (strlen (line) - 1);
			while (end > start)
			{
				if (*end == ']') break;
				--end;
			}
			++start;
			if (*end == ']')
			{
				*end = '\0';
				strncpy0 (section, start, sizeof (section));
				*prev_name = '\0';
				ELEKTRA_LOG_DEBUG ("Found section “%s”", section);

				size_t numberBackslashes = 0;
				for (char * endSection = section + strlen (section) - 1; endSection >= section && *endSection == '\\';
				     endSection--)
				{
					numberBackslashes++;
				}
				if (numberBackslashes % 2 != 0)
				{
					ELEKTRA_LOG_WARNING ("Found uneven number of backlashes at end of section");
					error = lineno;
					break;
				}

				if (!config->sectionHandler (user, section) && !error) error = lineno;
			}
			else
			{
				end = line + (strlen (line) - 1);
				if (*end == '\n')
				{
					strncpy0 (section, start, sizeof (section));
					while (fgets (line, INI_MAX_LINE, file))
					{
						end = line + (strlen (line) - 1);
						while ((end > line) && *end != ']')
							--end;
						if (*end == ']')
						{
							*end = '\0';
							strncpy0 (section + strlen (section), line, sizeof (section) - strlen (section));
							*prev_name = '\0';
							if (!config->sectionHandler (user, section) && !error) error = lineno;
							break;
						}
						else
						{
							strncpy0 (section + strlen (section), line, sizeof (section) - strlen (section));
						}
					}
				}
				else
				{
					error = lineno;
				}
			}
		}
		else if (isComment (line))
		{
			start = line;
			end = line + (strlen (line) - 1);
			if (*end == '\n') *end = '\0';
			if (!config->commentHandler (user, start) && !error) error = lineno;
		}
		else
		{
			ELEKTRA_LOG_DEBUG ("Line contains a key");

			char * ptr = start;
			unsigned int assign = 0;
			ELEKTRA_LOG_DEBUG ("Search for delimiter “%c”", delim);
			while (*ptr)
			{
				if (*ptr == delim)
				{
					++assign;
				}
				++ptr;
			}

			if (assign == 1)
			{
				ELEKTRA_LOG_DEBUG ("Found exactly one delimiter");
				name = start;
				end = strchr (start, delim);
				if (*name == '"')
				{
					ELEKTRA_LOG_DEBUG ("Name starts with double quote character");
					++name;
					if (*(end - 2) == '"')
					{
						*(end - 2) = '\0';
					}
					else if (*(end - 1) == '"')
					{
						*(end - 1) = '\0';
					}
					else
					{
						ELEKTRA_LOG_DEBUG ("Did not find closing double quote characters in current line");
						strncpy0 (prev_name, name, sizeof (prev_name));
						while (fgets (line, INI_MAX_LINE, file))
						{
							ELEKTRA_LOG_DEBUG ("Read continuation line with content “%s”", line);
							end = line + (strlen (line) - 1);
							while (end > line && *end != '"')
								--end;
							if (*end == '"')
							{
								ELEKTRA_LOG_DEBUG ("Found closing double quote character");
								*(end++) = '\0';
								strncpy0 (prev_name + strlen (prev_name), line,
									  sizeof (prev_name) - strlen (prev_name));
								break;
							}
							else
							{
								ELEKTRA_LOG_DEBUG ("Found name continuation");
								strncpy (prev_name + strlen (prev_name), line,
									 sizeof (prev_name) - strlen (prev_name));
							}
							ELEKTRA_LOG_DEBUG ("New extended name is “%s”", prev_name);
						}
						name = prev_name;
						ELEKTRA_LOG_DEBUG ("Name of key is “%s”", name);
					}
				}
				if (*end != delim)
				{
					ELEKTRA_LOG_DEBUG ("Search for delimiter in “%s”", end);
					ptr = lskip (end + 1);
					end = strchr (ptr, delim);
					if (end && *end == delim)
					{
						*end = '\0';
						ELEKTRA_LOG_DEBUG ("Found delimiter – New name is “%s”", end);
					}
					else
					{
						ELEKTRA_LOG_WARNING ("Unable to find delimiter");
						error = lineno;
						break;
					}
				}
				else
				{
					*end = '\0';
				}
				if (name != prev_name && end > line)
				{
					rstrip (end - 1);
				}
				value = lskip (end + 1);
				end = find_char_or_comment (value, '\0');
				if (*end == ';') *end = '\0';
				rstrip (value);
				if (*value == '"')
				{
					*(value++) = '\0';
					while ((*end != '"') && !isprint (*end) && end > value)
						--end;
					if (*end == '"') *end = '\0';
				}
				if (prev_name != name) strncpy0 (prev_name, name, sizeof (prev_name));
				if (!config->keyHandler (user, section, name, value, 0) && !error) error = lineno;
			}
			else if (assign == 0)
			{
				ELEKTRA_LOG_DEBUG ("Found no delimiter");
				if (*start == '"')
				{
					ELEKTRA_LOG_DEBUG ("Found initial double quote character");
					++start;
					end = line + (strlen (line) - 1);
					while (end > start && *end != '"')
						--end;
					if (*end == '"' && end != start)
					{
						*end = '\0';
						if (!config->keyHandler (user, section, start, NULL, 0) && !error) error = lineno;
					}
					else
					{
						ELEKTRA_LOG_DEBUG ("Did not find closing double quote character");
						strncpy0 (prev_name, start, sizeof (prev_name));
						while (fgets (line, INI_MAX_LINE, file))
						{
							end = line + (strlen (line) - 1);
							ELEKTRA_LOG_DEBUG ("Read continuation line with content “%s”", line);
							while (end > line && *end != '"')
								--end;
							if (*end == '"')
							{
								ELEKTRA_LOG_DEBUG ("Found closing double quote character");
								*end = '\0';
								strncpy0 (prev_name + strlen (prev_name), line,
									  sizeof (prev_name) - strlen (prev_name));
								break;
							}
							else
							{
								ELEKTRA_LOG_DEBUG ("Found name continuation");
								strncpy (prev_name + strlen (prev_name), line,
									 sizeof (prev_name) - strlen (prev_name));
							}
							ELEKTRA_LOG_DEBUG ("New extended name is “%s”", prev_name);
						}
						name = prev_name;
						ptr = end + 1;
						end = strchr (ptr, '=');
						if (!end) end = strchr (ptr, ':');
						if (!end)
						{
							if (!config->keyHandler (user, section, name, NULL, 0) && !error) error = lineno;
						}
						else
						{
							*end = '\0';
							value = lskip (end + 1);
							if (*value == '"') end = find_char_or_comment (value, '\0');
							if (*end == ';') *end = '\0';
							rstrip (value);
							if (*value == '"' || *(value + 1) == '"')
							{
								if (*value == '"')
									*(value++) = '\0';
								else if (*(value + 1) == '"')
								{
									*(value + 1) = '\0';
									value += 2;
								}
								while ((*end != '"') && !isprint (*end) && end > value)
									--end;
								if (*end == '"') *end = '\0';
							}
							if (prev_name != name) strncpy0 (prev_name, name, sizeof (prev_name));
							if (!config->keyHandler (user, section, name, value, 0) && !error) error = lineno;
						}
					}
				}
				else
				{
					name = rstrip (start);
					strncpy0 (prev_name, name, sizeof (prev_name));
					if (!config->keyHandler (user, section, name, NULL, 0) && !error) error = lineno;
				}
			}
			else
			{
				ELEKTRA_LOG_DEBUG ("Found multiple delimiters");
				ptr = start + 1;
				while (*ptr)
				{
					if (*ptr == delim)
					{
						if (*(ptr + 1) == '"' || *(ptr + 2) == '"' || *(ptr - 1) == '"' || *(ptr - 2) == '"') break;
					}
					++ptr;
				}
				if (*ptr)
				{
					ELEKTRA_LOG_DEBUG ("Found double quote character");
					char tmpDel[4] = { ' ', delim, ' ', '\0' };
					end = strstr (ptr, tmpDel);
					name = NULL;
					if (end)
					{
						// keyname == "=" or " = " where '=' is the delimiter
						if (*(ptr + 1) == '"')
						{
							*(ptr + 1) = '\0';
						}
						else if (*(ptr + 2) == '"')
						{
							*(ptr + 2) = '\0';
						}
						if (*(ptr - 1) == '"')
							*(ptr - 1) = '\0';
						else if (*(ptr - 2) == '"')
							*(ptr - 2) = '\0';
						name = ptr;
					}
					else if (*ptr == delim)
					{
						*ptr = '\0';
						rstrip (start);
						if (*start == '"') ++start;
						if (*(ptr - 1) == '"')
							*(ptr - 1) = '\0';
						else if (*(ptr - 2) == '"')
							*(ptr - 2) = '\0';
						name = start;
					}
					else
					{
						if (!end) end = strrstr (start + 1, tmpDel);
						*end = '\0';
						ptr = end + 2;
						rstrip (start);
						name = start;
					}
					value = ptr + 1;

					end = find_char_or_comment (value, '\0');
					if (*end == ';') *end = '\0';
					rstrip (value);
					if (*value == '"' || *(value + 1) == '"')
					{
						if (*value == '"')
							*(value++) = '\0';
						else if (*(value + 1) == '"')
						{
							*(value + 1) = '\0';
							value += 2;
						}
						while ((*end != '"') && !isprint (*end) && end > value)
							--end;
						if (*end == '"') *end = '\0';
					}
				}
				else
				{
					ELEKTRA_LOG_DEBUG ("Found no double quote character");
					rstrip (start);
					name = start;
					end = strchr (start, delim);
					if (!end)
					{
						ELEKTRA_LOG_DEBUG ("Found no delimiter");
						value = NULL;
					}
					else
					{
						ELEKTRA_LOG_DEBUG ("Found delimiter");
						if (*end == delim) *end = '\0';
						rstrip (end - 1);
						value = lskip (end + 1);
						rstrip (value);
						if (*value == '"')
						{
							*(value++) = '\0';
							while ((*end != '"') && !isprint (*end) && end > value)
								--end;
							if (*end == '"') *end = '\0';
						}
					}
				}
				strncpy0 (prev_name, name, sizeof (prev_name));

				if (!config->keyHandler (user, section, name, value, 0) && !error) error = lineno;
			}
		}

#if INI_STOP_ON_FIRST_ERROR
		if (error) break;
#endif
	}

	free (line);
	return error;
}