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); }
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]; }
//------------------------------------------------------------------------------ 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); }
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; }
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); }
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; }
/* 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; }