Index: src/OFXMLParser.h ================================================================== --- src/OFXMLParser.h +++ src/OFXMLParser.h @@ -165,10 +165,12 @@ of_xml_parser_string_block_t CDATAHandler; of_xml_parser_string_block_t commentHandler; of_xml_parser_unknown_entity_block_t unknownEntityHandler; #endif size_t level; + size_t lineNumber; + BOOL lastCarriageReturn; BOOL finishedParsing; } #ifdef OF_HAVE_PROPERTIES @property (retain) id delegate; @@ -316,13 +318,18 @@ * * \param path The path to the file to parse */ - (void)parseFile: (OFString*)path; +/** + * \return The current line number + */ +- (size_t)lineNumber; + /** * \return Whether the XML parser has finished parsing */ - (BOOL)finishedParsing; @end @interface OFObject (OFXMLParserDelegate) @end Index: src/OFXMLParser.m ================================================================== --- src/OFXMLParser.m +++ src/OFXMLParser.m @@ -143,10 +143,13 @@ pool = [[OFAutoreleasePool alloc] init]; dict = [OFMutableDictionary dictionaryWithKeysAndObjects: @"xml", @"http://www.w3.org/XML/1998/namespace", @"xmlns", @"http://www.w3.org/2000/xmlns/", nil]; [namespaces addObject: dict]; + + lineNumber = 1; + [pool release]; } @catch (id e) { [self release]; @throw e; } @@ -203,12 +206,24 @@ newWithClass: isa]; return; } - for (i = 0; i < size; i++) + for (i = 0; i < size; i++) { + size_t j = i; + lookup_table[state](self, selectors[state], buf, &i, &last); + + /* Ensure we don't count this character twice */ + if (i != j) + continue; + + if (buf[i] == '\r' || (buf[i] == '\n' && !lastCarriageReturn)) + lineNumber++; + + lastCarriageReturn = (buf[i] == '\r' ? YES : NO); + } /* In OF_XMLPARSER_IN_TAG, there can be only spaces */ if (size - last > 0 && state != OF_XMLPARSER_IN_TAG) [cache appendCStringWithoutUTF8Checking: buf + last length: size - last]; @@ -890,10 +905,15 @@ level--; } *last = *i + 1; } + +- (size_t)lineNumber +{ + return lineNumber; +} - (BOOL)finishedParsing { return finishedParsing; } Index: tests/OFXMLParserTests.m ================================================================== --- tests/OFXMLParserTests.m +++ tests/OFXMLParserTests.m @@ -22,10 +22,11 @@ #import "OFExceptions.h" #import "TestsAppDelegate.h" static OFString *module = @"OFXMLParser"; +static OFXMLParser *parser; static int i = 0; enum event_type { PROCESSING_INSTRUCTIONS, TAG_START, @@ -60,14 +61,15 @@ case 3: TEST(msg, et == TAG_START && [name isEqual: @"root"] && prefix == nil && ns == nil && [attrs count] == 0) break; case 4: - TEST(msg, et == STRING && [string isEqual: @"\n "]) + TEST(msg, et == STRING && [string isEqual: @"\n\n "]) break; case 5: - TEST(msg, et == CDATA && [string isEqual: @"f<]]]oo"]) + TEST(msg, et == CDATA && [string isEqual: @"f<]]]oo"] && + [parser lineNumber] == 3) break; case 6: TEST(msg, et == TAG_START && [name isEqual: @"bar"] && prefix == nil && ns == nil && attrs == nil) break; @@ -314,15 +316,14 @@ } - (void)XMLParserTests { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFXMLParser *parser; const char *str = "" - "<<>>>>\n" + "<<>>>>\r\r" " \n" - " \n" + " \r\n" " \n" " \n" " \n" " \n" @@ -351,11 +352,12 @@ else [parser parseBuffer: str + j withSize: 2]; } - TEST(@"Checking if everything was parsed", i == 32) + TEST(@"Checking if everything was parsed", + i == 32 && [parser lineNumber] == 18) TEST(@"-[finishedParsing]", [parser finishedParsing]) TEST(@"Parsing whitespaces after the document", R([parser parseString: @" \t\r\n "]))