mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-01-27 14:03:36 +03:00
error: Make xmlFormatError public
This is a useful function to get a verbose error report. Allows to remove duplicated code from runtest.c. Also reactivate check for schema parser failures.
This commit is contained in:
parent
d0eb5a7e54
commit
07c05546fa
62
error.c
62
error.c
@ -296,6 +296,8 @@ xmlSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) {
|
||||
* xmlParserPrintFileInfo:
|
||||
* @input: an xmlParserInputPtr input
|
||||
*
|
||||
* DEPRECATED: Use xmlFormatError.
|
||||
*
|
||||
* Displays the associated file and line information for the current input
|
||||
*/
|
||||
|
||||
@ -387,6 +389,8 @@ xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
|
||||
* xmlParserPrintFileContext:
|
||||
* @input: an xmlParserInputPtr input
|
||||
*
|
||||
* DEPRECATED: Use xmlFormatError.
|
||||
*
|
||||
* Displays current context within the input content for error tracking
|
||||
*/
|
||||
void
|
||||
@ -396,19 +400,19 @@ xmlParserPrintFileContext(xmlParserInputPtr input) {
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlReportError:
|
||||
* @err: the error
|
||||
* @ctx: the parser context or NULL
|
||||
* @str: the formatted error message
|
||||
* xmlFormatError:
|
||||
* @err: the error
|
||||
* @channel: callback
|
||||
* @data: user data for callback
|
||||
*
|
||||
* Report an error with its context, replace the 4 old error/warning
|
||||
* routines.
|
||||
* Report a formatted error to a printf-like callback.
|
||||
*
|
||||
* This can result in a verbose multi-line report including additional
|
||||
* information from the parser context.
|
||||
*/
|
||||
static void
|
||||
xmlReportError(xmlParserCtxtPtr ctxt, const xmlError *err)
|
||||
void
|
||||
xmlFormatError(const xmlError *err, xmlGenericErrorFunc channel, void *data)
|
||||
{
|
||||
xmlGenericErrorFunc channel;
|
||||
void *data;
|
||||
const char *message;
|
||||
const char *file;
|
||||
int line;
|
||||
@ -417,17 +421,12 @@ xmlReportError(xmlParserCtxtPtr ctxt, const xmlError *err)
|
||||
const xmlChar *name = NULL;
|
||||
xmlNodePtr node;
|
||||
xmlErrorLevel level;
|
||||
xmlParserCtxtPtr ctxt = NULL;
|
||||
xmlParserInputPtr input = NULL;
|
||||
xmlParserInputPtr cur = NULL;
|
||||
|
||||
if (err == NULL) {
|
||||
if (ctxt == NULL)
|
||||
return;
|
||||
err = &ctxt->lastError;
|
||||
}
|
||||
|
||||
channel = xmlGenericError;
|
||||
data = xmlGenericErrorContext;
|
||||
if ((err == NULL) || (channel == NULL))
|
||||
return;
|
||||
|
||||
message = err->message;
|
||||
file = err->file;
|
||||
@ -440,7 +439,14 @@ xmlReportError(xmlParserCtxtPtr ctxt, const xmlError *err)
|
||||
if (code == XML_ERR_OK)
|
||||
return;
|
||||
|
||||
if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
|
||||
if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
|
||||
(domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
|
||||
(domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
|
||||
ctxt = err->ctxt;
|
||||
}
|
||||
|
||||
if ((node != NULL) && (node->type == XML_ELEMENT_NODE) &&
|
||||
(domain != XML_FROM_SCHEMASV))
|
||||
name = node->name;
|
||||
|
||||
/*
|
||||
@ -725,7 +731,7 @@ xmlVRaiseError(xmlStructuredErrorFunc schannel,
|
||||
xmlStructuredError(xmlStructuredErrorContext, to);
|
||||
} else if (channel != NULL) {
|
||||
if ((ctxt == NULL) && (channel == xmlGenericErrorDefaultFunc))
|
||||
xmlReportError(ctxt, to);
|
||||
xmlFormatError(to, xmlGenericError, xmlGenericErrorContext);
|
||||
else
|
||||
channel(data, "%s", to->message);
|
||||
}
|
||||
@ -791,7 +797,9 @@ __xmlRaiseError(xmlStructuredErrorFunc schannel,
|
||||
void
|
||||
xmlParserError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
|
||||
{
|
||||
xmlReportError(ctx, NULL);
|
||||
xmlParserCtxtPtr ctxt = ctx;
|
||||
|
||||
xmlFormatError(&ctxt->lastError, xmlGenericError, xmlGenericErrorContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -806,7 +814,9 @@ xmlParserError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
|
||||
void
|
||||
xmlParserWarning(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
|
||||
{
|
||||
xmlReportError(ctx, NULL);
|
||||
xmlParserCtxtPtr ctxt = ctx;
|
||||
|
||||
xmlFormatError(&ctxt->lastError, xmlGenericError, xmlGenericErrorContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -821,7 +831,9 @@ xmlParserWarning(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
|
||||
void
|
||||
xmlParserValidityError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
|
||||
{
|
||||
xmlReportError(ctx, NULL);
|
||||
xmlParserCtxtPtr ctxt = ctx;
|
||||
|
||||
xmlFormatError(&ctxt->lastError, xmlGenericError, xmlGenericErrorContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -836,7 +848,9 @@ xmlParserValidityError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
|
||||
void
|
||||
xmlParserValidityWarning(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
|
||||
{
|
||||
xmlReportError(ctx, NULL);
|
||||
xmlParserCtxtPtr ctxt = ctx;
|
||||
|
||||
xmlFormatError(&ctxt->lastError, xmlGenericError, xmlGenericErrorContext);
|
||||
}
|
||||
|
||||
|
||||
|
@ -929,6 +929,10 @@ XMLPUBFUN void
|
||||
xmlParserPrintFileInfo (struct _xmlParserInput *input);
|
||||
XMLPUBFUN void
|
||||
xmlParserPrintFileContext (struct _xmlParserInput *input);
|
||||
XMLPUBFUN void
|
||||
xmlFormatError (const xmlError *err,
|
||||
xmlGenericErrorFunc channel,
|
||||
void *data);
|
||||
|
||||
/*
|
||||
* Extended error information routines
|
||||
|
@ -1,4 +1,4 @@
|
||||
I/O warning : failed to load external entity "test/schemas/import1_0bc.imp"
|
||||
I/O warning : failed to load "test/schemas/import1_0bc.imp": No such file or directory
|
||||
./test/schemas/import1_0.xsd:11: element import: Schemas parser warning : Element '{http://www.w3.org/2001/XMLSchema}import': Failed to locate a schema at location 'test/schemas/import1_0bc.imp'. Skipping the import.
|
||||
./test/schemas/import1_0.xsd:16: element import: Schemas parser warning : Element '{http://www.w3.org/2001/XMLSchema}import': Skipping import of schema located at 'test/schemas/import1_0b.imp' for the namespace 'http://BAR', since this namespace was already imported with the schema located at 'test/schemas/import1_0.imp'.
|
||||
./test/schemas/import1_0.xsd:26: element element: Schemas parser error : Element '{http://www.w3.org/2001/XMLSchema}element', attribute 'ref': The QName value '{http://BAR}bar.B' does not resolve to a(n) element declaration.
|
||||
|
314
runtest.c
314
runtest.c
@ -245,9 +245,6 @@ testExternalEntityLoader(const char *URL, const char *ID,
|
||||
static char testErrors[32769];
|
||||
static int testErrorsSize = 0;
|
||||
|
||||
#if defined(LIBXML_XINCLUDE_ENABLED) || \
|
||||
defined(LIBXML_READER_ENABLED) || \
|
||||
defined(LIBXML_SCHEMAS_ENABLED)
|
||||
static void
|
||||
testErrorHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
|
||||
va_list args;
|
||||
@ -269,297 +266,10 @@ testErrorHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
|
||||
}
|
||||
testErrors[testErrorsSize] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
channel(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
|
||||
va_list args;
|
||||
int res;
|
||||
|
||||
if (testErrorsSize >= 32768)
|
||||
return;
|
||||
va_start(args, msg);
|
||||
res = vsnprintf(&testErrors[testErrorsSize],
|
||||
32768 - testErrorsSize,
|
||||
msg, args);
|
||||
va_end(args);
|
||||
if (testErrorsSize + res >= 32768) {
|
||||
/* buffer is full */
|
||||
testErrorsSize = 32768;
|
||||
testErrors[testErrorsSize] = 0;
|
||||
} else {
|
||||
testErrorsSize += res;
|
||||
}
|
||||
testErrors[testErrorsSize] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlParserPrintFileContextInternal:
|
||||
* @input: an xmlParserInputPtr input
|
||||
*
|
||||
* Displays current context within the input content for error tracking
|
||||
*/
|
||||
|
||||
static void
|
||||
xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
|
||||
xmlGenericErrorFunc chanl, void *data ) {
|
||||
const xmlChar *cur, *base, *start;
|
||||
unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */
|
||||
xmlChar content[81]; /* space for 80 chars + line terminator */
|
||||
xmlChar *ctnt;
|
||||
|
||||
if ((input == NULL) || (input->cur == NULL))
|
||||
return;
|
||||
|
||||
cur = input->cur;
|
||||
base = input->base;
|
||||
/* skip backwards over any end-of-lines */
|
||||
while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
|
||||
cur--;
|
||||
}
|
||||
n = 0;
|
||||
/* search backwards for beginning-of-line (to max buff size) */
|
||||
while ((n++ < (sizeof(content)-1)) && (cur > base) &&
|
||||
(*(cur) != '\n') && (*(cur) != '\r'))
|
||||
cur--;
|
||||
if ((*(cur) == '\n') || (*(cur) == '\r')) {
|
||||
cur++;
|
||||
} else {
|
||||
/* skip over continuation bytes */
|
||||
while ((cur < input->cur) && ((*cur & 0xC0) == 0x80))
|
||||
cur++;
|
||||
}
|
||||
/* calculate the error position in terms of the current position */
|
||||
col = input->cur - cur;
|
||||
/* search forward for end-of-line (to max buff size) */
|
||||
n = 0;
|
||||
start = cur;
|
||||
/* copy selected text to our buffer */
|
||||
while ((*cur != 0) && (*(cur) != '\n') && (*(cur) != '\r')) {
|
||||
int len = input->end - cur;
|
||||
int c = xmlGetUTF8Char(cur, &len);
|
||||
|
||||
if ((c < 0) || (n + len > sizeof(content)-1))
|
||||
break;
|
||||
cur += len;
|
||||
n += len;
|
||||
}
|
||||
memcpy(content, start, n);
|
||||
content[n] = 0;
|
||||
/* print out the selected text */
|
||||
chanl(data ,"%s\n", content);
|
||||
/* create blank line with problem pointer */
|
||||
n = 0;
|
||||
ctnt = content;
|
||||
/* (leave buffer space for pointer + line terminator) */
|
||||
while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
|
||||
if (*(ctnt) != '\t')
|
||||
*(ctnt) = ' ';
|
||||
ctnt++;
|
||||
}
|
||||
*ctnt++ = '^';
|
||||
*ctnt = 0;
|
||||
chanl(data ,"%s\n", content);
|
||||
}
|
||||
|
||||
static void
|
||||
testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, const xmlError *err) {
|
||||
char *file = NULL;
|
||||
int line = 0;
|
||||
int code = -1;
|
||||
int domain;
|
||||
void *data = NULL;
|
||||
const char *str;
|
||||
const xmlChar *name = NULL;
|
||||
xmlNodePtr node;
|
||||
xmlErrorLevel level;
|
||||
xmlParserInputPtr input = NULL;
|
||||
xmlParserInputPtr cur = NULL;
|
||||
xmlParserCtxtPtr ctxt = NULL;
|
||||
|
||||
if (err == NULL)
|
||||
return;
|
||||
|
||||
file = err->file;
|
||||
line = err->line;
|
||||
code = err->code;
|
||||
domain = err->domain;
|
||||
level = err->level;
|
||||
node = err->node;
|
||||
if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
|
||||
(domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
|
||||
(domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
|
||||
ctxt = err->ctxt;
|
||||
}
|
||||
str = err->message;
|
||||
|
||||
if (code == XML_ERR_OK)
|
||||
return;
|
||||
|
||||
if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
|
||||
name = node->name;
|
||||
|
||||
/*
|
||||
* Maintain the compatibility with the legacy error handling
|
||||
*/
|
||||
if ((ctxt != NULL) && (ctxt->input != NULL)) {
|
||||
input = ctxt->input;
|
||||
if ((input->filename == NULL) &&
|
||||
(ctxt->inputNr > 1)) {
|
||||
cur = input;
|
||||
input = ctxt->inputTab[ctxt->inputNr - 2];
|
||||
}
|
||||
if (input->filename)
|
||||
channel(data, "%s:%d: ", input->filename, input->line);
|
||||
else if ((line != 0) && (domain == XML_FROM_PARSER))
|
||||
channel(data, "Entity: line %d: ", input->line);
|
||||
} else {
|
||||
if (file != NULL)
|
||||
channel(data, "%s:%d: ", file, line);
|
||||
else if ((line != 0) && (domain == XML_FROM_PARSER))
|
||||
channel(data, "Entity: line %d: ", line);
|
||||
}
|
||||
/*
|
||||
* Skip element name when testing schemas to make memory and streaming
|
||||
* output match.
|
||||
*/
|
||||
if ((domain != XML_FROM_SCHEMASV) && (name != NULL)) {
|
||||
channel(data, "element %s: ", name);
|
||||
}
|
||||
if (code == XML_ERR_OK)
|
||||
return;
|
||||
switch (domain) {
|
||||
case XML_FROM_PARSER:
|
||||
channel(data, "parser ");
|
||||
break;
|
||||
case XML_FROM_NAMESPACE:
|
||||
channel(data, "namespace ");
|
||||
break;
|
||||
case XML_FROM_DTD:
|
||||
case XML_FROM_VALID:
|
||||
channel(data, "validity ");
|
||||
break;
|
||||
case XML_FROM_HTML:
|
||||
channel(data, "HTML parser ");
|
||||
break;
|
||||
case XML_FROM_MEMORY:
|
||||
channel(data, "memory ");
|
||||
break;
|
||||
case XML_FROM_OUTPUT:
|
||||
channel(data, "output ");
|
||||
break;
|
||||
case XML_FROM_IO:
|
||||
channel(data, "I/O ");
|
||||
break;
|
||||
case XML_FROM_XINCLUDE:
|
||||
channel(data, "XInclude ");
|
||||
break;
|
||||
case XML_FROM_XPATH:
|
||||
channel(data, "XPath ");
|
||||
break;
|
||||
case XML_FROM_XPOINTER:
|
||||
channel(data, "parser ");
|
||||
break;
|
||||
case XML_FROM_REGEXP:
|
||||
channel(data, "regexp ");
|
||||
break;
|
||||
case XML_FROM_MODULE:
|
||||
channel(data, "module ");
|
||||
break;
|
||||
case XML_FROM_SCHEMASV:
|
||||
channel(data, "Schemas validity ");
|
||||
break;
|
||||
case XML_FROM_SCHEMASP:
|
||||
channel(data, "Schemas parser ");
|
||||
break;
|
||||
case XML_FROM_RELAXNGP:
|
||||
channel(data, "Relax-NG parser ");
|
||||
break;
|
||||
case XML_FROM_RELAXNGV:
|
||||
channel(data, "Relax-NG validity ");
|
||||
break;
|
||||
case XML_FROM_CATALOG:
|
||||
channel(data, "Catalog ");
|
||||
break;
|
||||
case XML_FROM_C14N:
|
||||
channel(data, "C14N ");
|
||||
break;
|
||||
case XML_FROM_XSLT:
|
||||
channel(data, "XSLT ");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (code == XML_ERR_OK)
|
||||
return;
|
||||
switch (level) {
|
||||
case XML_ERR_NONE:
|
||||
channel(data, ": ");
|
||||
break;
|
||||
case XML_ERR_WARNING:
|
||||
channel(data, "warning : ");
|
||||
break;
|
||||
case XML_ERR_ERROR:
|
||||
channel(data, "error : ");
|
||||
break;
|
||||
case XML_ERR_FATAL:
|
||||
channel(data, "error : ");
|
||||
break;
|
||||
}
|
||||
if (code == XML_ERR_OK)
|
||||
return;
|
||||
if (str != NULL) {
|
||||
int len;
|
||||
len = xmlStrlen((const xmlChar *)str);
|
||||
if ((len > 0) && (str[len - 1] != '\n'))
|
||||
channel(data, "%s\n", str);
|
||||
else
|
||||
channel(data, "%s", str);
|
||||
} else {
|
||||
channel(data, "%s\n", "out of memory error");
|
||||
}
|
||||
if (code == XML_ERR_OK)
|
||||
return;
|
||||
|
||||
if (ctxt != NULL) {
|
||||
if ((input != NULL) &&
|
||||
((input->buf == NULL) || (input->buf->encoder == NULL)) &&
|
||||
(code == XML_ERR_INVALID_ENCODING) &&
|
||||
(input->cur < input->end)) {
|
||||
int i;
|
||||
|
||||
channel(data, "Bytes:");
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (input->cur + i >= input->end)
|
||||
return;
|
||||
channel(data, " 0x%02X", input->cur[i]);
|
||||
}
|
||||
channel(data, "\n");
|
||||
}
|
||||
|
||||
xmlParserPrintFileContextInternal(input, channel, data);
|
||||
|
||||
if (cur != NULL) {
|
||||
if (cur->filename)
|
||||
channel(data, "%s:%d: \n", cur->filename, cur->line);
|
||||
else if ((line != 0) && (domain == XML_FROM_PARSER))
|
||||
channel(data, "Entity: line %d: \n", cur->line);
|
||||
xmlParserPrintFileContextInternal(cur, channel, data);
|
||||
}
|
||||
}
|
||||
if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
|
||||
(err->int1 < 100) &&
|
||||
(err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
|
||||
xmlChar buf[150];
|
||||
int i;
|
||||
|
||||
channel(data, "%s\n", err->str1);
|
||||
for (i=0;i < err->int1;i++)
|
||||
buf[i] = ' ';
|
||||
buf[i++] = '^';
|
||||
buf[i] = 0;
|
||||
channel(data, "%s\n", buf);
|
||||
}
|
||||
xmlFormatError(err, testErrorHandler, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -3505,6 +3215,9 @@ schemasOneTest(const char *sch,
|
||||
testErrorsSize = parseErrorsSize;
|
||||
testErrors[parseErrorsSize] = 0;
|
||||
|
||||
if (schemas == NULL)
|
||||
goto done;
|
||||
|
||||
ctxt = xmlSchemaNewValidCtxt(schemas);
|
||||
xmlSchemaSetValidStructuredErrors(ctxt, testStructuredErrorHandler,
|
||||
NULL);
|
||||
@ -3539,19 +3252,23 @@ schemasOneTest(const char *sch,
|
||||
filename);
|
||||
}
|
||||
fclose(schemasOutput);
|
||||
|
||||
if (result) {
|
||||
if (compareFiles(temp, result)) {
|
||||
fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
xmlSchemaFreeValidCtxt(ctxt);
|
||||
|
||||
done:
|
||||
if (compareFileMem(err, testErrors, testErrorsSize)) {
|
||||
fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
unlink(temp);
|
||||
xmlSchemaFreeValidCtxt(ctxt);
|
||||
}
|
||||
|
||||
free(temp);
|
||||
@ -3644,13 +3361,12 @@ schemasTest(const char *filename,
|
||||
fprintf(stderr, "don't know how to process %s\n", instance);
|
||||
continue;
|
||||
}
|
||||
if (schemas != NULL) {
|
||||
nb_tests++;
|
||||
ret = schemasOneTest(filename, instance, result, err,
|
||||
options, schemas);
|
||||
if (ret != 0)
|
||||
res = ret;
|
||||
}
|
||||
|
||||
nb_tests++;
|
||||
ret = schemasOneTest(filename, instance, result, err,
|
||||
options, schemas);
|
||||
if (ret != 0)
|
||||
res = ret;
|
||||
}
|
||||
globfree(&globbuf);
|
||||
xmlSchemaFree(schemas);
|
||||
|
Loading…
x
Reference in New Issue
Block a user