Hello,

first of the (on the NXLog's "Community Forum") announced patches:
this allows the pm_pattern configuration (the XML) to be split into
several files using external XML entity references, i.e.

main.xml:
    <?xml version='1.0' encoding='UTF-8'?>
    <!DOCTYPE patterndb [
        <!ENTITY group1 SYSTEM "group1.xml">
    ]>
    <patterndb>
        &group1;
        <group><id>2</id>...
    ...

group1.xml:
    <?xml version='1.0' encoding='UTF-8'?>
    <group><id>1</id>...
    ...

To implement this, I must have made a little "hack" to influence the
code generated by xcc: I have defined a macro XML_SetUserData which
later replaces the call to original (Expat) function XML_SetUserData()
in xcc_run() to also register my external entity handler.

To have a more user-friendly XML parser error reporting, I have
re-implemented xcc's exception handler to also print line numbers (and
file names as well), which closes the "FIXME implement own error
handler...". To do so, I must have added a pointer to XML_Parser to
the nx_patterndb_parser_data_t structure (and fill it using the before
mentioned hack).

I tried to unify error messages as much as possible without completely
rewriting the xcc's included code. In xcc_run(), general (well-formed)
XML errors are printed to stderr using xcc_error(), which can not be
avoided (even using macro hacks). So I directed all other errors to
stderr as well, the only message which goes into internal log is the
final one stating the module's configuration failed:

xcc: unexpected "name" in the context of "id"
        in entity 'bar.xml' at line 2
xcc: parse error in entity 'bar.xml' at line 2:
        mismatched tag
xcc: parse error in entity 'foo.xml' at line 2:
        error in processing external entity reference
xcc: parse error at line 42:
        error in processing external entity reference
2016-01-09 23:42:17 ERROR failed to parse pattern database 'test.xml'

This shows the output of testing run, everything on stderr, only the
last line comes from internal log. The main configuration file is
"test.xml", at line 42 it references "foo.xml", which in turn
references "bar.xml". The "bar.xml" contains a validity error
(...<id><name>...). The above lines 2 and 3 are redundant, but only
for validity errors (not for not-well-formed errors).

The added member "level" in the structure nx_patterndb_parser_data_t
is used only in the exception handler to differentiate top level
entity from referenced entities: on top level, we do not print file
name, only line numbers (in accordance with the xcc code).

The patch is made against 2.8.1248, the last published source version.
>From the last changelog, I believe it applies to current version as
well. I have added a note citing my name and the change (as required
by the LICENSE). Tested on Debian Jessie x86_64. To review the patch,
look at the patterndb_parser.xcc changes at the end: the patch begins
with generated .c file to be complete.

Milan
diff -Naur nxlog-ce-2.8.1248.old/src/modules/processor/pattern/patterndb_parser.c nxlog-ce-2.8.1248/src/modules/processor/pattern/patterndb_parser.c
--- nxlog-ce-2.8.1248.old/src/modules/processor/pattern/patterndb_parser.c	2014-07-19 15:52:33.000000000 +0200
+++ nxlog-ce-2.8.1248/src/modules/processor/pattern/patterndb_parser.c	2016-01-09 23:15:52.384154970 +0100
@@ -7,10 +7,14 @@
  * See the file LICENSE in the source root for licensing terms.
  * Website: http://nxlog.org
  * Author: Botond Botyanszki <botond.botyans...@nxlog.org>
+ * Modified: Milan Krcmar <milan.krc...@gmail.com> Sat, 09 Jan 2016
+ * - add line numbers to exception handler's output
+ * - allow the parsed XML to reference external system entities
  */
 
 #include "patterndb.h"
 #include "../../../common/exception.h"
+#include <expat.h>
 
 #define NX_LOGMODULE NX_LOGMODULE_MODULE
 
@@ -19,14 +23,25 @@
     apr_pool_t *pool; ///< parent pool
     nx_patterndb_t *patterndb;
     const char *filename;
+    XML_Parser xp;
+    int level;
 } nx_patterndb_parser_data_t;
 
 #define XCC_GET_PATTERNDB(X) (((nx_patterndb_parser_data_t *) ((XCCParserData *)(X))->udata)->patterndb)
 #define XCC_GET_PATTERNDB_POOL(X) ((((nx_patterndb_parser_data_t *) ((XCCParserData *)(X))->udata)->patterndb)->pool)
 #define XCC_GET_FILENAME(X) (((nx_patterndb_parser_data_t *) ((XCCParserData *)(X))->udata)->filename)
 
+int nx_external_entity_handler(XML_Parser xp, const XML_Char *context,
+    const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId);
+
+#define XML_SetUserData(p, userData) { \
+    XML_SetUserData(p, userData); \
+    XML_SetExternalEntityRefHandler(p, nx_external_entity_handler); \
+    ((nx_patterndb_parser_data_t *)((XCCParserData *)userData)->udata)->xp = p; \
+}
+
     
-#line 30 "patterndb_parser.c"
+#line 45 "patterndb_parser.c"
 /*
  * XCC - XML Compiler-Compiler
  * 
@@ -846,14 +861,14 @@
 
     switch (element_id) {
     case 1: /* patterndb */
-#line 35 "patterndb_parser.xcc"
+#line 50 "patterndb_parser.xcc"
 
      
          element.patterndb = nx_patterndb_new(((const nx_patterndb_parser_data_t *) ((const XCCParserData *)(pdata))->udata)->pool);
          XCC_GET_PATTERNDB(pdata) = element.patterndb;
       
     
-#line 857 "patterndb_parser.c"
+#line 872 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -874,13 +889,13 @@
         }
         break;
     case 2: /* group */
-#line 42 "patterndb_parser.xcc"
+#line 57 "patterndb_parser.xcc"
 
      
         element.patterngroup = nx_patterngroup_new(XCC_GET_PATTERNDB(pdata));
      
     
-#line 884 "patterndb_parser.c"
+#line 899 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -901,13 +916,13 @@
         }
         break;
     case 3: /* pattern */
-#line 48 "patterndb_parser.xcc"
+#line 63 "patterndb_parser.xcc"
 
      
         element.pattern = nx_pattern_new(XCC_GET_PATTERNDB(pdata));
      
     
-#line 911 "patterndb_parser.c"
+#line 926 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -928,13 +943,13 @@
         }
         break;
     case 4: /* matchfield */
-#line 54 "patterndb_parser.xcc"
+#line 69 "patterndb_parser.xcc"
 
      
         element.matchfield = nx_pattern_matchfield_new(XCC_GET_PATTERNDB(pdata));
      
     
-#line 938 "patterndb_parser.c"
+#line 953 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -955,13 +970,13 @@
         }
         break;
     case 5: /* capturedfield */
-#line 60 "patterndb_parser.xcc"
+#line 75 "patterndb_parser.xcc"
 
      
         element.capturedfield = apr_pcalloc(XCC_GET_PATTERNDB_POOL(pdata), sizeof(nx_pattern_capturedfield_t));
      
     
-#line 965 "patterndb_parser.c"
+#line 980 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -982,13 +997,13 @@
         }
         break;
     case 6: /* field */
-#line 73 "patterndb_parser.xcc"
+#line 88 "patterndb_parser.xcc"
 
      
         element.field = malloc(sizeof(nx_pattern_field_t));
      
     
-#line 992 "patterndb_parser.c"
+#line 1007 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -1009,10 +1024,10 @@
         }
         break;
     case 7: /* type */
-#line 32 "patterndb_parser.xcc"
+#line 47 "patterndb_parser.xcc"
 
     
-#line 1016 "patterndb_parser.c"
+#line 1031 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -1033,10 +1048,10 @@
         }
         break;
     case 8: /* fieldname */
-#line 32 "patterndb_parser.xcc"
+#line 47 "patterndb_parser.xcc"
 
     
-#line 1040 "patterndb_parser.c"
+#line 1055 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -1057,10 +1072,10 @@
         }
         break;
     case 9: /* name */
-#line 32 "patterndb_parser.xcc"
+#line 47 "patterndb_parser.xcc"
 
     
-#line 1064 "patterndb_parser.c"
+#line 1079 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -1081,10 +1096,10 @@
         }
         break;
     case 10: /* description */
-#line 32 "patterndb_parser.xcc"
+#line 47 "patterndb_parser.xcc"
 
     
-#line 1088 "patterndb_parser.c"
+#line 1103 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -1105,10 +1120,10 @@
         }
         break;
     case 11: /* value */
-#line 32 "patterndb_parser.xcc"
+#line 47 "patterndb_parser.xcc"
 
     
-#line 1112 "patterndb_parser.c"
+#line 1127 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -1129,10 +1144,10 @@
         }
         break;
     case 12: /* id */
-#line 32 "patterndb_parser.xcc"
+#line 47 "patterndb_parser.xcc"
 
     
-#line 1136 "patterndb_parser.c"
+#line 1151 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -1153,10 +1168,10 @@
         }
         break;
     case 13: /* exec */
-#line 32 "patterndb_parser.xcc"
+#line 47 "patterndb_parser.xcc"
 
     
-#line 1160 "patterndb_parser.c"
+#line 1175 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -1177,10 +1192,10 @@
         }
         break;
     case 14: /* created */
-#line 29 "patterndb_parser.xcc"
+#line 44 "patterndb_parser.xcc"
 
     
-#line 1184 "patterndb_parser.c"
+#line 1199 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -1201,10 +1216,10 @@
         }
         break;
     case 15: /* version */
-#line 29 "patterndb_parser.xcc"
+#line 44 "patterndb_parser.xcc"
 
     
-#line 1208 "patterndb_parser.c"
+#line 1223 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -1225,14 +1240,14 @@
         }
         break;
     case 16: /* set */
-#line 66 "patterndb_parser.xcc"
+#line 81 "patterndb_parser.xcc"
 
      
         element.field_list = apr_pcalloc(XCC_GET_PATTERNDB_POOL(pdata), sizeof(nx_logdata_field_list_t));
         NX_DLIST_INIT(element.field_list, nx_logdata_field_list_t, link);
      
     
-#line 1236 "patterndb_parser.c"
+#line 1251 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -1253,10 +1268,10 @@
         }
         break;
     case 17: /* testcase */
-#line 29 "patterndb_parser.xcc"
+#line 44 "patterndb_parser.xcc"
 
     
-#line 1260 "patterndb_parser.c"
+#line 1275 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -1277,13 +1292,13 @@
         }
         break;
     case 18: /* capturedvalue */
-#line 73 "patterndb_parser.xcc"
+#line 88 "patterndb_parser.xcc"
 
      
         element.field = malloc(sizeof(nx_pattern_field_t));
      
     
-#line 1287 "patterndb_parser.c"
+#line 1302 "patterndb_parser.c"
         attr = xcc_augment_attributes(attr_in, nattr_extra, attr_extra);
         for (i = 0; attr[i]; i += 2) {
             askip = 0;
@@ -1336,65 +1351,65 @@
     switch (element_id) {
     case 7: /* type */
         {
-#line 215 "patterndb_parser.xcc"
+#line 230 "patterndb_parser.xcc"
 
             element.string = cdata;
         
-#line 1344 "patterndb_parser.c"
+#line 1359 "patterndb_parser.c"
         }
         break;
     case 8: /* fieldname */
         {
-#line 221 "patterndb_parser.xcc"
+#line 236 "patterndb_parser.xcc"
 
             element.string = cdata;
         
-#line 1353 "patterndb_parser.c"
+#line 1368 "patterndb_parser.c"
         }
         break;
     case 9: /* name */
         {
-#line 227 "patterndb_parser.xcc"
+#line 242 "patterndb_parser.xcc"
 
             element.string = cdata;
         
-#line 1362 "patterndb_parser.c"
+#line 1377 "patterndb_parser.c"
         }
         break;
     case 10: /* description */
         {
-#line 233 "patterndb_parser.xcc"
+#line 248 "patterndb_parser.xcc"
 
             element.string = cdata;
         
-#line 1371 "patterndb_parser.c"
+#line 1386 "patterndb_parser.c"
         }
         break;
     case 11: /* value */
         {
-#line 239 "patterndb_parser.xcc"
+#line 254 "patterndb_parser.xcc"
 
             element.string = cdata;
         
-#line 1380 "patterndb_parser.c"
+#line 1395 "patterndb_parser.c"
         }
         break;
     case 12: /* id */
         {
-#line 245 "patterndb_parser.xcc"
+#line 260 "patterndb_parser.xcc"
 
             element.string = cdata;
         
-#line 1389 "patterndb_parser.c"
+#line 1404 "patterndb_parser.c"
         }
         break;
     case 13: /* exec */
         {
-#line 251 "patterndb_parser.xcc"
+#line 266 "patterndb_parser.xcc"
 
             element.string = cdata;
         
-#line 1398 "patterndb_parser.c"
+#line 1413 "patterndb_parser.c"
         }
         break;
     }
@@ -1434,320 +1449,320 @@
         break;
     case 32:
         {
-#line 87 "patterndb_parser.xcc"
+#line 102 "patterndb_parser.xcc"
 
 	
-#line 1441 "patterndb_parser.c"
+#line 1456 "patterndb_parser.c"
         }
         break;
     case 33:
         {
-#line 89 "patterndb_parser.xcc"
+#line 104 "patterndb_parser.xcc"
 
 	
-#line 1449 "patterndb_parser.c"
+#line 1464 "patterndb_parser.c"
         }
         break;
     case 20:
         {
-#line 91 "patterndb_parser.xcc"
+#line 106 "patterndb_parser.xcc"
 
            
                nx_patterndb_add_group(pelement.patterndb, element.patterngroup);
            
 	
-#line 1460 "patterndb_parser.c"
+#line 1475 "patterndb_parser.c"
         }
         break;
     case 48:
         {
-#line 99 "patterndb_parser.xcc"
+#line 114 "patterndb_parser.xcc"
 
            
                pelement.patterngroup->id = atoi(element.string);
                log_debug("patterngroup id: %ld", pelement.patterngroup->id);
            
 	
-#line 1472 "patterndb_parser.c"
+#line 1487 "patterndb_parser.c"
         }
         break;
     case 45:
         {
-#line 105 "patterndb_parser.xcc"
+#line 120 "patterndb_parser.xcc"
 
            
                pelement.patterngroup->name = apr_pstrdup(XCC_GET_PATTERNDB_POOL(pdata), element.string);
                log_debug("patterngroup name: %s", pelement.patterngroup->name);
            
 	
-#line 1484 "patterndb_parser.c"
+#line 1499 "patterndb_parser.c"
         }
         break;
     case 46:
         {
-#line 111 "patterndb_parser.xcc"
+#line 126 "patterndb_parser.xcc"
 
-#line 1491 "patterndb_parser.c"
+#line 1506 "patterndb_parser.c"
         }
         break;
     case 39:
         {
-#line 112 "patterndb_parser.xcc"
+#line 127 "patterndb_parser.xcc"
 
            
                nx_patterngroup_add_pattern(pelement.patterngroup, element.pattern);
            
 	
-#line 1502 "patterndb_parser.c"
+#line 1517 "patterndb_parser.c"
         }
         break;
     case 40:
         {
-#line 117 "patterndb_parser.xcc"
+#line 132 "patterndb_parser.xcc"
 
            
                nx_patterngroup_add_matchfield(XCC_GET_PATTERNDB_POOL(pdata), pelement.patterngroup, element.matchfield);
            
 	
-#line 1513 "patterndb_parser.c"
+#line 1528 "patterndb_parser.c"
         }
         break;
     case 66:
         {
-#line 125 "patterndb_parser.xcc"
+#line 140 "patterndb_parser.xcc"
 
            
                pelement.pattern->id = atoi(element.string);
                log_debug("pattern id: %ld", pelement.pattern->id);
            
 	
-#line 1525 "patterndb_parser.c"
+#line 1540 "patterndb_parser.c"
         }
         break;
     case 63:
         {
-#line 131 "patterndb_parser.xcc"
+#line 146 "patterndb_parser.xcc"
 
            
                pelement.pattern->name = apr_pstrdup(XCC_GET_PATTERNDB_POOL(pdata), element.string);
            
 	
-#line 1536 "patterndb_parser.c"
+#line 1551 "patterndb_parser.c"
         }
         break;
     case 64:
         {
-#line 136 "patterndb_parser.xcc"
+#line 151 "patterndb_parser.xcc"
 
-#line 1543 "patterndb_parser.c"
+#line 1558 "patterndb_parser.c"
         }
         break;
     case 58:
         {
-#line 137 "patterndb_parser.xcc"
+#line 152 "patterndb_parser.xcc"
 
           
                nx_pattern_add_matchfield(XCC_GET_PATTERNDB_POOL(pdata), pelement.pattern, element.matchfield);
            
 	
-#line 1554 "patterndb_parser.c"
+#line 1569 "patterndb_parser.c"
         }
         break;
     case 70:
         {
-#line 142 "patterndb_parser.xcc"
+#line 157 "patterndb_parser.xcc"
 
           
                pelement.pattern->setfields = element.field_list;
            
 	
-#line 1565 "patterndb_parser.c"
+#line 1580 "patterndb_parser.c"
         }
         break;
     case 67:
         {
-#line 147 "patterndb_parser.xcc"
+#line 162 "patterndb_parser.xcc"
 
           
                nx_patterndb_parse_exec_block(NULL, XCC_GET_PATTERNDB(pdata), pelement.pattern, element.string, XCC_GET_FILENAME(pdata),
                                              xcc_get_linenum(pdata), 1); //TODO linepos
             
 	
-#line 1577 "patterndb_parser.c"
+#line 1592 "patterndb_parser.c"
         }
         break;
     case 71:
         {
-#line 153 "patterndb_parser.xcc"
+#line 168 "patterndb_parser.xcc"
 
           
              //FIXME
            
 	
-#line 1588 "patterndb_parser.c"
+#line 1603 "patterndb_parser.c"
         }
         break;
     case 81:
         {
-#line 161 "patterndb_parser.xcc"
+#line 176 "patterndb_parser.xcc"
 
            
                pelement.matchfield->name = apr_pstrdup(XCC_GET_PATTERNDB_POOL(pdata), element.string);
            
 	
-#line 1599 "patterndb_parser.c"
+#line 1614 "patterndb_parser.c"
         }
         break;
     case 79:
         {
-#line 166 "patterndb_parser.xcc"
+#line 181 "patterndb_parser.xcc"
 
           
                pelement.matchfield->type = nx_pattern_match_type_from_string(element.string);
            
 	
-#line 1610 "patterndb_parser.c"
+#line 1625 "patterndb_parser.c"
         }
         break;
     case 83:
         {
-#line 171 "patterndb_parser.xcc"
+#line 186 "patterndb_parser.xcc"
 
            
                pelement.matchfield->value = apr_pstrdup(XCC_GET_PATTERNDB_POOL(pdata), element.string);
            
 	
-#line 1621 "patterndb_parser.c"
+#line 1636 "patterndb_parser.c"
         }
         break;
     case 77:
         {
-#line 176 "patterndb_parser.xcc"
+#line 191 "patterndb_parser.xcc"
 
           
                nx_pattern_matchfield_add_capturedfield(pelement.matchfield, element.capturedfield);
            
 	
-#line 1632 "patterndb_parser.c"
+#line 1647 "patterndb_parser.c"
         }
         break;
     case 99:
         {
-#line 184 "patterndb_parser.xcc"
+#line 199 "patterndb_parser.xcc"
 
            
                pelement.capturedfield->name = apr_pstrdup(XCC_GET_PATTERNDB_POOL(pdata), element.string);
            
 	
-#line 1643 "patterndb_parser.c"
+#line 1658 "patterndb_parser.c"
         }
         break;
     case 97:
         {
-#line 189 "patterndb_parser.xcc"
+#line 204 "patterndb_parser.xcc"
 
           
                pelement.capturedfield->type = nx_value_type_from_string(element.string);
            
 	
-#line 1654 "patterndb_parser.c"
+#line 1669 "patterndb_parser.c"
         }
         break;
     case 117:
         {
-#line 197 "patterndb_parser.xcc"
+#line 212 "patterndb_parser.xcc"
 
           
                pelement.field->name = strdup(element.string);
            
 	
-#line 1665 "patterndb_parser.c"
+#line 1680 "patterndb_parser.c"
         }
         break;
     case 119:
         {
-#line 202 "patterndb_parser.xcc"
+#line 217 "patterndb_parser.xcc"
 
           
                pelement.field->value = strdup(element.string);
            
 	
-#line 1676 "patterndb_parser.c"
+#line 1691 "patterndb_parser.c"
         }
         break;
     case 115:
         {
-#line 207 "patterndb_parser.xcc"
+#line 222 "patterndb_parser.xcc"
 
           
                pelement.field->type = nx_value_type_from_string(element.string);
            
 	
-#line 1687 "patterndb_parser.c"
+#line 1702 "patterndb_parser.c"
         }
         break;
     case 294:
         {
-#line 263 "patterndb_parser.xcc"
+#line 278 "patterndb_parser.xcc"
 
           
                nx_pattern_field_list_insert_field(XCC_GET_PATTERNDB_POOL(pdata), pelement.field_list, element.field->name, element.field->value, element.field->type);
                nx_pattern_field_free(element.field);
            
 	
-#line 1699 "patterndb_parser.c"
+#line 1714 "patterndb_parser.c"
         }
         break;
     case 312:
         {
-#line 272 "patterndb_parser.xcc"
+#line 287 "patterndb_parser.xcc"
 
 	
-#line 1707 "patterndb_parser.c"
+#line 1722 "patterndb_parser.c"
         }
         break;
     case 324:
         {
-#line 274 "patterndb_parser.xcc"
+#line 289 "patterndb_parser.xcc"
 
           
                nx_pattern_field_free(element.field);
            
 	
-#line 1718 "patterndb_parser.c"
+#line 1733 "patterndb_parser.c"
         }
         break;
     case 333:
         {
-#line 282 "patterndb_parser.xcc"
+#line 297 "patterndb_parser.xcc"
 
           
                pelement.field->name = strdup(element.string);
            
 	
-#line 1729 "patterndb_parser.c"
+#line 1744 "patterndb_parser.c"
         }
         break;
     case 335:
         {
-#line 287 "patterndb_parser.xcc"
+#line 302 "patterndb_parser.xcc"
 
           
                pelement.field->value = strdup(element.string);
            
 	
-#line 1740 "patterndb_parser.c"
+#line 1755 "patterndb_parser.c"
         }
         break;
     case 331:
         {
-#line 292 "patterndb_parser.xcc"
+#line 307 "patterndb_parser.xcc"
 
           
                pelement.field->type = nx_value_type_from_string(element.string);
            
 	
-#line 1751 "patterndb_parser.c"
+#line 1766 "patterndb_parser.c"
         }
         break;
     default:
@@ -1768,13 +1783,109 @@
 {
     return xcc_run(fp, root, udata, xcc_start_handler, xcc_end_handler, exception_handler);
 }
-#line 299 "patterndb_parser.xcc"
+#line 314 "patterndb_parser.xcc"
+
+
+void nx_xcc_err_filepos(nx_patterndb_parser_data_t *parser_data)
+{
+    if (parser_data->level)
+        fprintf(stderr, "\tin entity '%s' at line %d\n",
+            parser_data->filename, (int) XML_GetCurrentLineNumber(parser_data->xp));
+    else
+        fprintf(stderr, "\tat line %d\n",
+            (int) XML_GetCurrentLineNumber(parser_data->xp));
+}
+
+int nx_exception_handler(int ierrno, const char *entity, const char *context, void *udata)
+{
+    int retval;
+
+    retval = xcc_exception_handler(ierrno, entity, context, udata);
+    nx_xcc_err_filepos((nx_patterndb_parser_data_t *)udata);
+    return retval;
+}
+
+inline int nx_external_entity_parse(XML_Parser xp, FILE *f, XCCParserData *pdata)
+{
+    char buff[XCC_BUFFSIZE];
+
+    if (!xp) {
+        xcc_error("Couldn't allocate memory for subparser");
+        return 0;
+    }
 
+    while (!pdata->error) {
+        int done, len;
 
-//FIXME implement own error handler to throw exception with line number
-//      and pass it to xcc_parse below
-//int exception_handler(int ierrno, const char *entity, const char *context, void *udata)
+        len = fread(buff, 1, sizeof(buff), f);
+        if (ferror(f)) {
+            xcc_error("Read error");
+            pdata->error = 1;
+            break;
+        }
+        done = feof(f);
 
+        if (!XML_Parse(xp, buff, len, done)) {
+            xcc_error("parse error in entity '%s' at line %d:\n\t%s",
+                ((nx_patterndb_parser_data_t *)pdata->udata)->filename,
+                XML_GetCurrentLineNumber(xp),
+                XML_ErrorString(XML_GetErrorCode(xp)));
+            pdata->error = 1;
+            break;
+        }
+
+        if (done) {
+            break;
+        }
+    }
+
+    XML_ParserFree(xp);
+
+    return !pdata->error;
+}
+
+int nx_external_entity_handler(XML_Parser xp, const XML_Char *context,
+    const XML_Char *base, const XML_Char *filename /* systemId */, const XML_Char *publicId)
+{
+    FILE *f;
+    nx_patterndb_parser_data_t *parser_data; // just to get rid of repeating typecasts
+    char *parent_filename;
+    char err_buf[256];
+    int retval;
+
+    parser_data = (nx_patterndb_parser_data_t *)((XCCParserData *)XML_GetUserData(xp))->udata;
+
+    ASSERT(base == NULL);
+    if ( filename == NULL || publicId != NULL )
+    {
+        xcc_error("external entity is not of SYSTEM type");
+        return 0;
+    }
+
+    f = fopen(filename, "r");
+    if ( f == NULL )
+    {
+        xcc_error("couldn't open enternal entity file '%s': %s", filename,
+            apr_strerror(apr_get_os_error(), err_buf, sizeof(err_buf)));
+        return 0;
+    }
+
+    parser_data->level += 1;
+    parent_filename = parser_data->filename;
+    parser_data->filename = filename;
+    parser_data->xp = XML_ExternalEntityParserCreate(xp, context, NULL);
+
+    retval = nx_external_entity_parse(parser_data->xp, f,
+        (XCCParserData *)XML_GetUserData(xp));
+
+    parser_data->level -= 1;
+    parser_data->filename = parent_filename;
+    parser_data->xp = xp;
+
+    fclose(f);
+
+    return retval;
+}
 
 nx_patterndb_t *nx_patterndb_parse(apr_pool_t *pool, const char *filename)
 {
@@ -1797,7 +1908,7 @@
 
     try
     {
-	if ( xcc_parse(f, (void **) &(parser_data.patterndb), (void *) &parser_data, NULL) != XCC_RETURN_SUCCESS )
+	if ( xcc_parse(f, (void **) &(parser_data.patterndb), (void *) &parser_data, nx_exception_handler) != XCC_RETURN_SUCCESS )
 	{
 	    throw_msg("failed to parse pattern database '%s'", filename);
 	}
@@ -1814,4 +1925,4 @@
 }
 
     
-#line 1818 "patterndb_parser.c"
+#line 1929 "patterndb_parser.c"
diff -Naur nxlog-ce-2.8.1248.old/src/modules/processor/pattern/patterndb_parser.xcc nxlog-ce-2.8.1248/src/modules/processor/pattern/patterndb_parser.xcc
--- nxlog-ce-2.8.1248.old/src/modules/processor/pattern/patterndb_parser.xcc	2014-07-19 15:52:07.000000000 +0200
+++ nxlog-ce-2.8.1248/src/modules/processor/pattern/patterndb_parser.xcc	2016-01-09 23:15:45.880250356 +0100
@@ -6,10 +6,14 @@
  * See the file LICENSE in the source root for licensing terms.
  * Website: http://nxlog.org
  * Author: Botond Botyanszki <botond.botyans...@nxlog.org>
+ * Modified: Milan Krcmar <milan.krc...@gmail.com> Sat, 09 Jan 2016
+ * - add line numbers to exception handler's output
+ * - allow the parsed XML to reference external system entities
  */
 
 #include "patterndb.h"
 #include "../../../common/exception.h"
+#include <expat.h>
 
 #define NX_LOGMODULE NX_LOGMODULE_MODULE
 
@@ -18,12 +22,23 @@
     apr_pool_t *pool; ///< parent pool
     nx_patterndb_t *patterndb;
     const char *filename;
+    XML_Parser xp;
+    int level;
 } nx_patterndb_parser_data_t;
 
 #define XCC_GET_PATTERNDB(X) (((nx_patterndb_parser_data_t *) ((XCCParserData *)(X))->udata)->patterndb)
 #define XCC_GET_PATTERNDB_POOL(X) ((((nx_patterndb_parser_data_t *) ((XCCParserData *)(X))->udata)->patterndb)->pool)
 #define XCC_GET_FILENAME(X) (((nx_patterndb_parser_data_t *) ((XCCParserData *)(X))->udata)->filename)
 
+int nx_external_entity_handler(XML_Parser xp, const XML_Char *context,
+    const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId);
+
+#define XML_SetUserData(p, userData) { \
+    XML_SetUserData(p, userData); \
+    XML_SetExternalEntityRefHandler(p, nx_external_entity_handler); \
+    ((nx_patterndb_parser_data_t *)((XCCParserData *)userData)->udata)->xp = p; \
+}
+
     ]]></preamble>
 
     <element-type name="ignored" ctype="void *">
@@ -298,10 +313,106 @@
 
     <postamble><![CDATA[
 
-//FIXME implement own error handler to throw exception with line number
-//      and pass it to xcc_parse below
-//int exception_handler(int ierrno, const char *entity, const char *context, void *udata)
+void nx_xcc_err_filepos(nx_patterndb_parser_data_t *parser_data)
+{
+    if (parser_data->level)
+        fprintf(stderr, "\tin entity '%s' at line %d\n",
+            parser_data->filename, (int) XML_GetCurrentLineNumber(parser_data->xp));
+    else
+        fprintf(stderr, "\tat line %d\n",
+            (int) XML_GetCurrentLineNumber(parser_data->xp));
+}
+
+int nx_exception_handler(int ierrno, const char *entity, const char *context, void *udata)
+{
+    int retval;
+
+    retval = xcc_exception_handler(ierrno, entity, context, udata);
+    nx_xcc_err_filepos((nx_patterndb_parser_data_t *)udata);
+    return retval;
+}
+
+inline int nx_external_entity_parse(XML_Parser xp, FILE *f, XCCParserData *pdata)
+{
+    char buff[XCC_BUFFSIZE];
+
+    if (!xp) {
+        xcc_error("Couldn't allocate memory for subparser");
+        return 0;
+    }
+
+    while (!pdata->error) {
+        int done, len;
+
+        len = fread(buff, 1, sizeof(buff), f);
+        if (ferror(f)) {
+            xcc_error("Read error");
+            pdata->error = 1;
+            break;
+        }
+        done = feof(f);
+
+        if (!XML_Parse(xp, buff, len, done)) {
+            xcc_error("parse error in entity '%s' at line %d:\n\t%s",
+                ((nx_patterndb_parser_data_t *)pdata->udata)->filename,
+                XML_GetCurrentLineNumber(xp),
+                XML_ErrorString(XML_GetErrorCode(xp)));
+            pdata->error = 1;
+            break;
+        }
+
+        if (done) {
+            break;
+        }
+    }
+
+    XML_ParserFree(xp);
+
+    return !pdata->error;
+}
+
+int nx_external_entity_handler(XML_Parser xp, const XML_Char *context,
+    const XML_Char *base, const XML_Char *filename /* systemId */, const XML_Char *publicId)
+{
+    FILE *f;
+    nx_patterndb_parser_data_t *parser_data; // just to get rid of repeating typecasts
+    char *parent_filename;
+    char err_buf[256];
+    int retval;
+
+    parser_data = (nx_patterndb_parser_data_t *)((XCCParserData *)XML_GetUserData(xp))->udata;
+
+    ASSERT(base == NULL);
+    if ( filename == NULL || publicId != NULL )
+    {
+        xcc_error("external entity is not of SYSTEM type");
+        return 0;
+    }
+
+    f = fopen(filename, "r");
+    if ( f == NULL )
+    {
+        xcc_error("couldn't open enternal entity file '%s': %s", filename,
+            apr_strerror(apr_get_os_error(), err_buf, sizeof(err_buf)));
+        return 0;
+    }
+
+    parser_data->level += 1;
+    parent_filename = parser_data->filename;
+    parser_data->filename = filename;
+    parser_data->xp = XML_ExternalEntityParserCreate(xp, context, NULL);
+
+    retval = nx_external_entity_parse(parser_data->xp, f,
+        (XCCParserData *)XML_GetUserData(xp));
+
+    parser_data->level -= 1;
+    parser_data->filename = parent_filename;
+    parser_data->xp = xp;
+
+    fclose(f);
 
+    return retval;
+}
 
 nx_patterndb_t *nx_patterndb_parse(apr_pool_t *pool, const char *filename)
 {
@@ -324,7 +435,7 @@
 
     try
     {
-	if ( xcc_parse(f, (void **) &(parser_data.patterndb), (void *) &parser_data, NULL) != XCC_RETURN_SUCCESS )
+	if ( xcc_parse(f, (void **) &(parser_data.patterndb), (void *) &parser_data, nx_exception_handler) != XCC_RETURN_SUCCESS )
 	{
 	    throw_msg("failed to parse pattern database '%s'", filename);
 	}
------------------------------------------------------------------------------
Site24x7 APM Insight: Get Deep Visibility into Application Performance
APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month
Monitor end-to-end web transactions and take corrective actions now
Troubleshoot faster and improve end-user experience. Signup Now!
http://pubads.g.doubleclick.net/gampad/clk?id=267308311&iu=/4140
_______________________________________________
nxlog-ce-users mailing list
nxlog-ce-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nxlog-ce-users

Reply via email to