[libxml++] Parser: Throw more detailed error messages.



commit a6ac0b12f2574570f101450b880329eba7cfd6f2
Author: Kjell Ahlstedt <kjell ahlstedt bredband net>
Date:   Mon Jan 30 19:33:17 2012 +0100

    Parser: Throw more detailed error messages.
    
    * examples/dom_parser/main.cc: Add command parameters -v -e -t.
    * libxml++/exceptions/exception.[h|cc]: Add format_xml_error() and
    format_xml_parser_error().
    * libxml++/parsers/domparser.cc: Call format_xml_error() and
    format_xml_parser_error() to get more detailed messages in exceptions.
    * libxml++/parsers/parser.[h|cc]: Add [set|get]_throw_messages() and (local in
    .cc until ABI can be broken) on_parser_[error|warning](). Bug #304020.

 ChangeLog                        |   12 ++
 examples/dom_parser/main.cc      |   38 +++++++-
 libxml++/exceptions/exception.cc |   77 ++++++++++++++
 libxml++/exceptions/exception.h  |   21 ++++
 libxml++/parsers/domparser.cc    |   52 +++-------
 libxml++/parsers/parser.cc       |  208 ++++++++++++++++++++++++++++----------
 libxml++/parsers/parser.h        |   48 ++++++++-
 7 files changed, 360 insertions(+), 96 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 85b52a5..c0b6207 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2012-01-30  Kjell Ahlstedt  <kjell ahlstedt bredband net>
+
+	Parser: Throw more detailed error messages.
+
+	* examples/dom_parser/main.cc: Add command parameters -v -e -t.
+	* libxml++/exceptions/exception.[h|cc]: Add format_xml_error() and
+	format_xml_parser_error().
+	* libxml++/parsers/domparser.cc: Call format_xml_error() and
+	format_xml_parser_error() to get more detailed messages in exceptions.
+	* libxml++/parsers/parser.[h|cc]: Add [set|get]_throw_messages() and (local in
+	.cc until ABI can be broken) on_parser_[error|warning](). Bug #304020.
+
 2012-01-30  Murray Cumming  <murrayc murrayc com>
 
 	Document: Make the Document(xmlDoc*) constructor protected.
diff --git a/examples/dom_parser/main.cc b/examples/dom_parser/main.cc
index 160a45b..3508216 100644
--- a/examples/dom_parser/main.cc
+++ b/examples/dom_parser/main.cc
@@ -124,9 +124,38 @@ int main(int argc, char* argv[])
   // so we can use std::cout with UTF-8, via Glib::ustring, without exceptions.
   std::locale::global(std::locale(""));
 
+  bool validate = false;
+  bool set_throw_messages = false;
+  bool throw_messages = false;
+
+  int argi = 1;
+  while (argc > argi && *argv[argi] == '-') // option
+  {
+    switch (*(argv[argi]+1))
+    {
+      case 'v':
+        validate = true;
+        break;
+      case 't':
+       set_throw_messages = true;
+       throw_messages = true;
+       break;
+      case 'e':
+       set_throw_messages = true;
+       throw_messages = false;
+       break;
+     default:
+       std::cout << "Usage: " << argv[0] << " [-v] [-t] [-e] [filename]" << std::endl
+                 << "       -v  Validate" << std::endl
+                 << "       -t  Throw messages in an exception" << std::endl
+                 << "       -e  Write messages to stderr" << std::endl;
+       return 1;
+     }
+     argi++;
+  }
   std::string filepath;
-  if(argc > 1 )
-    filepath = argv[1]; //Allow the user to specify a different XML file to parse.
+  if(argc > argi)
+    filepath = argv[argi]; //Allow the user to specify a different XML file to parse.
   else
     filepath = "example.xml";
  
@@ -135,7 +164,10 @@ int main(int argc, char* argv[])
   {
   #endif //LIBXMLCPP_EXCEPTIONS_ENABLED 
     xmlpp::DomParser parser;
-    //parser.set_validate();
+    if (validate)
+      parser.set_validate();
+    if (set_throw_messages)
+      parser.set_throw_messages(throw_messages);
     parser.set_substitute_entities(); //We just want the text to be resolved/unescaped automatically.
     parser.parse_file(filepath);
     if(parser)
diff --git a/libxml++/exceptions/exception.cc b/libxml++/exceptions/exception.cc
index 5a4db18..da36c64 100644
--- a/libxml++/exceptions/exception.cc
+++ b/libxml++/exceptions/exception.cc
@@ -1,4 +1,6 @@
 #include "exception.h"
+#include <libxml/xmlerror.h>
+#include <libxml/parser.h>
 
 namespace xmlpp {
   
@@ -27,5 +29,80 @@ exception * exception::Clone() const
   return new exception(*this);
 }
 
+Glib::ustring format_xml_error(const _xmlError* error)
+{
+  if (!error)
+    error = xmlGetLastError();
+
+  if (!error || error->code == XML_ERR_OK)
+    return ""; // No error
+
+  Glib::ustring str;
+
+  if (error->file && *error->file != '\0')
+  {
+    str += "File ";
+    str += error->file;
+  }
+
+  if (error->line > 0)
+  {
+    str += (str.empty() ? "Line " : ", line ") + Glib::ustring::format(error->line);
+    if (error->int2 > 0)
+      str += ", column " + Glib::ustring::format(error->int2);
+  }
+
+  const bool two_lines = !str.empty();
+  if (two_lines)
+    str += ' ';
+
+  switch (error->level)
+  {
+    case XML_ERR_WARNING:
+      str += "(warning):";
+      break;
+    case XML_ERR_ERROR:
+      str += "(error):";
+      break;
+    case XML_ERR_FATAL:
+      str += "(fatal):";
+      break;
+    default:
+      str += "():";
+      break;
+  }
+
+  str += two_lines ? '\n' : ' ';
+
+  if (error->message && *error->message != '\0')
+    str += error->message;
+  else
+    str += "Error code " + Glib::ustring::format(error->code);
+
+  // If the string does not end with end-of-line, append an end-of-line.
+  if (*str.rbegin() != '\n')
+    str += '\n';
+
+  return str;
+}
+
+Glib::ustring format_xml_parser_error(const _xmlParserCtxt* parser_context)
+{
+  if (!parser_context)
+    return "Error. xmlpp::format_xml_parser_error() called with parser_context == 0\n";
+
+  const _xmlError* error = xmlCtxtGetLastError(const_cast<_xmlParserCtxt*>(parser_context));
+
+  if (!error)
+    return ""; // No error
+
+  Glib::ustring str;
+
+  if (!parser_context->wellFormed)
+    str += "Document not well-formed.\n";
+
+  return str + format_xml_error(error);
+}
+
 } //namespace xmlpp
 
diff --git a/libxml++/exceptions/exception.h b/libxml++/exceptions/exception.h
index d5c2988..0c2dd05 100644
--- a/libxml++/exceptions/exception.h
+++ b/libxml++/exceptions/exception.h
@@ -27,6 +27,11 @@
 
 #include <libxml++config.h>
 
+extern "C" {
+  struct _xmlError;
+  struct _xmlParserCtxt;
+}
+
 namespace xmlpp
 {
 
@@ -46,6 +51,22 @@ private:
   Glib::ustring message_;
 };
 
+/** Format an _xmlError struct into a text string, suitable for printing.
+ * @param error Pointer to an _xmlError struct or <tt>0</tt>. If <tt>0</tt>,
+ *              the error returned by xmlGetLastError() is used.
+ * @returns A formatted text string. If the error struct does not contain an
+ *          error (error->code == XML_ERR_OK), an empty string is returned.
+ */
+Glib::ustring format_xml_error(const _xmlError* error = 0);
+
+/** Format a parser error into a text string, suitable for printing.
+ * @param parser_context Pointer to an _xmlParserCtxt struct.
+ * @returns A formatted text string. If the parser context does not contain an
+ *          error (parser_context->lastError.code == XML_ERR_OK), an empty
+ *          string is returned.
+ */
+Glib::ustring format_xml_parser_error(const _xmlParserCtxt* parser_context);
+
 } // namespace xmlpp
 
 #endif // __LIBXMLPP_EXCEPTION_H
diff --git a/libxml++/parsers/domparser.cc b/libxml++/parsers/domparser.cc
index 17a0ec4..0bd249c 100644
--- a/libxml++/parsers/domparser.cc
+++ b/libxml++/parsers/domparser.cc
@@ -43,6 +43,7 @@ void DomParser::parse_file(const Glib::ustring& filename)
   release_underlying(); //Free any existing document.
 
   KeepBlanks k(KeepBlanks::Default);
+  xmlResetLastError();
 
   //The following is based on the implementation of xmlParseFile(), in xmlSAXParseFileWithData():
   context_ = xmlCreateFileParserCtxt(filename.c_str());
@@ -50,7 +51,7 @@ void DomParser::parse_file(const Glib::ustring& filename)
   if(!context_)
   {
     #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
-    throw internal_error("Couldn't create parsing context");
+    throw internal_error("Couldn't create parsing context\n" + format_xml_error());
     #else
     return;
     #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
@@ -70,6 +71,7 @@ void DomParser::parse_memory_raw(const unsigned char* contents, size_type bytes_
   release_underlying(); //Free any existing document.
 
   KeepBlanks k(KeepBlanks::Default);
+  xmlResetLastError();
 
   //The following is based on the implementation of xmlParseFile(), in xmlSAXParseFileWithData():
   context_ = xmlCreateMemoryParserCtxt((const char*)contents, bytes_count);
@@ -77,7 +79,7 @@ void DomParser::parse_memory_raw(const unsigned char* contents, size_type bytes_
   if(!context_)
   {
     #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
-    throw internal_error("Couldn't create parsing context");
+    throw internal_error("Couldn't create parsing context\n" + format_xml_error());
     #else
     return;
     #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
@@ -94,6 +96,7 @@ void DomParser::parse_memory(const Glib::ustring& contents)
 void DomParser::parse_context()
 {
   KeepBlanks k(KeepBlanks::Default);
+  xmlResetLastError();
 
   //The following is based on the implementation of xmlParseFile(), in xmlSAXParseFileWithData():
   //and the implementation of xmlParseMemory(), in xmlSaxParseMemoryWithData().
@@ -102,7 +105,7 @@ void DomParser::parse_context()
   if(!context_)
   {
     #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
-    throw internal_error("Context not initialized");
+    throw internal_error("Context not initialized\n" + format_xml_error());
     #else
     return;
     #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
@@ -112,26 +115,14 @@ void DomParser::parse_context()
 
   check_for_exception();
 
-  if(!context_->wellFormed)
-  {
-    release_underlying(); //Free doc_;
-
-    #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
-    throw parse_error("Document not well-formed.");
-    #else
-    return;
-    #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
-  }
+  const Glib::ustring error_str = format_xml_parser_error(context_);
 
-  if(context_->errNo != 0)
+  if(!error_str.empty())
   {
-    std::ostringstream o;
-    o << "libxml error " << context_->errNo;
-
-    release_underlying();
+    release_underlying(); //Free doc_ and context_
 
     #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
-    throw parse_error(o.str());
+    throw parse_error(error_str);
     #else
     return;
     #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
@@ -155,6 +146,7 @@ void DomParser::parse_stream(std::istream& in)
   release_underlying(); //Free any existing document.
 
   KeepBlanks k(KeepBlanks::Default);
+  xmlResetLastError();
 
   context_ = xmlCreatePushParserCtxt(
       0, // setting thoses two parameters to 0 force the parser
@@ -166,7 +158,7 @@ void DomParser::parse_stream(std::istream& in)
   if(!context_)
   {
     #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
-    throw internal_error("Couldn't create parsing context");
+    throw internal_error("Couldn't create parsing context\n" + format_xml_error());
     #else
     return;
     #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
@@ -189,26 +181,14 @@ void DomParser::parse_stream(std::istream& in)
 
   check_for_exception();
 
-  if(!context_->wellFormed)
-  {
-    release_underlying(); //Free doc_;
-
-    #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
-    throw parse_error("Document not well-formed.");
-    #else
-    return;
-    #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
-  }
+  const Glib::ustring error_str = format_xml_parser_error(context_);
 
-  if(context_->errNo != 0)
+  if(!error_str.empty())
   {
-    std::ostringstream o;
-    o << "libxml error " << context_->errNo;
-
-    release_underlying();
+    release_underlying(); //Free doc_ and context_
 
     #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
-    throw parse_error(o.str());
+    throw parse_error(error_str);
     #else
     return;
     #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
diff --git a/libxml++/parsers/parser.cc b/libxml++/parsers/parser.cc
index 3a40046..f458ed4 100644
--- a/libxml++/parsers/parser.cc
+++ b/libxml++/parsers/parser.cc
@@ -8,8 +8,41 @@
 
 #include <libxml/parser.h>
 
-#include <cstdarg> //For va_list.
 #include <memory> //For auto_ptr.
+#include <map>
+
+//TODO: See several TODOs in parser.h for changes at the next API/ABI break.
+
+namespace // anonymous
+{
+// These are new data members that can't be added to xmlpp::Parser now,
+// because it would break ABI.
+struct ExtraParserData
+{
+  // Strange default values chosen for backward compatibility.
+  ExtraParserData()
+  : throw_parser_messages_(false), throw_validity_messages_(true)
+  {}
+  Glib::ustring parser_error_;
+  Glib::ustring parser_warning_;
+  bool throw_parser_messages_;
+  bool throw_validity_messages_;
+};
+
+std::map<const xmlpp::Parser*, ExtraParserData> extra_parser_data;
+
+void on_parser_error(const xmlpp::Parser* parser, const Glib::ustring& message)
+{
+  //Throw an exception later when the whole message has been received:
+  extra_parser_data[parser].parser_error_ += message;
+}
+
+void on_parser_warning(const xmlpp::Parser* parser, const Glib::ustring& message)
+{
+  //Throw an exception later when the whole message has been received:
+  extra_parser_data[parser].parser_warning_ += message;
+}
+} // anonymous
 
 namespace xmlpp {
 
@@ -22,6 +55,8 @@ Parser::Parser()
 Parser::~Parser()
 {
   release_underlying();
+  delete exception_;
+  extra_parser_data.erase(this);
 }
 
 void Parser::set_validate(bool val)
@@ -44,6 +79,17 @@ bool Parser::get_substitute_entities() const
   return substitute_entities_;
 }
 
+void Parser::set_throw_messages(bool val)
+{
+  extra_parser_data[this].throw_parser_messages_ = val;
+  extra_parser_data[this].throw_validity_messages_ = val;
+}
+
+bool Parser::get_throw_messages() const
+{
+  return extra_parser_data[this].throw_parser_messages_;
+}
+
 void Parser::initialize_context()
 {
   //Disactivate any non-standards-compliant libxml1 features.
@@ -55,10 +101,21 @@ void Parser::initialize_context()
   //Turn on/off validation:
   context_->validate = (validate_ ? 1 : 0);
 
-  //Tell the validity context about the callbacks:
-  //(These are only called if validation is on - see above)
-  context_->vctxt.error = &callback_validity_error;
-  context_->vctxt.warning = &callback_validity_warning;
+  if (context_->sax && extra_parser_data[this].throw_parser_messages_)
+  {
+    //Tell the parser context about the callbacks.
+    context_->sax->fatalError = &callback_parser_error;
+    context_->sax->error = &callback_parser_error;
+    context_->sax->warning = &callback_parser_warning;
+  }
+
+  if (extra_parser_data[this].throw_validity_messages_)
+  {
+    //Tell the validity context about the callbacks:
+    //(These are only called if validation is on - see above)
+    context_->vctxt.error = &callback_validity_error;
+    context_->vctxt.warning = &callback_validity_warning;
+  }
 
   //Allow the callback_validity_*() methods to retrieve the C++ instance:
   context_->_private = this;
@@ -67,6 +124,8 @@ void Parser::initialize_context()
   context_->replaceEntities = (substitute_entities_ ? 1 : 0);
 
   //Clear these temporary buffers too:
+  extra_parser_data[this].parser_error_.erase();
+  extra_parser_data[this].parser_warning_.erase();
   validate_error_.erase();
   validate_warning_.erase();
 }
@@ -99,83 +158,126 @@ void Parser::on_validity_warning(const Glib::ustring& message)
   validate_warning_ += message;
 }
 
-void Parser::check_for_validity_messages()
+void Parser::check_for_validity_messages() // Also checks parser messages
 {
-  if(!validate_error_.empty())
+  Glib::ustring msg(exception_ ? exception_->what() : "");
+  bool parser_msg = false;
+  bool validity_msg = false;
+
+  if (!extra_parser_data[this].parser_error_.empty())
+  {
+    parser_msg = true;
+    msg += "\nParser error:\n" + extra_parser_data[this].parser_error_;
+    extra_parser_data[this].parser_error_.erase();
+  }
+
+  if (!extra_parser_data[this].parser_warning_.empty())
   {
-    if(!exception_)
-      exception_ = new validity_error("Validity error:\n" + validate_error_);
+    parser_msg = true;
+    msg += "\nParser warning:\n" + extra_parser_data[this].parser_warning_;
+    extra_parser_data[this].parser_warning_.erase();
+  }
 
+  if (!validate_error_.empty())
+  {
+    validity_msg = true;
+    msg += "\nValidity error:\n" + validate_error_;
     validate_error_.erase();
   }
 
-  if(!validate_warning_.empty())
+  if (!validate_warning_.empty())
   {
-    if(!exception_)
-      exception_ = new validity_error("Validity warning:\n" + validate_warning_);
-
+    validity_msg = true;
+    msg += "\nValidity warning:\n" + validate_warning_;
     validate_warning_.erase();
   }
+
+  if (parser_msg || validity_msg)
+  {
+    delete exception_;
+    if (validity_msg)
+      exception_ = new validity_error(msg);
+    else
+      exception_ = new parse_error(msg);
+  }
 }
   
-void Parser::callback_validity_error(void* context_, const char* msg, ...)
+void Parser::callback_parser_error(void* ctx, const char* msg, ...)
 {
-  //See xmlHTMLValidityError() in xmllint.c in libxml for more about this:
-  
-  xmlParserCtxtPtr context = (xmlParserCtxtPtr)context_;
-  if(context)
-  {
-    Parser* parser = static_cast<Parser*>(context->_private);
-    if(parser)
-    {
-      //Convert the ... to a string:
-      va_list arg;
-      char buff[1024]; //TODO: Larger/Shared
+  va_list var_args;
+  va_start(var_args, msg);
+  callback_error_or_warning(MsgParserError, ctx, msg, var_args);
+  va_end(var_args);
+}
 
-      va_start(arg, msg);
-      vsnprintf(buff, sizeof(buff)/sizeof(buff[0]), msg, arg);
-      va_end(arg);
+void Parser::callback_parser_warning(void* ctx, const char* msg, ...)
+{
+  va_list var_args;
+  va_start(var_args, msg);
+  callback_error_or_warning(MsgParserWarning, ctx, msg, var_args);
+  va_end(var_args);
+}
 
-      #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
-      try
-      {
-      #endif
-        parser->on_validity_error(Glib::ustring(buff));
-      #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
-      }
-      catch(const exception& e)
-      {
-        parser->handleException(e);
-      }
-      #endif
-    }
-  }
-  
+void Parser::callback_validity_error(void* ctx, const char* msg, ...)
+{
+  va_list var_args;
+  va_start(var_args, msg);
+  callback_error_or_warning(MsgValidityError, ctx, msg, var_args);
+  va_end(var_args);
+}
+
+void Parser::callback_validity_warning(void* ctx, const char* msg, ...)
+{
+  va_list var_args;
+  va_start(var_args, msg);
+  callback_error_or_warning(MsgValidityWarning, ctx, msg, var_args);
+  va_end(var_args);
 }
 
-void Parser::callback_validity_warning(void* context_, const char* msg, ...)
+void Parser::callback_error_or_warning(MsgType msg_type, void* ctx,
+                                       const char* msg, va_list var_args)
 {
   //See xmlHTMLValidityError() in xmllint.c in libxml for more about this:
   
-  xmlParserCtxtPtr context = (xmlParserCtxtPtr)context_;
+  xmlParserCtxtPtr context = (xmlParserCtxtPtr)ctx;
   if(context)
   {
     Parser* parser = static_cast<Parser*>(context->_private);
     if(parser)
     {
-      //Convert the ... to a string:
-      va_list arg;
-      char buff[1024]; //TODO: Larger/Shared
+      Glib::ustring ubuff = format_xml_error(&context->lastError);
+      if (ubuff.empty())
+      {
+        // Usually the result of formatting var_args with the format string msg
+        // is the same string as is stored in context->lastError.message.
+        // It's unnecessary to use msg and var_args, if format_xml_error()
+        // returns an error message (as it usually does).
 
-      va_start(arg, msg);
-      vsnprintf(buff, sizeof(buff)/sizeof(buff[0]), msg, arg);
-      va_end(arg);
+        //Convert the ... to a string:
+        char buff[1024];
 
+        vsnprintf(buff, sizeof(buff)/sizeof(buff[0]), msg, var_args);
+        ubuff = buff;
+      }
       #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
       try
       {
       #endif
-        parser->on_validity_warning(Glib::ustring(buff));
+        switch (msg_type)
+        {
+          case MsgParserError:
+            on_parser_error(parser, ubuff);
+            break;
+          case MsgParserWarning:
+            on_parser_warning(parser, ubuff);
+            break;
+          case MsgValidityError:
+            parser->on_validity_error(ubuff);
+            break;
+          case MsgValidityWarning:
+            parser->on_validity_warning(ubuff);
+            break;
+        }
       #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
       }
       catch(const exception& e)
@@ -189,6 +291,7 @@ void Parser::callback_validity_warning(void* context_, const char* msg, ...)
 
 void Parser::handleException(const exception& e)
 {
+  delete exception_;
   exception_ = e.Clone();
 
   if(context_)
@@ -211,4 +314,3 @@ void Parser::check_for_exception()
 
 } // namespace xmlpp
 
-
diff --git a/libxml++/parsers/parser.h b/libxml++/parsers/parser.h
index 99591b9..b6558cd 100644
--- a/libxml++/parsers/parser.h
+++ b/libxml++/parsers/parser.h
@@ -16,6 +16,7 @@
 #include <libxml++/exceptions/internal_error.h>
 
 #include <istream>
+#include <cstdarg> //For va_list.
 
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
 extern "C" {
@@ -57,6 +58,25 @@ public:
    * @returns Whether entities will be substituted during parsing.
    */
   virtual bool get_substitute_entities() const;
+
+  /** Set whether the parser will collect and throw error and warning messages.
+   * If messages are collected, they are included in an exception thrown at the
+   * end of parsing. If the messages are not collected, they are written on
+   * stderr. The messages written on stderr are slightly different, and may
+   * be preferred in a program started from the command-line.
+   *
+   * The default, if set_throw_messages() is not called, is to collect and throw
+   * only messages from validation. Other messages are written to stderr.
+   * This is for backward compatibility, and may change in the future.
+   * @param val Whether messages will be collected and thrown in an exception.
+   */
+  void set_throw_messages(bool val = true);
+
+  /** See set_throw_messages().
+   * @returns Whether messages will be collected and thrown in an exception.
+   *          The default with only validation messages thrown is returned as false.
+   */
+  bool get_throw_messages() const;
   
   /** Parse an XML document from a file.
    * @throw exception
@@ -78,24 +98,46 @@ public:
    */
   virtual void parse_stream(std::istream& in) = 0;
 
-  //TODO: Add stop_parser()/stop_parsing(), wrapping XmlStopParser()?
+  //TODO: Add stop_parser()/stop_parsing(), wrapping xmlStopParser()?
 
 protected:
   virtual void initialize_context();
   virtual void release_underlying();
 
+  //TODO: In a future ABI-break, add these virtual functions.
+  //virtual void on_parser_error(const Glib::ustring& message);
+  //virtual void on_parser_warning(const Glib::ustring& message);
   virtual void on_validity_error(const Glib::ustring& message);
   virtual void on_validity_warning(const Glib::ustring& message);
 
   virtual void handleException(const exception& e);
   virtual void check_for_exception();
+  //TODO: In a future API/ABI-break, change the name of this function to
+  // something more appropriate, such as check_for_error_and_warning_messages.
   virtual void check_for_validity_messages();
   
+  static void callback_parser_error(void* ctx, const char* msg, ...);
+  static void callback_parser_warning(void* ctx, const char* msg, ...);
   static void callback_validity_error(void* ctx, const char* msg, ...);
   static void callback_validity_warning(void* ctx, const char* msg, ...);
-  
+
+  enum MsgType
+  {
+    MsgParserError,
+    MsgParserWarning,
+    MsgValidityError,
+    MsgValidityWarning
+  };
+
+  static void callback_error_or_warning(MsgType msg_type, void* ctx,
+                                        const char* msg, va_list var_args);
+
   _xmlParserCtxt* context_;
   exception* exception_;
+  //TODO: In a future ABI-break, add these members.
+  //bool throw_messages_;
+  //Glib::ustring parser_error_;
+  //Glib::ustring parser_warning_;
   Glib::ustring validate_error_;
   Glib::ustring validate_warning_; //Built gradually - used in an exception at the end of parsing.
 
@@ -107,5 +149,3 @@ protected:
 
 #endif //__LIBXMLPP_PARSER_H
 
-
-



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]