diff --git a/HTMLparser.c b/HTMLparser.c index 09a9a4b..bb521a3 100644 --- a/HTMLparser.c +++ b/HTMLparser.c @@ -4645,6 +4645,7 @@ htmlParseDocument(htmlParserCtxtPtr ctxt) { } ctxt->html = 1; ctxt->linenumbers = 1; + ctxt->columnnumbers = 1; GROW; /* * SAX: beginning of the document processing. @@ -4852,6 +4853,7 @@ htmlInitParserCtxt(htmlParserCtxtPtr ctxt) ctxt->wellFormed = 1; ctxt->replaceEntities = 0; ctxt->linenumbers = xmlLineNumbersDefaultValue; + ctxt->columnnumbers = xmlColumnNumbersDefaultValue; ctxt->html = 1; ctxt->vctxt.finishDtd = XML_CTXT_FINISH_DTD_0; ctxt->vctxt.userData = ctxt; diff --git a/SAX2.c b/SAX2.c index 94db7da..d735384 100644 --- a/SAX2.c +++ b/SAX2.c @@ -1626,10 +1626,19 @@ xmlSAX2StartElement(void *ctx, const xmlChar *fullname, const xmlChar **atts) ctxt->nodemem = -1; if (ctxt->linenumbers) { if (ctxt->input != NULL) { - if (ctxt->input->line < 65535) - ret->line = (short) ctxt->input->line; + if (ctxt->input->line < UINT_MAX) + ret->line = (unsigned int) ctxt->input->line; + else + ret->line = UINT_MAX; + } + } + + if (ctxt->columnnumbers) { + if (ctxt->input != NULL) { + if (ctxt->input->col < UINT_MAX) + ret->column = (unsigned int) ctxt->input->col; else - ret->line = 65535; + ret->column = UINT_MAX; } } @@ -1884,15 +1893,27 @@ skip: if (ctxt->linenumbers) { if (ctxt->input != NULL) { - if (ctxt->input->line < 65535) + if (ctxt->input->line < UINT_MAX) ret->line = (short) ctxt->input->line; else { - ret->line = 65535; + ret->line = UINT_MAX; if (ctxt->options & XML_PARSE_BIG_LINES) ret->psvi = (void *) ctxt->input->line; } } } + + if (ctxt->columnnumbers) { + if (ctxt->input != NULL) { + if (ctxt->input->col < UINT_MAX) + ret->column = (short) ctxt->input->col; + else { + ret->column = UINT_MAX; + //if (ctxt->options & XML_PARSE_BIG_LINES) + // ret->psvi = (void *) ctxt->input->column; + } + } + } if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue(ret); @@ -2261,10 +2282,19 @@ xmlSAX2StartElementNs(void *ctx, } if (ctxt->linenumbers) { if (ctxt->input != NULL) { - if (ctxt->input->line < 65535) - ret->line = (short) ctxt->input->line; + if (ctxt->input->line < UINT_MAX) + ret->line = (unsigned int) ctxt->input->line; else - ret->line = 65535; + ret->line = UINT_MAX; + } + } + + if (ctxt->columnnumbers) { + if (ctxt->input != NULL) { + if (ctxt->input->col < UINT_MAX) + ret->column = (unsigned int) ctxt->input->col; + else + ret->column = UINT_MAX; } } @@ -2653,12 +2683,22 @@ xmlSAX2ProcessingInstruction(void *ctx, const xmlChar *target, if (ctxt->linenumbers) { if (ctxt->input != NULL) { - if (ctxt->input->line < 65535) + if (ctxt->input->line < UINT_MAX) ret->line = (short) ctxt->input->line; else - ret->line = 65535; + ret->line = UINT_MAX; + } + } + + if (ctxt->columnnumbers) { + if (ctxt->input != NULL) { + if (ctxt->input->col < UINT_MAX) + ret->column = (short) ctxt->input->col; + else + ret->column = UINT_MAX; } } + if (ctxt->inSubset == 1) { xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret); return; @@ -2713,10 +2753,19 @@ xmlSAX2Comment(void *ctx, const xmlChar *value) if (ret == NULL) return; if (ctxt->linenumbers) { if (ctxt->input != NULL) { - if (ctxt->input->line < 65535) + if (ctxt->input->line < UINT_MAX) ret->line = (short) ctxt->input->line; else - ret->line = 65535; + ret->line = UINT_MAX; + } + } + + if (ctxt->columnnumbers) { + if (ctxt->input != NULL) { + if (ctxt->input->col < UINT_MAX) + ret->column = (short) ctxt->input->col; + else + ret->column = UINT_MAX; } } diff --git a/globals.c b/globals.c index 69002f0..0584025 100644 --- a/globals.c +++ b/globals.c @@ -155,6 +155,7 @@ xmlStrdupFunc xmlMemStrdup = (xmlStrdupFunc) xmlStrdup; #undef xmlTreeIndentString #undef xmlKeepBlanksDefaultValue #undef xmlLineNumbersDefaultValue +#undef xmlColumnNumbersDefaultValue #undef xmlLoadExtDtdDefaultValue #undef xmlParserDebugEntities #undef xmlParserVersion @@ -253,6 +254,16 @@ static int xmlPedanticParserDefaultValueThrDef = 0; int xmlLineNumbersDefaultValue = 0; static int xmlLineNumbersDefaultValueThrDef = 0; /** + * xmlColumnNumbersDefaultValue: + * + * Global setting, indicate that the parser should store the column number + * in the content field of elements in the DOM tree. + * Disabled by default since this may not be safe for old classes of + * applicaton. + */ +int xmlColumnNumbersDefaultValue = 0; +static int xmlColumnNumbersDefaultValueThrDef = 0; +/** * xmlKeepBlanksDefaultValue: * * Global setting, indicate that the parser should keep all blanks @@ -980,6 +991,23 @@ int xmlThrDefLineNumbersDefaultValue(int v) { return ret; } +#undef xmlColumnNumbersDefaultValue +int * +__xmlColumnNumbersDefaultValue(void) { + if (IS_MAIN_THREAD) + return (&xmlColumnNumbersDefaultValue); + else + return (&xmlGetGlobalState()->xmlColumnNumbersDefaultValue); +} +int xmlThrDefColumnNumbersDefaultValue(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlColumnNumbersDefaultValueThrDef; + xmlColumnNumbersDefaultValueThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} + #undef xmlLoadExtDtdDefaultValue int * __xmlLoadExtDtdDefaultValue(void) { diff --git a/include/libxml/globals.h b/include/libxml/globals.h index 9d688e0..d072924 100644 --- a/include/libxml/globals.h +++ b/include/libxml/globals.h @@ -82,6 +82,7 @@ XMLCALL xmlOutputBufferCreateFilenameDefault (xmlOutputBufferCreateFilenameFunc #undef xmlTreeIndentString #undef xmlKeepBlanksDefaultValue #undef xmlLineNumbersDefaultValue +#undef xmlColumnNumbersDefaultValue #undef xmlLoadExtDtdDefaultValue #undef xmlMalloc #undef xmlMallocAtomic @@ -143,6 +144,7 @@ struct _xmlGlobalState int xmlGetWarningsDefaultValue; int xmlKeepBlanksDefaultValue; int xmlLineNumbersDefaultValue; + int xmlColumnNumbersDefaultValue; int xmlLoadExtDtdDefaultValue; int xmlParserDebugEntities; int xmlPedanticParserDefaultValue; @@ -410,6 +412,15 @@ XMLPUBVAR int xmlLineNumbersDefaultValue; #endif XMLPUBFUN int XMLCALL xmlThrDefLineNumbersDefaultValue(int v); +XMLPUBFUN int * XMLCALL __xmlColumnNumbersDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlColumnNumbersDefaultValue \ +(*(__xmlColumnNumbersDefaultValue())) +#else +XMLPUBVAR int xmlColumnNumbersDefaultValue; +#endif +XMLPUBFUN int XMLCALL xmlThrDefColumnNumbersDefaultValue(int v); + XMLPUBFUN int * XMLCALL __xmlLoadExtDtdDefaultValue(void); #ifdef LIBXML_THREAD_ENABLED #define xmlLoadExtDtdDefaultValue \ diff --git a/include/libxml/parser.h b/include/libxml/parser.h index 1f11fd9..987f16a 100644 --- a/include/libxml/parser.h +++ b/include/libxml/parser.h @@ -257,6 +257,7 @@ struct _xmlParserCtxt { int loadsubset; /* should the external subset be loaded */ int linenumbers; /* set line number in element content */ + int columnnumbers; /* set column number in element content */ void *catalogs; /* document's own catalog */ int recovery; /* run in recovery mode */ int progressive; /* is this a progressive parsing */ diff --git a/include/libxml/tree.h b/include/libxml/tree.h index 68f92f9..7e18a01 100644 --- a/include/libxml/tree.h +++ b/include/libxml/tree.h @@ -502,7 +502,8 @@ struct _xmlNode { struct _xmlAttr *properties;/* properties list */ xmlNs *nsDef; /* namespace definitions on this node */ void *psvi; /* for type/PSVI informations */ - unsigned short line; /* line number */ + unsigned int line; /* line number */ + unsigned int column; /* column index */ unsigned short extra; /* extra data for XPath/XSLT */ }; @@ -907,6 +908,8 @@ XMLPUBFUN xmlNodePtr XMLCALL */ XMLPUBFUN long XMLCALL xmlGetLineNo (xmlNodePtr node); +XMLPUBFUN long XMLCALL + xmlGetColumnNo (xmlNodePtr node); #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED) XMLPUBFUN xmlChar * XMLCALL xmlGetNodePath (xmlNodePtr node); diff --git a/parser.c b/parser.c index 9a57b01..0288d66 100644 --- a/parser.c +++ b/parser.c @@ -12880,6 +12880,7 @@ xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx, const xmlChar *URL, ctxt->attsDefault = ctx->attsDefault; ctxt->attsSpecial = ctx->attsSpecial; ctxt->linenumbers = ctx->linenumbers; + ctxt->columnnumbers = ctx->columnnumbers; xmlParseContent(ctxt); @@ -13960,6 +13961,7 @@ xmlCreateURLParserCtxt(const char *filename, int options) if (options) xmlCtxtUseOptionsInternal(ctxt, options, NULL); ctxt->linenumbers = 1; + ctxt->columnnumbers = 1; inputStream = xmlLoadExternalEntity(filename, NULL, ctxt); if (inputStream == NULL) { @@ -15011,6 +15013,7 @@ xmlCtxtUseOptionsInternal(xmlParserCtxtPtr ctxt, int options, const char *encodi options -= XML_PARSE_BIG_LINES; } ctxt->linenumbers = 1; + ctxt->columnnumbers = 1; return (options); } diff --git a/parserInternals.c b/parserInternals.c index b8d5bbc..b8fc1d0 100644 --- a/parserInternals.c +++ b/parserInternals.c @@ -1694,6 +1694,7 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt) ctxt->validate = xmlDoValidityCheckingDefaultValue; ctxt->pedantic = xmlPedanticParserDefaultValue; ctxt->linenumbers = xmlLineNumbersDefaultValue; + ctxt->columnnumbers = xmlColumnNumbersDefaultValue; ctxt->keepBlanks = xmlKeepBlanksDefaultValue; if (ctxt->keepBlanks == 0) ctxt->sax->ignorableWhitespace = xmlSAX2IgnorableWhitespace; diff --git a/testapi.c b/testapi.c index deb8cca..e20a333 100644 --- a/testapi.c +++ b/testapi.c @@ -20580,6 +20580,37 @@ test_xmlGetLineNo(void) { return(test_ret); } +static int +test_xmlGetColumnNo(void) { + int test_ret = 0; + + int mem_base; + long ret_val; + xmlNodePtr node; /* valid node */ + int n_node; + + for (n_node = 0;n_node < gen_nb_xmlNodePtr;n_node++) { + mem_base = xmlMemBlocks(); + node = gen_xmlNodePtr(n_node, 0); + + ret_val = xmlGetColumnNo(node); + desret_long(ret_val); + call_tests++; + des_xmlNodePtr(n_node, node, 0); + xmlResetLastError(); + if (mem_base != xmlMemBlocks()) { + printf("Leak of %d blocks found in xmlGetColumnNo", + xmlMemBlocks() - mem_base); + test_ret++; + printf(" %d", n_node); + printf("\n"); + } + } + function_tests++; + + return(test_ret); +} + static int test_xmlGetNoNsProp(void) { @@ -24245,6 +24276,7 @@ test_tree(void) { test_ret += test_xmlGetIntSubset(); test_ret += test_xmlGetLastChild(); test_ret += test_xmlGetLineNo(); + test_ret += test_xmlGetColumnNo(); test_ret += test_xmlGetNoNsProp(); test_ret += test_xmlGetNodePath(); test_ret += test_xmlGetNsList(); diff --git a/tree.c b/tree.c index df6f608..7a76a5d 100644 --- a/tree.c +++ b/tree.c @@ -4192,6 +4192,7 @@ xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, }else{ if (node->type == XML_ELEMENT_NODE) ret->line = node->line; + ret->column = node->column; } if (parent != NULL) { xmlNodePtr tmp; @@ -4551,7 +4552,7 @@ xmlGetLineNoInternal(xmlNodePtr node, int depth) (node->type == XML_TEXT_NODE) || (node->type == XML_COMMENT_NODE) || (node->type == XML_PI_NODE)) { - if (node->line == 65535) { + if (node->line == UINT_MAX) { if ((node->type == XML_TEXT_NODE) && (node->psvi != NULL)) result = (long) node->psvi; else if ((node->type == XML_ELEMENT_NODE) && @@ -4562,7 +4563,7 @@ xmlGetLineNoInternal(xmlNodePtr node, int depth) else if (node->prev != NULL) result = xmlGetLineNoInternal(node->prev, depth + 1); } - if ((result == -1) || (result == 65535)) + if ((result == -1) || (result == UINT_MAX)) result = (long) node->line; } else if ((node->prev != NULL) && ((node->prev->type == XML_ELEMENT_NODE) || @@ -4593,6 +4594,40 @@ xmlGetLineNo(xmlNodePtr node) return(xmlGetLineNoInternal(node, 0)); } +/** + * xmlGetColumnNo: + * @node: valid node + * + * Get column number of @node. This requires activation of this option + * before invoking the parser by calling xmlColumnNumbersDefault(1) + * + * Returns the col number if successful, -1 otherwise + */ +long +xmlGetColumnNo(xmlNodePtr node) +{ + long result = -1; + + if (!node) + return result; + if ((node->type == XML_ELEMENT_NODE) || + (node->type == XML_TEXT_NODE) || + (node->type == XML_COMMENT_NODE) || + (node->type == XML_PI_NODE)) + result = (long) node->column; + else if ((node->prev != NULL) && + ((node->prev->type == XML_ELEMENT_NODE) || + (node->prev->type == XML_TEXT_NODE) || + (node->prev->type == XML_COMMENT_NODE) || + (node->prev->type == XML_PI_NODE))) + result = xmlGetColumnNo(node->prev); + else if ((node->parent != NULL) && + (node->parent->type == XML_ELEMENT_NODE)) + result = xmlGetColumnNo(node->parent); + + return result; +} + #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED) /** * xmlGetNodePath: @@ -9143,6 +9178,7 @@ ns_end: if (cur->type == XML_ELEMENT_NODE) { cur->psvi = NULL; cur->line = 0; + cur->column = 0; cur->extra = 0; /* * Walk attributes. diff --git a/xmlreader.c b/xmlreader.c index c6ca46e..97771ad 100644 --- a/xmlreader.c +++ b/xmlreader.c @@ -2140,6 +2140,7 @@ xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) { ret->ctxt->parseMode = XML_PARSE_READER; ret->ctxt->_private = ret; ret->ctxt->linenumbers = 1; + ret->ctxt->columnnumbers = 1; ret->ctxt->dictNames = 1; ret->allocs = XML_TEXTREADER_CTXT; /* @@ -5217,6 +5218,7 @@ xmlTextReaderSetup(xmlTextReaderPtr reader, } reader->ctxt->_private = reader; reader->ctxt->linenumbers = 1; + reader->ctxt->columnnumbers = 1; reader->ctxt->dictNames = 1; /* * use the parser dictionnary to allocate all elements and attributes names diff --git a/xmlschemas.c b/xmlschemas.c index c3a080f..0d32870 100644 --- a/xmlschemas.c +++ b/xmlschemas.c @@ -28785,6 +28785,7 @@ xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt, xmlCtxtUseOptions(pctxt, options); #endif pctxt->linenumbers = 1; + pctxt->columnnumbers = 1; xmlSchemaValidateSetLocator(ctxt, xmlSchemaValidateStreamLocator, pctxt); inputStream = xmlNewIOInputStream(pctxt, input, enc);;