|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* @file pdag.c
|
|
Packit |
1422b7 |
* @brief Implementation of the parse dag object.
|
|
Packit |
1422b7 |
* @class ln_pdag pdag.h
|
|
Packit |
1422b7 |
*//*
|
|
Packit |
1422b7 |
* Copyright 2015 by Rainer Gerhards and Adiscon GmbH.
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* Released under ASL 2.0.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
#include "config.h"
|
|
Packit |
1422b7 |
#include <stdlib.h>
|
|
Packit |
1422b7 |
#include <stdio.h>
|
|
Packit |
1422b7 |
#include <stdarg.h>
|
|
Packit |
1422b7 |
#include <string.h>
|
|
Packit |
1422b7 |
#include <assert.h>
|
|
Packit |
1422b7 |
#include <ctype.h>
|
|
Packit |
1422b7 |
#include <libestr.h>
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
#include "liblognorm.h"
|
|
Packit |
1422b7 |
#include "v1_liblognorm.h"
|
|
Packit |
1422b7 |
#include "v1_ptree.h"
|
|
Packit |
1422b7 |
#include "lognorm.h"
|
|
Packit |
1422b7 |
#include "samp.h"
|
|
Packit |
1422b7 |
#include "pdag.h"
|
|
Packit |
1422b7 |
#include "annot.h"
|
|
Packit |
1422b7 |
#include "internal.h"
|
|
Packit |
1422b7 |
#include "parser.h"
|
|
Packit |
1422b7 |
#include "helpers.h"
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
void ln_displayPDAGComponentAlternative(struct ln_pdag *dag, int level);
|
|
Packit |
1422b7 |
void ln_displayPDAGComponent(struct ln_pdag *dag, int level);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
#ifdef ADVANCED_STATS
|
|
Packit |
1422b7 |
uint64_t advstats_parsers_called = 0;
|
|
Packit |
1422b7 |
uint64_t advstats_parsers_success = 0;
|
|
Packit |
1422b7 |
int advstats_max_pathlen = 0;
|
|
Packit |
1422b7 |
int advstats_pathlens[ADVSTATS_MAX_ENTITIES];
|
|
Packit |
1422b7 |
int advstats_max_backtracked = 0;
|
|
Packit |
1422b7 |
int advstats_backtracks[ADVSTATS_MAX_ENTITIES];
|
|
Packit |
1422b7 |
int advstats_max_parser_calls = 0;
|
|
Packit |
1422b7 |
int advstats_parser_calls[ADVSTATS_MAX_ENTITIES];
|
|
Packit |
1422b7 |
int advstats_max_lit_parser_calls = 0;
|
|
Packit |
1422b7 |
int advstats_lit_parser_calls[ADVSTATS_MAX_ENTITIES];
|
|
Packit |
1422b7 |
#endif
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* parser lookup table
|
|
Packit |
1422b7 |
* This is a memory- and cache-optimized way of calling parsers.
|
|
Packit |
1422b7 |
* VERY IMPORTANT: the initialization must be done EXACTLY in the
|
|
Packit |
1422b7 |
* order of parser IDs (also see comment in pdag.h).
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* Rough guideline for assigning priorites:
|
|
Packit |
1422b7 |
* 0 is highest, 255 lowest. 255 should be reserved for things that
|
|
Packit |
1422b7 |
* *really* should only be run as last resort --> rest. Also keep in
|
|
Packit |
1422b7 |
* mind that the user-assigned priority is put in the upper 24 bits, so
|
|
Packit |
1422b7 |
* parser-specific priorities only count when the user has assigned
|
|
Packit |
1422b7 |
* no priorities (which is expected to be common) or user-assigned
|
|
Packit |
1422b7 |
* priorities are equal for some parsers.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
#ifdef ADVANCED_STATS
|
|
Packit |
1422b7 |
#define PARSER_ENTRY_NO_DATA(identifier, parser, prio) \
|
|
Packit |
1422b7 |
{ identifier, prio, NULL, ln_v2_parse##parser, NULL, 0, 0 }
|
|
Packit |
1422b7 |
#define PARSER_ENTRY(identifier, parser, prio) \
|
|
Packit |
1422b7 |
{ identifier, prio, ln_construct##parser, ln_v2_parse##parser, ln_destruct##parser, 0, 0 }
|
|
Packit |
1422b7 |
#else
|
|
Packit |
1422b7 |
#define PARSER_ENTRY_NO_DATA(identifier, parser, prio) \
|
|
Packit |
1422b7 |
{ identifier, prio, NULL, ln_v2_parse##parser, NULL }
|
|
Packit |
1422b7 |
#define PARSER_ENTRY(identifier, parser, prio) \
|
|
Packit |
1422b7 |
{ identifier, prio, ln_construct##parser, ln_v2_parse##parser, ln_destruct##parser }
|
|
Packit |
1422b7 |
#endif
|
|
Packit |
1422b7 |
static struct ln_parser_info parser_lookup_table[] = {
|
|
Packit |
1422b7 |
PARSER_ENTRY("literal", Literal, 4),
|
|
Packit |
1422b7 |
PARSER_ENTRY("repeat", Repeat, 4),
|
|
Packit |
1422b7 |
PARSER_ENTRY("date-rfc3164", RFC3164Date, 8),
|
|
Packit |
1422b7 |
PARSER_ENTRY("date-rfc5424", RFC5424Date, 8),
|
|
Packit |
1422b7 |
PARSER_ENTRY("number", Number, 16),
|
|
Packit |
1422b7 |
PARSER_ENTRY("float", Float, 16),
|
|
Packit |
1422b7 |
PARSER_ENTRY("hexnumber", HexNumber, 16),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("kernel-timestamp", KernelTimestamp, 16),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("whitespace", Whitespace, 4),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("ipv4", IPv4, 4),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("ipv6", IPv6, 4),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("word", Word, 32),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("alpha", Alpha, 32),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("rest", Rest, 255),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("op-quoted-string", OpQuotedString, 64),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("quoted-string", QuotedString, 64),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("date-iso", ISODate, 8),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("time-24hr", Time24hr, 8),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("time-12hr", Time12hr, 8),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("duration", Duration, 16),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("cisco-interface-spec", CiscoInterfaceSpec, 4),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("name-value-list", NameValue, 8),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("json", JSON, 4),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("cee-syslog", CEESyslog, 4),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("mac48", MAC48, 16),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("cef", CEF, 4),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("checkpoint-lea", CheckpointLEA, 4),
|
|
Packit |
1422b7 |
PARSER_ENTRY_NO_DATA("v2-iptables", v2IPTables, 4),
|
|
Packit |
1422b7 |
PARSER_ENTRY("string-to", StringTo, 32),
|
|
Packit |
1422b7 |
PARSER_ENTRY("char-to", CharTo, 32),
|
|
Packit |
1422b7 |
PARSER_ENTRY("char-sep", CharSeparated, 32),
|
|
Packit |
1422b7 |
PARSER_ENTRY("string", String, 32)
|
|
Packit |
1422b7 |
};
|
|
Packit |
1422b7 |
#define NPARSERS (sizeof(parser_lookup_table)/sizeof(struct ln_parser_info))
|
|
Packit |
1422b7 |
#define DFLT_USR_PARSER_PRIO 30000 /**< default priority if user has not specified it */
|
|
Packit |
1422b7 |
static inline const char *
|
|
Packit |
1422b7 |
parserName(const prsid_t id)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
const char *name;
|
|
Packit |
1422b7 |
if(id == PRS_CUSTOM_TYPE)
|
|
Packit |
1422b7 |
name = "USER-DEFINED";
|
|
Packit |
1422b7 |
else
|
|
Packit |
1422b7 |
name = parser_lookup_table[id].name;
|
|
Packit |
1422b7 |
return name;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
prsid_t
|
|
Packit |
1422b7 |
ln_parserName2ID(const char *const __restrict__ name)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
unsigned i;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
for( i = 0
|
|
Packit |
1422b7 |
; i < sizeof(parser_lookup_table) / sizeof(struct ln_parser_info)
|
|
Packit |
1422b7 |
; ++i) {
|
|
Packit |
1422b7 |
if(!strcmp(parser_lookup_table[i].name, name)) {
|
|
Packit |
1422b7 |
return i;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
return PRS_INVALID;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* find type pdag in table. If "bAdd" is set, add it if not
|
|
Packit |
1422b7 |
* already present, a new entry will be added.
|
|
Packit |
1422b7 |
* Returns NULL on error, ptr to type pdag entry otherwise
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
struct ln_type_pdag *
|
|
Packit |
1422b7 |
ln_pdagFindType(ln_ctx ctx, const char *const __restrict__ name, const int bAdd)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
struct ln_type_pdag *td = NULL;
|
|
Packit |
1422b7 |
int i;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "ln_pdagFindType, name '%s', bAdd: %d, nTypes %d",
|
|
Packit |
1422b7 |
name, bAdd, ctx->nTypes);
|
|
Packit |
1422b7 |
for(i = 0 ; i < ctx->nTypes ; ++i) {
|
|
Packit |
1422b7 |
if(!strcmp(ctx->type_pdags[i].name, name)) {
|
|
Packit |
1422b7 |
td = ctx->type_pdags + i;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(!bAdd) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "custom type '%s' not found", name);
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* type does not yet exist -- create entry */
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "custom type '%s' does not yet exist, adding...", name);
|
|
Packit |
1422b7 |
struct ln_type_pdag *newarr;
|
|
Packit |
1422b7 |
newarr = realloc(ctx->type_pdags, sizeof(struct ln_type_pdag) * (ctx->nTypes+1));
|
|
Packit |
1422b7 |
if(newarr == NULL) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "ln_pdagFindTypeAG: alloc newarr failed");
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
ctx->type_pdags = newarr;
|
|
Packit |
1422b7 |
td = ctx->type_pdags + ctx->nTypes;
|
|
Packit |
1422b7 |
++ctx->nTypes;
|
|
Packit |
1422b7 |
td->name = strdup(name);
|
|
Packit |
1422b7 |
td->pdag = ln_newPDAG(ctx);
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return td;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* we clear some multiple times, but as long as we have no loops
|
|
Packit |
1422b7 |
* (dag!) we have no real issue.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static void
|
|
Packit |
1422b7 |
ln_pdagComponentClearVisited(struct ln_pdag *const dag)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
dag->flags.visited = 0;
|
|
Packit |
1422b7 |
for(int i = 0 ; i < dag->nparsers ; ++i) {
|
|
Packit |
1422b7 |
ln_parser_t *prs = dag->parsers+i;
|
|
Packit |
1422b7 |
ln_pdagComponentClearVisited(prs->node);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
static void
|
|
Packit |
1422b7 |
ln_pdagClearVisited(ln_ctx ctx)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
for(int i = 0 ; i < ctx->nTypes ; ++i)
|
|
Packit |
1422b7 |
ln_pdagComponentClearVisited(ctx->type_pdags[i].pdag);
|
|
Packit |
1422b7 |
ln_pdagComponentClearVisited(ctx->pdag);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Process a parser defintion. Note that a single defintion can potentially
|
|
Packit |
1422b7 |
* contain many parser instances.
|
|
Packit |
1422b7 |
* @return parser node ptr or NULL (on error)
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
ln_parser_t*
|
|
Packit |
1422b7 |
ln_newParser(ln_ctx ctx,
|
|
Packit |
1422b7 |
json_object *prscnf)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
ln_parser_t *node = NULL;
|
|
Packit |
1422b7 |
json_object *json;
|
|
Packit |
1422b7 |
const char *val;
|
|
Packit |
1422b7 |
prsid_t prsid;
|
|
Packit |
1422b7 |
struct ln_type_pdag *custType = NULL;
|
|
Packit |
1422b7 |
const char *name = NULL;
|
|
Packit |
1422b7 |
const char *textconf = json_object_to_json_string(prscnf);
|
|
Packit |
1422b7 |
int assignedPrio = DFLT_USR_PARSER_PRIO;
|
|
Packit |
1422b7 |
int parserPrio;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
json_object_object_get_ex(prscnf, "type", &json);
|
|
Packit |
1422b7 |
if(json == NULL) {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "parser type missing in config: %s",
|
|
Packit |
1422b7 |
json_object_to_json_string(prscnf));
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
val = json_object_get_string(json);
|
|
Packit |
1422b7 |
if(*val == '@') {
|
|
Packit |
1422b7 |
prsid = PRS_CUSTOM_TYPE;
|
|
Packit |
1422b7 |
custType = ln_pdagFindType(ctx, val, 0);
|
|
Packit |
1422b7 |
parserPrio = 16; /* hopefully relatively specific... */
|
|
Packit |
1422b7 |
if(custType == NULL) {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "unknown user-defined type '%s'", val);
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
prsid = ln_parserName2ID(val);
|
|
Packit |
1422b7 |
if(prsid == PRS_INVALID) {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "invalid field type '%s'", val);
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
parserPrio = parser_lookup_table[prsid].prio;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
json_object_object_get_ex(prscnf, "name", &json);
|
|
Packit |
1422b7 |
if(json == NULL || !strcmp(json_object_get_string(json), "-")) {
|
|
Packit |
1422b7 |
name = NULL;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
name = strdup(json_object_get_string(json));
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
json_object_object_get_ex(prscnf, "priority", &json);
|
|
Packit |
1422b7 |
if(json != NULL) {
|
|
Packit |
1422b7 |
assignedPrio = json_object_get_int(json);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "assigned priority is %d", assignedPrio);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* we need to remove already processed items from the config, so
|
|
Packit |
1422b7 |
* that we can pass the remaining parameters to the parser.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
json_object_object_del(prscnf, "type");
|
|
Packit |
1422b7 |
json_object_object_del(prscnf, "priority");
|
|
Packit |
1422b7 |
if(name != NULL)
|
|
Packit |
1422b7 |
json_object_object_del(prscnf, "name");
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* got all data items */
|
|
Packit |
1422b7 |
if((node = calloc(1, sizeof(ln_parser_t))) == NULL) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "lnNewParser: alloc node failed");
|
|
Packit |
1422b7 |
free((void*)name);
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
node->node = NULL;
|
|
Packit |
1422b7 |
node->prio = ((assignedPrio << 8) & 0xffffff00) | (parserPrio & 0xff);
|
|
Packit |
1422b7 |
node->name = name;
|
|
Packit |
1422b7 |
node->prsid = prsid;
|
|
Packit |
1422b7 |
node->conf = strdup(textconf);
|
|
Packit |
1422b7 |
if(prsid == PRS_CUSTOM_TYPE) {
|
|
Packit |
1422b7 |
node->custType = custType;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
if(parser_lookup_table[prsid].construct != NULL) {
|
|
Packit |
1422b7 |
parser_lookup_table[prsid].construct(ctx, prscnf, &node->parser_data);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return node;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct ln_pdag*
|
|
Packit |
1422b7 |
ln_newPDAG(ln_ctx ctx)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
struct ln_pdag *dag;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if((dag = calloc(1, sizeof(struct ln_pdag))) == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
dag->refcnt = 1;
|
|
Packit |
1422b7 |
dag->ctx = ctx;
|
|
Packit |
1422b7 |
ctx->nNodes++;
|
|
Packit |
1422b7 |
done: return dag;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* note: we must NOT free the parser itself, because
|
|
Packit |
1422b7 |
* it is stored inside a parser table (so no single
|
|
Packit |
1422b7 |
* alloc for the parser!).
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static void
|
|
Packit |
1422b7 |
pdagDeletePrs(ln_ctx ctx, ln_parser_t *const __restrict__ prs)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
// TODO: be careful here: once we move to real DAG from tree, we
|
|
Packit |
1422b7 |
// cannot simply delete the next node! (refcount? something else?)
|
|
Packit |
1422b7 |
if(prs->node != NULL)
|
|
Packit |
1422b7 |
ln_pdagDelete(prs->node);
|
|
Packit |
1422b7 |
free((void*)prs->name);
|
|
Packit |
1422b7 |
free((void*)prs->conf);
|
|
Packit |
1422b7 |
if(prs->parser_data != NULL)
|
|
Packit |
1422b7 |
parser_lookup_table[prs->prsid].destruct(ctx, prs->parser_data);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
void
|
|
Packit |
1422b7 |
ln_pdagDelete(struct ln_pdag *const __restrict__ pdag)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
if(pdag == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
LN_DBGPRINTF(pdag->ctx, "delete %p[%d]: %s", pdag, pdag->refcnt, pdag->rb_id);
|
|
Packit |
1422b7 |
--pdag->refcnt;
|
|
Packit |
1422b7 |
if(pdag->refcnt > 0)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(pdag->tags != NULL)
|
|
Packit |
1422b7 |
json_object_put(pdag->tags);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
for(int i = 0 ; i < pdag->nparsers ; ++i) {
|
|
Packit |
1422b7 |
pdagDeletePrs(pdag->ctx, pdag->parsers+i);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
free(pdag->parsers);
|
|
Packit |
1422b7 |
free((void*)pdag->rb_id);
|
|
Packit |
1422b7 |
free((void*)pdag->rb_file);
|
|
Packit |
1422b7 |
free(pdag);
|
|
Packit |
1422b7 |
done: return;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* pdag optimizer step: literal path compaction
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* We compress as much as possible and evalute the path down to
|
|
Packit |
1422b7 |
* the first non-compressable element. Note that we must NOT
|
|
Packit |
1422b7 |
* compact those literals that are either terminal nodes OR
|
|
Packit |
1422b7 |
* contain names so that the literal is to be parsed out.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static inline int
|
|
Packit |
1422b7 |
optLitPathCompact(ln_ctx ctx, ln_parser_t *prs)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
while(prs != NULL) {
|
|
Packit |
1422b7 |
/* note the NOT prefix in the condition below! */
|
|
Packit |
1422b7 |
if(!( prs->prsid == PRS_LITERAL
|
|
Packit |
1422b7 |
&& prs->name == NULL
|
|
Packit |
1422b7 |
&& prs->node->flags.isTerminal == 0
|
|
Packit |
1422b7 |
&& prs->node->refcnt == 1
|
|
Packit |
1422b7 |
&& prs->node->nparsers == 1
|
|
Packit |
1422b7 |
/* we need to do some checks on the child as well */
|
|
Packit |
1422b7 |
&& prs->node->parsers[0].prsid == PRS_LITERAL
|
|
Packit |
1422b7 |
&& prs->node->parsers[0].name == NULL
|
|
Packit |
1422b7 |
&& prs->node->parsers[0].node->refcnt == 1)
|
|
Packit |
1422b7 |
)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* ok, we have two compactable literals in a row, let's compact the nodes */
|
|
Packit |
1422b7 |
ln_parser_t *child_prs = prs->node->parsers;
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "opt path compact: add %p to %p", child_prs, prs);
|
|
Packit |
1422b7 |
CHKR(ln_combineData_Literal(prs->parser_data, child_prs->parser_data));
|
|
Packit |
1422b7 |
ln_pdag *const node_del = prs->node;
|
|
Packit |
1422b7 |
prs->node = child_prs->node;
|
|
Packit |
1422b7 |
child_prs->node = NULL; /* remove, else this would be destructed! */
|
|
Packit |
1422b7 |
ln_pdagDelete(node_del);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
qsort_parserCmp(const void *v1, const void *v2)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
const ln_parser_t *const p1 = (const ln_parser_t *const) v1;
|
|
Packit |
1422b7 |
const ln_parser_t *const p2 = (const ln_parser_t *const) v2;
|
|
Packit |
1422b7 |
return p1->prio - p2->prio;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
ln_pdagComponentOptimize(ln_ctx ctx, struct ln_pdag *const dag)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
for(int i = 0 ; i < dag->nparsers ; ++i) { /* TODO: remove when confident enough */
|
|
Packit |
1422b7 |
ln_parser_t *prs = dag->parsers+i;
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "pre sort, parser %d:%s[%d]", i, prs->name, prs->prio);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
/* first sort parsers in priority order */
|
|
Packit |
1422b7 |
if(dag->nparsers > 1) {
|
|
Packit |
1422b7 |
qsort(dag->parsers, dag->nparsers, sizeof(ln_parser_t), qsort_parserCmp);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
for(int i = 0 ; i < dag->nparsers ; ++i) { /* TODO: remove when confident enough */
|
|
Packit |
1422b7 |
ln_parser_t *prs = dag->parsers+i;
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "post sort, parser %d:%s[%d]", i, prs->name, prs->prio);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* now on to rest of processing */
|
|
Packit |
1422b7 |
for(int i = 0 ; i < dag->nparsers ; ++i) {
|
|
Packit |
1422b7 |
ln_parser_t *prs = dag->parsers+i;
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "optimizing %p: field %d type '%s', name '%s': '%s':",
|
|
Packit |
1422b7 |
prs->node, i, parserName(prs->prsid), prs->name,
|
|
Packit |
1422b7 |
(prs->prsid == PRS_LITERAL) ? ln_DataForDisplayLiteral(dag->ctx, prs->parser_data)
|
|
Packit |
1422b7 |
: "UNKNOWN");
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
optLitPathCompact(ctx, prs);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
ln_pdagComponentOptimize(ctx, prs->node);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
static void
|
|
Packit |
1422b7 |
deleteComponentID(struct ln_pdag *const __restrict__ dag)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
free((void*)dag->rb_id);
|
|
Packit |
1422b7 |
dag->rb_id = NULL;
|
|
Packit |
1422b7 |
for(int i = 0 ; i < dag->nparsers ; ++i) {
|
|
Packit |
1422b7 |
ln_parser_t *prs = dag->parsers+i;
|
|
Packit |
1422b7 |
deleteComponentID(prs->node);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
/* fixes rb_ids for this node as well as it predecessors.
|
|
Packit |
1422b7 |
* This is required if the ALTERNATIVE parser type is used,
|
|
Packit |
1422b7 |
* which will create component IDs for each of it's invocations.
|
|
Packit |
1422b7 |
* As such, we do not only fix the string, but know that all
|
|
Packit |
1422b7 |
* children also need fixning. We do this be simply deleting
|
|
Packit |
1422b7 |
* all of their rb_ids, as we know they will be visited again.
|
|
Packit |
1422b7 |
* Note: if we introduce the same situation by new functionality,
|
|
Packit |
1422b7 |
* we may need to review this code here as well. Also note
|
|
Packit |
1422b7 |
* that the component ID will not be 100% correct after our fix,
|
|
Packit |
1422b7 |
* because that ID could acutally be created by two sets of rules.
|
|
Packit |
1422b7 |
* But this is the best we can do.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static void
|
|
Packit |
1422b7 |
fixComponentID(struct ln_pdag *const __restrict__ dag, const char *const new)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
char *updated;
|
|
Packit |
1422b7 |
const char *const curr = dag->rb_id;
|
|
Packit |
1422b7 |
int i;
|
|
Packit |
1422b7 |
int len = (int) strlen(curr);
|
|
Packit |
1422b7 |
for(i = 0 ; i < len ; ++i){
|
|
Packit |
1422b7 |
if(curr[i] != new [i])
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(i >= 1 && curr[i-1] == '%')
|
|
Packit |
1422b7 |
--i;
|
|
Packit |
1422b7 |
if(asprintf(&updated, "%.*s[%s|%s]", i, curr, curr+i, new+i) == -1)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
deleteComponentID(dag);
|
|
Packit |
1422b7 |
dag->rb_id = updated;
|
|
Packit |
1422b7 |
done: return;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Assign human-readable identifiers (names) to each node. These are
|
|
Packit |
1422b7 |
* later used in stats, debug output and whereever else this may make
|
|
Packit |
1422b7 |
* sense.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static void
|
|
Packit |
1422b7 |
ln_pdagComponentSetIDs(ln_ctx ctx, struct ln_pdag *const dag, const char *prefix)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
char *id = NULL;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(prefix == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
if(dag->rb_id == NULL) {
|
|
Packit |
1422b7 |
dag->rb_id = strdup(prefix);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "rb_id already exists - fixing as good as "
|
|
Packit |
1422b7 |
"possible. This happens with ALTERNATIVE parser. "
|
|
Packit |
1422b7 |
"old: '%s', new: '%s'",
|
|
Packit |
1422b7 |
dag->rb_id, prefix);
|
|
Packit |
1422b7 |
fixComponentID(dag, prefix);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "\"fixed\" rb_id: %s", dag->rb_id);
|
|
Packit |
1422b7 |
prefix = dag->rb_id;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
/* now on to rest of processing */
|
|
Packit |
1422b7 |
for(int i = 0 ; i < dag->nparsers ; ++i) {
|
|
Packit |
1422b7 |
ln_parser_t *prs = dag->parsers+i;
|
|
Packit |
1422b7 |
if(prs->prsid == PRS_LITERAL) {
|
|
Packit |
1422b7 |
if(prs->name == NULL) {
|
|
Packit |
1422b7 |
if(asprintf(&id, "%s%s", prefix,
|
|
Packit |
1422b7 |
ln_DataForDisplayLiteral(dag->ctx, prs->parser_data)) == -1)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
if(asprintf(&id, "%s%%%s:%s:%s%%", prefix,
|
|
Packit |
1422b7 |
prs->name,
|
|
Packit |
1422b7 |
parserName(prs->prsid),
|
|
Packit |
1422b7 |
ln_DataForDisplayLiteral(dag->ctx, prs->parser_data)) == -1)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
if(asprintf(&id, "%s%%%s:%s%%", prefix,
|
|
Packit |
1422b7 |
prs->name ? prs->name : "-",
|
|
Packit |
1422b7 |
parserName(prs->prsid)) == -1)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
ln_pdagComponentSetIDs(ctx, prs->node, id);
|
|
Packit |
1422b7 |
free(id);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
done: return;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Optimize the pdag.
|
|
Packit |
1422b7 |
* This includes all components.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
int
|
|
Packit |
1422b7 |
ln_pdagOptimize(ln_ctx ctx)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
for(int i = 0 ; i < ctx->nTypes ; ++i) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "optimizing component %s\n", ctx->type_pdags[i].name);
|
|
Packit |
1422b7 |
ln_pdagComponentOptimize(ctx, ctx->type_pdags[i].pdag);
|
|
Packit |
1422b7 |
ln_pdagComponentSetIDs(ctx, ctx->type_pdags[i].pdag, "");
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "optimizing main pdag component");
|
|
Packit |
1422b7 |
ln_pdagComponentOptimize(ctx, ctx->pdag);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "finished optimizing main pdag component");
|
|
Packit |
1422b7 |
ln_pdagComponentSetIDs(ctx, ctx->pdag, "");
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "---AFTER OPTIMIZATION------------------");
|
|
Packit |
1422b7 |
ln_displayPDAG(ctx);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "=======================================");
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
#define LN_INTERN_PDAG_STATS_NPARSERS 100
|
|
Packit |
1422b7 |
/* data structure for pdag statistics */
|
|
Packit |
1422b7 |
struct pdag_stats {
|
|
Packit |
1422b7 |
int nodes;
|
|
Packit |
1422b7 |
int term_nodes;
|
|
Packit |
1422b7 |
int parsers;
|
|
Packit |
1422b7 |
int max_nparsers;
|
|
Packit |
1422b7 |
int nparsers_cnt[LN_INTERN_PDAG_STATS_NPARSERS];
|
|
Packit |
1422b7 |
int nparsers_100plus;
|
|
Packit |
1422b7 |
int *prs_cnt;
|
|
Packit |
1422b7 |
};
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Recursive step of statistics gatherer.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
ln_pdagStatsRec(ln_ctx ctx, struct ln_pdag *const dag, struct pdag_stats *const stats)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
if(dag->flags.visited)
|
|
Packit |
1422b7 |
return 0;
|
|
Packit |
1422b7 |
dag->flags.visited = 1;
|
|
Packit |
1422b7 |
stats->nodes++;
|
|
Packit |
1422b7 |
if(dag->flags.isTerminal)
|
|
Packit |
1422b7 |
stats->term_nodes++;
|
|
Packit |
1422b7 |
if(dag->nparsers > stats->max_nparsers)
|
|
Packit |
1422b7 |
stats->max_nparsers = dag->nparsers;
|
|
Packit |
1422b7 |
if(dag->nparsers >= LN_INTERN_PDAG_STATS_NPARSERS)
|
|
Packit |
1422b7 |
stats->nparsers_100plus++;
|
|
Packit |
1422b7 |
else
|
|
Packit |
1422b7 |
stats->nparsers_cnt[dag->nparsers]++;
|
|
Packit |
1422b7 |
stats->parsers += dag->nparsers;
|
|
Packit |
1422b7 |
int max_path = 0;
|
|
Packit |
1422b7 |
for(int i = 0 ; i < dag->nparsers ; ++i) {
|
|
Packit |
1422b7 |
ln_parser_t *prs = dag->parsers+i;
|
|
Packit |
1422b7 |
if(prs->prsid != PRS_CUSTOM_TYPE)
|
|
Packit |
1422b7 |
stats->prs_cnt[prs->prsid]++;
|
|
Packit |
1422b7 |
const int path_len = ln_pdagStatsRec(ctx, prs->node, stats);
|
|
Packit |
1422b7 |
if(path_len > max_path)
|
|
Packit |
1422b7 |
max_path = path_len;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
return max_path + 1;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
static void
|
|
Packit |
1422b7 |
ln_pdagStatsExtended(ln_ctx ctx, struct ln_pdag *const dag, FILE *const fp, int level)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
char indent[2048];
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(level > 1023)
|
|
Packit |
1422b7 |
level = 1023;
|
|
Packit |
1422b7 |
memset(indent, ' ', level * 2);
|
|
Packit |
1422b7 |
indent[level * 2] = '\0';
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(dag->stats.called > 0) {
|
|
Packit |
1422b7 |
fprintf(fp, "%u, %u, %s\n",
|
|
Packit |
1422b7 |
dag->stats.called,
|
|
Packit |
1422b7 |
dag->stats.backtracked,
|
|
Packit |
1422b7 |
dag->rb_id);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
for(int i = 0 ; i < dag->nparsers ; ++i) {
|
|
Packit |
1422b7 |
ln_parser_t *const prs = dag->parsers+i;
|
|
Packit |
1422b7 |
if(prs->node->stats.called > 0) {
|
|
Packit |
1422b7 |
ln_pdagStatsExtended(ctx, prs->node, fp, level+1);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Gather pdag statistics for a *specific* pdag.
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* Data is sent to given file ptr.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static void
|
|
Packit |
1422b7 |
ln_pdagStats(ln_ctx ctx, struct ln_pdag *const dag, FILE *const fp, const int extendedStats)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
struct pdag_stats *const stats = calloc(1, sizeof(struct pdag_stats));
|
|
Packit |
1422b7 |
stats->prs_cnt = calloc(NPARSERS, sizeof(int));
|
|
Packit |
1422b7 |
//ln_pdagClearVisited(ctx);
|
|
Packit |
1422b7 |
const int longest_path = ln_pdagStatsRec(ctx, dag, stats);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
fprintf(fp, "nodes.............: %4d\n", stats->nodes);
|
|
Packit |
1422b7 |
fprintf(fp, "terminal nodes....: %4d\n", stats->term_nodes);
|
|
Packit |
1422b7 |
fprintf(fp, "parsers entries...: %4d\n", stats->parsers);
|
|
Packit |
1422b7 |
fprintf(fp, "longest path......: %4d\n", longest_path);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
fprintf(fp, "Parser Type Counts:\n");
|
|
Packit |
1422b7 |
for(prsid_t i = 0 ; i < NPARSERS ; ++i) {
|
|
Packit |
1422b7 |
if(stats->prs_cnt[i] != 0)
|
|
Packit |
1422b7 |
fprintf(fp, "\t%20s: %d\n", parserName(i), stats->prs_cnt[i]);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
int pp = 0;
|
|
Packit |
1422b7 |
fprintf(fp, "Parsers per Node:\n");
|
|
Packit |
1422b7 |
fprintf(fp, "\tmax:\t%4d\n", stats->max_nparsers);
|
|
Packit |
1422b7 |
for(int i = 0 ; i < 100 ; ++i) {
|
|
Packit |
1422b7 |
pp += stats->nparsers_cnt[i];
|
|
Packit |
1422b7 |
if(stats->nparsers_cnt[i] != 0)
|
|
Packit |
1422b7 |
fprintf(fp, "\t%d:\t%4d\n", i, stats->nparsers_cnt[i]);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
free(stats->prs_cnt);
|
|
Packit |
1422b7 |
free(stats);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(extendedStats) {
|
|
Packit |
1422b7 |
fprintf(fp, "Usage Statistics:\n"
|
|
Packit |
1422b7 |
"-----------------\n");
|
|
Packit |
1422b7 |
fprintf(fp, "called, backtracked, rule\n");
|
|
Packit |
1422b7 |
ln_pdagComponentClearVisited(dag);
|
|
Packit |
1422b7 |
ln_pdagStatsExtended(ctx, dag, fp, 0);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Gather and output pdag statistics for the full pdag (ctx)
|
|
Packit |
1422b7 |
* including all disconnected components (type defs).
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* Data is sent to given file ptr.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
void
|
|
Packit |
1422b7 |
ln_fullPdagStats(ln_ctx ctx, FILE *const fp, const int extendedStats)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
if(ctx->ptree != NULL) {
|
|
Packit |
1422b7 |
/* we need to handle the old cruft */
|
|
Packit |
1422b7 |
ln_fullPTreeStats(ctx, fp, extendedStats);
|
|
Packit |
1422b7 |
return;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
fprintf(fp, "User-Defined Types\n"
|
|
Packit |
1422b7 |
"==================\n");
|
|
Packit |
1422b7 |
fprintf(fp, "number types: %d\n", ctx->nTypes);
|
|
Packit |
1422b7 |
for(int i = 0 ; i < ctx->nTypes ; ++i)
|
|
Packit |
1422b7 |
fprintf(fp, "type: %s\n", ctx->type_pdags[i].name);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
for(int i = 0 ; i < ctx->nTypes ; ++i) {
|
|
Packit |
1422b7 |
fprintf(fp, "\n"
|
|
Packit |
1422b7 |
"type PDAG: %s\n"
|
|
Packit |
1422b7 |
"----------\n", ctx->type_pdags[i].name);
|
|
Packit |
1422b7 |
ln_pdagStats(ctx, ctx->type_pdags[i].pdag, fp, extendedStats);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
fprintf(fp, "\n"
|
|
Packit |
1422b7 |
"Main PDAG\n"
|
|
Packit |
1422b7 |
"=========\n");
|
|
Packit |
1422b7 |
ln_pdagStats(ctx, ctx->pdag, fp, extendedStats);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
#ifdef ADVANCED_STATS
|
|
Packit |
1422b7 |
const uint64_t parsers_failed = advstats_parsers_called - advstats_parsers_success;
|
|
Packit |
1422b7 |
fprintf(fp, "\n"
|
|
Packit |
1422b7 |
"Advanced Runtime Stats\n"
|
|
Packit |
1422b7 |
"======================\n");
|
|
Packit |
1422b7 |
fprintf(fp, "These are actual number from analyzing the control flow "
|
|
Packit |
1422b7 |
"at runtime.\n");
|
|
Packit |
1422b7 |
fprintf(fp, "Note that literal matching is also done via parsers. As such, \n"
|
|
Packit |
1422b7 |
"it is expected that fail rates increase with the size of the \n"
|
|
Packit |
1422b7 |
"rule base.\n");
|
|
Packit |
1422b7 |
fprintf(fp, "\n");
|
|
Packit |
1422b7 |
fprintf(fp, "Parser Calls:\n");
|
|
Packit |
1422b7 |
fprintf(fp, "total....: %10" PRIu64 "\n", advstats_parsers_called);
|
|
Packit |
1422b7 |
fprintf(fp, "succesful: %10" PRIu64 "\n", advstats_parsers_success);
|
|
Packit |
1422b7 |
fprintf(fp, "failed...: %10" PRIu64 " [%d%%]\n",
|
|
Packit |
1422b7 |
parsers_failed,
|
|
Packit |
1422b7 |
(int) ((parsers_failed * 100) / advstats_parsers_called) );
|
|
Packit |
1422b7 |
fprintf(fp, "\nIndividual Parser Calls "
|
|
Packit |
1422b7 |
"(never called parsers are not shown):\n");
|
|
Packit |
1422b7 |
for( size_t i = 0
|
|
Packit |
1422b7 |
; i < sizeof(parser_lookup_table) / sizeof(struct ln_parser_info)
|
|
Packit |
1422b7 |
; ++i) {
|
|
Packit |
1422b7 |
if(parser_lookup_table[i].called > 0) {
|
|
Packit |
1422b7 |
const uint64_t failed = parser_lookup_table[i].called
|
|
Packit |
1422b7 |
- parser_lookup_table[i].success;
|
|
Packit |
1422b7 |
fprintf(fp, "%20s: %10" PRIu64 " [%5.2f%%] "
|
|
Packit |
1422b7 |
"success: %10" PRIu64 " [%5.1f%%] "
|
|
Packit |
1422b7 |
"fail: %10" PRIu64 " [%5.1f%%]"
|
|
Packit |
1422b7 |
"\n",
|
|
Packit |
1422b7 |
parser_lookup_table[i].name,
|
|
Packit |
1422b7 |
parser_lookup_table[i].called,
|
|
Packit |
1422b7 |
(float)(parser_lookup_table[i].called * 100)
|
|
Packit |
1422b7 |
/ advstats_parsers_called,
|
|
Packit |
1422b7 |
parser_lookup_table[i].success,
|
|
Packit |
1422b7 |
(float)(parser_lookup_table[i].success * 100)
|
|
Packit |
1422b7 |
/ parser_lookup_table[i].called,
|
|
Packit |
1422b7 |
failed,
|
|
Packit |
1422b7 |
(float)(failed * 100)
|
|
Packit |
1422b7 |
/ parser_lookup_table[i].called
|
|
Packit |
1422b7 |
);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
uint64_t total_len;
|
|
Packit |
1422b7 |
uint64_t total_cnt;
|
|
Packit |
1422b7 |
fprintf(fp, "\n");
|
|
Packit |
1422b7 |
fprintf(fp, "\n"
|
|
Packit |
1422b7 |
"Path Length Statistics\n"
|
|
Packit |
1422b7 |
"----------------------\n"
|
|
Packit |
1422b7 |
"The regular path length is the number of nodes being visited,\n"
|
|
Packit |
1422b7 |
"where each node potentially evaluates several parsers. The\n"
|
|
Packit |
1422b7 |
"parser call statistic is the number of parsers called along\n"
|
|
Packit |
1422b7 |
"the path. That number is higher, as multiple parsers may be\n"
|
|
Packit |
1422b7 |
"called at each node. The number of literal parser calls is\n"
|
|
Packit |
1422b7 |
"given explicitely, as they use almost no time to process.\n"
|
|
Packit |
1422b7 |
"\n"
|
|
Packit |
1422b7 |
);
|
|
Packit |
1422b7 |
total_len = 0;
|
|
Packit |
1422b7 |
total_cnt = 0;
|
|
Packit |
1422b7 |
fprintf(fp, "Path Length\n");
|
|
Packit |
1422b7 |
for(int i = 0 ; i < ADVSTATS_MAX_ENTITIES ; ++i) {
|
|
Packit |
1422b7 |
if(advstats_pathlens[i] > 0 ) {
|
|
Packit |
1422b7 |
fprintf(fp, "%3d: %d\n", i, advstats_pathlens[i]);
|
|
Packit |
1422b7 |
total_len += i * advstats_pathlens[i];
|
|
Packit |
1422b7 |
total_cnt += advstats_pathlens[i];
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
fprintf(fp, "avg: %f\n", (double) total_len / (double) total_cnt);
|
|
Packit |
1422b7 |
fprintf(fp, "max: %d\n", advstats_max_pathlen);
|
|
Packit |
1422b7 |
fprintf(fp, "\n");
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
total_len = 0;
|
|
Packit |
1422b7 |
total_cnt = 0;
|
|
Packit |
1422b7 |
fprintf(fp, "Nbr Backtracked\n");
|
|
Packit |
1422b7 |
for(int i = 0 ; i < ADVSTATS_MAX_ENTITIES ; ++i) {
|
|
Packit |
1422b7 |
if(advstats_backtracks[i] > 0 ) {
|
|
Packit |
1422b7 |
fprintf(fp, "%3d: %d\n", i, advstats_backtracks[i]);
|
|
Packit |
1422b7 |
total_len += i * advstats_backtracks[i];
|
|
Packit |
1422b7 |
total_cnt += advstats_backtracks[i];
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
fprintf(fp, "avg: %f\n", (double) total_len / (double) total_cnt);
|
|
Packit |
1422b7 |
fprintf(fp, "max: %d\n", advstats_max_backtracked);
|
|
Packit |
1422b7 |
fprintf(fp, "\n");
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* we calc some stats while we output */
|
|
Packit |
1422b7 |
total_len = 0;
|
|
Packit |
1422b7 |
total_cnt = 0;
|
|
Packit |
1422b7 |
fprintf(fp, "Parser Calls\n");
|
|
Packit |
1422b7 |
for(int i = 0 ; i < ADVSTATS_MAX_ENTITIES ; ++i) {
|
|
Packit |
1422b7 |
if(advstats_parser_calls[i] > 0 ) {
|
|
Packit |
1422b7 |
fprintf(fp, "%3d: %d\n", i, advstats_parser_calls[i]);
|
|
Packit |
1422b7 |
total_len += i * advstats_parser_calls[i];
|
|
Packit |
1422b7 |
total_cnt += advstats_parser_calls[i];
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
fprintf(fp, "avg: %f\n", (double) total_len / (double) total_cnt);
|
|
Packit |
1422b7 |
fprintf(fp, "max: %d\n", advstats_max_parser_calls);
|
|
Packit |
1422b7 |
fprintf(fp, "\n");
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
total_len = 0;
|
|
Packit |
1422b7 |
total_cnt = 0;
|
|
Packit |
1422b7 |
fprintf(fp, "LITERAL Parser Calls\n");
|
|
Packit |
1422b7 |
for(int i = 0 ; i < ADVSTATS_MAX_ENTITIES ; ++i) {
|
|
Packit |
1422b7 |
if(advstats_lit_parser_calls[i] > 0 ) {
|
|
Packit |
1422b7 |
fprintf(fp, "%3d: %d\n", i, advstats_lit_parser_calls[i]);
|
|
Packit |
1422b7 |
total_len += i * advstats_lit_parser_calls[i];
|
|
Packit |
1422b7 |
total_cnt += advstats_lit_parser_calls[i];
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
fprintf(fp, "avg: %f\n", (double) total_len / (double) total_cnt);
|
|
Packit |
1422b7 |
fprintf(fp, "max: %d\n", advstats_max_lit_parser_calls);
|
|
Packit |
1422b7 |
fprintf(fp, "\n");
|
|
Packit |
1422b7 |
#endif
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Check if the provided dag is a leaf. This means that it
|
|
Packit |
1422b7 |
* does not contain any subdags.
|
|
Packit |
1422b7 |
* @return 1 if it is a leaf, 0 otherwise
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static inline int
|
|
Packit |
1422b7 |
isLeaf(struct ln_pdag *dag)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
return dag->nparsers == 0 ? 1 : 0;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Add a parser instance to the pdag at the current position.
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* @param[in] ctx
|
|
Packit |
1422b7 |
* @param[in] prscnf json parser config *object* (no array!)
|
|
Packit |
1422b7 |
* @param[in] pdag current pdag position (to which parser is to be added)
|
|
Packit |
1422b7 |
* @param[in/out] nextnode contains point to the next node, either
|
|
Packit |
1422b7 |
* an existing one or one newly created.
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* The nextnode parameter permits to use this function to create
|
|
Packit |
1422b7 |
* multiple parsers alternative parsers with a single run. To do so,
|
|
Packit |
1422b7 |
* set nextnode=NULL on first call. On successive calls, keep the
|
|
Packit |
1422b7 |
* value. If a value is present, we will not accept non-identical
|
|
Packit |
1422b7 |
* parsers which point to different nodes - this will result in an
|
|
Packit |
1422b7 |
* error.
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* IMPORTANT: the caller is responsible to update its pdag pointer
|
|
Packit |
1422b7 |
* to the nextnode value when he is done adding parsers.
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* If a parser of the same type with identical data already exists,
|
|
Packit |
1422b7 |
* it is "resued", which means the function is effectively used to
|
|
Packit |
1422b7 |
* walk the path. This is used during parser construction to
|
|
Packit |
1422b7 |
* navigate to new parts of the pdag.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
ln_pdagAddParserInstance(ln_ctx ctx,
|
|
Packit |
1422b7 |
json_object *const __restrict__ prscnf,
|
|
Packit |
1422b7 |
struct ln_pdag *const __restrict__ pdag,
|
|
Packit |
1422b7 |
struct ln_pdag **nextnode)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r;
|
|
Packit |
1422b7 |
ln_parser_t *newtab;
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "ln_pdagAddParserInstance: %s, nextnode %p",
|
|
Packit |
1422b7 |
json_object_to_json_string(prscnf), *nextnode);
|
|
Packit |
1422b7 |
ln_parser_t *const parser = ln_newParser(ctx, prscnf);
|
|
Packit |
1422b7 |
CHKN(parser);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "pdag: %p, parser %p", pdag, parser);
|
|
Packit |
1422b7 |
/* check if we already have this parser, if so, merge
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
int i;
|
|
Packit |
1422b7 |
for(i = 0 ; i < pdag->nparsers ; ++i) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "parser comparison:\n%s\n%s", pdag->parsers[i].conf, parser->conf);
|
|
Packit |
1422b7 |
if( pdag->parsers[i].prsid == parser->prsid
|
|
Packit |
1422b7 |
&& !strcmp(pdag->parsers[i].conf, parser->conf)) {
|
|
Packit |
1422b7 |
// FIXME: the current ->conf object is depending on
|
|
Packit |
1422b7 |
// the order of json elements. We should do a JSON
|
|
Packit |
1422b7 |
// comparison (a bit more complex). For now, it
|
|
Packit |
1422b7 |
// works like we do it now.
|
|
Packit |
1422b7 |
// FIXME: if nextnode is set, check we can actually combine,
|
|
Packit |
1422b7 |
// else err out
|
|
Packit |
1422b7 |
*nextnode = pdag->parsers[i].node;
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "merging with pdag %p", pdag);
|
|
Packit |
1422b7 |
pdagDeletePrs(ctx, parser); /* no need for data items */
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
/* if we reach this point, we have a new parser type */
|
|
Packit |
1422b7 |
if(*nextnode == NULL) {
|
|
Packit |
1422b7 |
CHKN(*nextnode = ln_newPDAG(ctx)); /* we need a new node */
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
(*nextnode)->refcnt++;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
parser->node = *nextnode;
|
|
Packit |
1422b7 |
newtab = realloc(pdag->parsers, (pdag->nparsers+1) * sizeof(ln_parser_t));
|
|
Packit |
1422b7 |
CHKN(newtab);
|
|
Packit |
1422b7 |
pdag->parsers = newtab;
|
|
Packit |
1422b7 |
memcpy(pdag->parsers+pdag->nparsers, parser, sizeof(ln_parser_t));
|
|
Packit |
1422b7 |
pdag->nparsers++;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
free(parser);
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
static int ln_pdagAddParserInternal(ln_ctx ctx, struct ln_pdag **pdag, const int mode, json_object *const prscnf,
|
|
Packit |
1422b7 |
struct ln_pdag **nextnode);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* add parsers to current pdag. This is used
|
|
Packit |
1422b7 |
* to add parsers stored in an array. The mode specifies
|
|
Packit |
1422b7 |
* how parsers shall be added.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
#define PRS_ADD_MODE_SEQ 0
|
|
Packit |
1422b7 |
#define PRS_ADD_MODE_ALTERNATIVE 1
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
ln_pdagAddParsers(ln_ctx ctx,
|
|
Packit |
1422b7 |
json_object *const prscnf,
|
|
Packit |
1422b7 |
const int mode,
|
|
Packit |
1422b7 |
struct ln_pdag **pdag,
|
|
Packit |
1422b7 |
struct ln_pdag **p_nextnode)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = LN_BADCONFIG;
|
|
Packit |
1422b7 |
struct ln_pdag *dag = *pdag;
|
|
Packit |
1422b7 |
struct ln_pdag *nextnode = *p_nextnode;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
const int lenarr = json_object_array_length(prscnf);
|
|
Packit |
1422b7 |
for(int i = 0 ; i < lenarr ; ++i) {
|
|
Packit |
1422b7 |
struct json_object *const curr_prscnf =
|
|
Packit |
1422b7 |
json_object_array_get_idx(prscnf, i);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "parser %d: %s", i, json_object_to_json_string(curr_prscnf));
|
|
Packit |
1422b7 |
if(json_object_get_type(curr_prscnf) == json_type_array) {
|
|
Packit |
1422b7 |
struct ln_pdag *local_dag = dag;
|
|
Packit |
1422b7 |
CHKR(ln_pdagAddParserInternal(ctx, &local_dag, mode,
|
|
Packit |
1422b7 |
curr_prscnf, &nextnode));
|
|
Packit |
1422b7 |
if(mode == PRS_ADD_MODE_SEQ) {
|
|
Packit |
1422b7 |
dag = local_dag;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
CHKR(ln_pdagAddParserInstance(ctx, curr_prscnf, dag, &nextnode));
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(mode == PRS_ADD_MODE_SEQ) {
|
|
Packit |
1422b7 |
dag = nextnode;
|
|
Packit |
1422b7 |
*p_nextnode = nextnode;
|
|
Packit |
1422b7 |
nextnode = NULL;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(mode != PRS_ADD_MODE_SEQ)
|
|
Packit |
1422b7 |
dag = nextnode;
|
|
Packit |
1422b7 |
*pdag = dag;
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* add a json parser config object. Note that this object may contain
|
|
Packit |
1422b7 |
* multiple parser instances. Additionally, moves the pdag object to
|
|
Packit |
1422b7 |
* the next node, which is either newly created or previously existed.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
ln_pdagAddParserInternal(ln_ctx ctx, struct ln_pdag **pdag,
|
|
Packit |
1422b7 |
const int mode, json_object *const prscnf, struct ln_pdag **nextnode)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = LN_BADCONFIG;
|
|
Packit |
1422b7 |
struct ln_pdag *dag = *pdag;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "ln_pdagAddParserInternal: %s", json_object_to_json_string(prscnf));
|
|
Packit |
1422b7 |
if(json_object_get_type(prscnf) == json_type_object) {
|
|
Packit |
1422b7 |
/* check for special types we need to handle here */
|
|
Packit |
1422b7 |
struct json_object *json;
|
|
Packit |
1422b7 |
json_object_object_get_ex(prscnf, "type", &json);
|
|
Packit |
1422b7 |
const char *const ftype = json_object_get_string(json);
|
|
Packit |
1422b7 |
if(!strcmp(ftype, "alternative")) {
|
|
Packit |
1422b7 |
json_object_object_get_ex(prscnf, "parser", &json);
|
|
Packit |
1422b7 |
if(json_object_get_type(json) != json_type_array) {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "alternative type needs array of parsers. "
|
|
Packit |
1422b7 |
"Object: '%s', type is %s",
|
|
Packit |
1422b7 |
json_object_to_json_string(prscnf),
|
|
Packit |
1422b7 |
json_type_to_name(json_object_get_type(json)));
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
CHKR(ln_pdagAddParsers(ctx, json, PRS_ADD_MODE_ALTERNATIVE, &dag, nextnode));
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
CHKR(ln_pdagAddParserInstance(ctx, prscnf, dag, nextnode));
|
|
Packit |
1422b7 |
if(mode == PRS_ADD_MODE_SEQ)
|
|
Packit |
1422b7 |
dag = *nextnode;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else if(json_object_get_type(prscnf) == json_type_array) {
|
|
Packit |
1422b7 |
CHKR(ln_pdagAddParsers(ctx, prscnf, PRS_ADD_MODE_SEQ, &dag, nextnode));
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "bug: prscnf object of wrong type. Object: '%s'",
|
|
Packit |
1422b7 |
json_object_to_json_string(prscnf));
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
*pdag = dag;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* add a json parser config object. Note that this object may contain
|
|
Packit |
1422b7 |
* multiple parser instances. Additionally, moves the pdag object to
|
|
Packit |
1422b7 |
* the next node, which is either newly created or previously existed.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
int
|
|
Packit |
1422b7 |
ln_pdagAddParser(ln_ctx ctx, struct ln_pdag **pdag, json_object *const prscnf)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
struct ln_pdag *nextnode = NULL;
|
|
Packit |
1422b7 |
int r = ln_pdagAddParserInternal(ctx, pdag, PRS_ADD_MODE_SEQ, prscnf, &nextnode);
|
|
Packit |
1422b7 |
json_object_put(prscnf);
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
void
|
|
Packit |
1422b7 |
ln_displayPDAGComponent(struct ln_pdag *dag, int level)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
char indent[2048];
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(level > 1023)
|
|
Packit |
1422b7 |
level = 1023;
|
|
Packit |
1422b7 |
memset(indent, ' ', level * 2);
|
|
Packit |
1422b7 |
indent[level * 2] = '\0';
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "%ssubDAG%s %p (children: %d parsers, ref %d) [called %u, backtracked %u]",
|
|
Packit |
1422b7 |
indent, dag->flags.isTerminal ? " [TERM]" : "", dag, dag->nparsers, dag->refcnt,
|
|
Packit |
1422b7 |
dag->stats.called, dag->stats.backtracked);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
for(int i = 0 ; i < dag->nparsers ; ++i) {
|
|
Packit |
1422b7 |
ln_parser_t *const prs = dag->parsers+i;
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "%sfield type '%s', name '%s': '%s': called %u", indent,
|
|
Packit |
1422b7 |
parserName(prs->prsid),
|
|
Packit |
1422b7 |
dag->parsers[i].name,
|
|
Packit |
1422b7 |
(prs->prsid == PRS_LITERAL) ? ln_DataForDisplayLiteral(dag->ctx, prs->parser_data) : "UNKNOWN",
|
|
Packit |
1422b7 |
dag->parsers[i].node->stats.called);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
for(int i = 0 ; i < dag->nparsers ; ++i) {
|
|
Packit |
1422b7 |
ln_parser_t *const prs = dag->parsers+i;
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "%sfield type '%s', name '%s': '%s':", indent,
|
|
Packit |
1422b7 |
parserName(prs->prsid),
|
|
Packit |
1422b7 |
dag->parsers[i].name,
|
|
Packit |
1422b7 |
(prs->prsid == PRS_LITERAL) ? ln_DataForDisplayLiteral(dag->ctx, prs->parser_data) :
|
|
Packit |
1422b7 |
"UNKNOWN");
|
|
Packit |
1422b7 |
if(prs->prsid == PRS_REPEAT) {
|
|
Packit |
1422b7 |
struct data_Repeat *const data = (struct data_Repeat*) prs->parser_data;
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "%sparser:", indent);
|
|
Packit |
1422b7 |
ln_displayPDAGComponent(data->parser, level + 1);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "%swhile:", indent);
|
|
Packit |
1422b7 |
ln_displayPDAGComponent(data->while_cond, level + 1);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "%send repeat def", indent);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
ln_displayPDAGComponent(dag->parsers[i].node, level + 1);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
void ln_displayPDAGComponentAlternative(struct ln_pdag *dag, int level)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
char indent[2048];
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(level > 1023)
|
|
Packit |
1422b7 |
level = 1023;
|
|
Packit |
1422b7 |
memset(indent, ' ', level * 2);
|
|
Packit |
1422b7 |
indent[level * 2] = '\0';
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "%s%p[ref %d]: %s", indent, dag, dag->refcnt, dag->rb_id);
|
|
Packit |
1422b7 |
for(int i = 0 ; i < dag->nparsers ; ++i) {
|
|
Packit |
1422b7 |
ln_displayPDAGComponentAlternative(dag->parsers[i].node, level + 1);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* developer debug aid, to be used for example as follows:
|
|
Packit |
1422b7 |
* LN_DBGPRINTF(dag->ctx, "---------------------------------------");
|
|
Packit |
1422b7 |
* ln_displayPDAG(dag);
|
|
Packit |
1422b7 |
* LN_DBGPRINTF(dag->ctx, "=======================================");
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
void
|
|
Packit |
1422b7 |
ln_displayPDAG(ln_ctx ctx)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
ln_pdagClearVisited(ctx);
|
|
Packit |
1422b7 |
for(int i = 0 ; i < ctx->nTypes ; ++i) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "COMPONENT: %s", ctx->type_pdags[i].name);
|
|
Packit |
1422b7 |
ln_displayPDAGComponent(ctx->type_pdags[i].pdag, 0);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "MAIN COMPONENT:");
|
|
Packit |
1422b7 |
ln_displayPDAGComponent(ctx->pdag, 0);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "MAIN COMPONENT (alternative):");
|
|
Packit |
1422b7 |
ln_displayPDAGComponentAlternative(ctx->pdag, 0);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* the following is a quick hack, which should be moved to the
|
|
Packit |
1422b7 |
* string class.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static inline void dotAddPtr(es_str_t **str, void *p)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
char buf[64];
|
|
Packit |
1422b7 |
int i;
|
|
Packit |
1422b7 |
i = snprintf(buf, sizeof(buf), "l%p", p);
|
|
Packit |
1422b7 |
es_addBuf(str, buf, i);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
struct data_Literal { const char *lit; }; // TODO remove when this hack is no longe needed
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* recursive handler for DOT graph generator.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static void
|
|
Packit |
1422b7 |
ln_genDotPDAGGraphRec(struct ln_pdag *dag, es_str_t **str)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
char s_refcnt[16];
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "in dot: %p, visited %d", dag, (int) dag->flags.visited);
|
|
Packit |
1422b7 |
if(dag->flags.visited)
|
|
Packit |
1422b7 |
return; /* already processed this subpart */
|
|
Packit |
1422b7 |
dag->flags.visited = 1;
|
|
Packit |
1422b7 |
dotAddPtr(str, dag);
|
|
Packit |
1422b7 |
snprintf(s_refcnt, sizeof(s_refcnt), "%d", dag->refcnt);
|
|
Packit |
1422b7 |
s_refcnt[sizeof(s_refcnt)-1] = '\0';
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, " [ label=\"");
|
|
Packit |
1422b7 |
es_addBuf(str, s_refcnt, strlen(s_refcnt));
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, "\"");
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(isLeaf(dag)) {
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, " style=\"bold\"");
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, "]\n");
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* display field subdags */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
for(int i = 0 ; i < dag->nparsers ; ++i) {
|
|
Packit |
1422b7 |
ln_parser_t *const prs = dag->parsers+i;
|
|
Packit |
1422b7 |
dotAddPtr(str, dag);
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, " -> ");
|
|
Packit |
1422b7 |
dotAddPtr(str, prs->node);
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, " [label=\"");
|
|
Packit |
1422b7 |
es_addBuf(str, parserName(prs->prsid), strlen(parserName(prs->prsid)));
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, ":");
|
|
Packit |
1422b7 |
//es_addStr(str, node->name);
|
|
Packit |
1422b7 |
if(prs->prsid == PRS_LITERAL) {
|
|
Packit |
1422b7 |
for(const char *p = ((struct data_Literal*)prs->parser_data)->lit ; *p ; ++p) {
|
|
Packit |
1422b7 |
// TODO: handle! if(*p == '\\')
|
|
Packit |
1422b7 |
//es_addChar(str, '\\');
|
|
Packit |
1422b7 |
if(*p != '\\' && *p != '"')
|
|
Packit |
1422b7 |
es_addChar(str, *p);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, "\"");
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, " style=\"dotted\"]\n");
|
|
Packit |
1422b7 |
ln_genDotPDAGGraphRec(prs->node, str);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
void
|
|
Packit |
1422b7 |
ln_genDotPDAGGraph(struct ln_pdag *dag, es_str_t **str)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
ln_pdagClearVisited(dag->ctx);
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, "digraph pdag {\n");
|
|
Packit |
1422b7 |
ln_genDotPDAGGraphRec(dag, str);
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, "}\n");
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* recursive handler for statistics DOT graph generator.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static void
|
|
Packit |
1422b7 |
ln_genStatsDotPDAGGraphRec(struct ln_pdag *dag, FILE *const __restrict__ fp)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
if(dag->flags.visited)
|
|
Packit |
1422b7 |
return; /* already processed this subpart */
|
|
Packit |
1422b7 |
dag->flags.visited = 1;
|
|
Packit |
1422b7 |
fprintf(fp, "l%p [ label=\"%u:%u\"", dag,
|
|
Packit |
1422b7 |
dag->stats.called, dag->stats.backtracked);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(isLeaf(dag)) {
|
|
Packit |
1422b7 |
fprintf(fp, " style=\"bold\"");
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
fprintf(fp, "]\n");
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* display field subdags */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
for(int i = 0 ; i < dag->nparsers ; ++i) {
|
|
Packit |
1422b7 |
ln_parser_t *const prs = dag->parsers+i;
|
|
Packit |
1422b7 |
if(prs->node->stats.called == 0)
|
|
Packit |
1422b7 |
continue;
|
|
Packit |
1422b7 |
fprintf(fp, "l%p -> l%p [label=\"", dag, prs->node);
|
|
Packit |
1422b7 |
if(prs->prsid == PRS_LITERAL) {
|
|
Packit |
1422b7 |
for(const char *p = ((struct data_Literal*)prs->parser_data)->lit ; *p ; ++p) {
|
|
Packit |
1422b7 |
if(*p != '\\' && *p != '"')
|
|
Packit |
1422b7 |
fputc(*p, fp);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
fprintf(fp, "%s", parserName(prs->prsid));
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
fprintf(fp, "\" style=\"dotted\"]\n");
|
|
Packit |
1422b7 |
ln_genStatsDotPDAGGraphRec(prs->node, fp);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
static void
|
|
Packit |
1422b7 |
ln_genStatsDotPDAGGraph(struct ln_pdag *dag, FILE *const fp)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
ln_pdagClearVisited(dag->ctx);
|
|
Packit |
1422b7 |
fprintf(fp, "digraph pdag {\n");
|
|
Packit |
1422b7 |
ln_genStatsDotPDAGGraphRec(dag, fp);
|
|
Packit |
1422b7 |
fprintf(fp, "}\n");
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
void
|
|
Packit |
1422b7 |
ln_fullPDagStatsDOT(ln_ctx ctx, FILE *const fp)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
ln_genStatsDotPDAGGraph(ctx->pdag, fp);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
static inline int
|
|
Packit |
1422b7 |
addOriginalMsg(const char *str, const size_t strLen, struct json_object *const json)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 1;
|
|
Packit |
1422b7 |
struct json_object *value;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
value = json_object_new_string_len(str, strLen);
|
|
Packit |
1422b7 |
if (value == NULL) {
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
json_object_object_add(json, ORIGINAL_MSG_KEY, value);
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
static char *
|
|
Packit |
1422b7 |
strrev(char *const __restrict__ str)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
char ch;
|
|
Packit |
1422b7 |
size_t i = strlen(str)-1,j=0;
|
|
Packit |
1422b7 |
while(i>j)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
ch = str[i];
|
|
Packit |
1422b7 |
str[i]= str[j];
|
|
Packit |
1422b7 |
str[j] = ch;
|
|
Packit |
1422b7 |
i--;
|
|
Packit |
1422b7 |
j++;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
return str;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* note: "originalmsg" is NOT added as metadata in order to keep
|
|
Packit |
1422b7 |
* backwards compatible.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static inline void
|
|
Packit |
1422b7 |
addRuleMetadata(npb_t *const __restrict__ npb,
|
|
Packit |
1422b7 |
struct json_object *const json,
|
|
Packit |
1422b7 |
struct ln_pdag *const __restrict__ endNode)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
ln_ctx ctx = npb->ctx;
|
|
Packit |
1422b7 |
struct json_object *meta = NULL;
|
|
Packit |
1422b7 |
struct json_object *meta_rule = NULL;
|
|
Packit |
1422b7 |
struct json_object *value;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(ctx->opts & LN_CTXOPT_ADD_RULE) { /* matching rule mockup */
|
|
Packit |
1422b7 |
if(meta_rule == NULL)
|
|
Packit |
1422b7 |
meta_rule = json_object_new_object();
|
|
Packit |
1422b7 |
char *cstr = strrev(es_str2cstr(npb->rule, NULL));
|
|
Packit |
1422b7 |
json_object_object_add(meta_rule, RULE_MOCKUP_KEY,
|
|
Packit |
1422b7 |
json_object_new_string(cstr));
|
|
Packit |
1422b7 |
free(cstr);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(ctx->opts & LN_CTXOPT_ADD_RULE_LOCATION) {
|
|
Packit |
1422b7 |
if(meta_rule == NULL)
|
|
Packit |
1422b7 |
meta_rule = json_object_new_object();
|
|
Packit |
1422b7 |
struct json_object *const location = json_object_new_object();
|
|
Packit |
1422b7 |
value = json_object_new_string(endNode->rb_file);
|
|
Packit |
1422b7 |
json_object_object_add(location, "file", value);
|
|
Packit |
1422b7 |
value = json_object_new_int((int)endNode->rb_lineno);
|
|
Packit |
1422b7 |
json_object_object_add(location, "line", value);
|
|
Packit |
1422b7 |
json_object_object_add(meta_rule, RULE_LOCATION_KEY, location);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(meta_rule != NULL) {
|
|
Packit |
1422b7 |
if(meta == NULL)
|
|
Packit |
1422b7 |
meta = json_object_new_object();
|
|
Packit |
1422b7 |
json_object_object_add(meta, META_RULE_KEY, meta_rule);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
#ifdef ADVANCED_STATS
|
|
Packit |
1422b7 |
/* complete execution path */
|
|
Packit |
1422b7 |
if(ctx->opts & LN_CTXOPT_ADD_EXEC_PATH) {
|
|
Packit |
1422b7 |
if(meta == NULL)
|
|
Packit |
1422b7 |
meta = json_object_new_object();
|
|
Packit |
1422b7 |
char hdr[128];
|
|
Packit |
1422b7 |
const size_t lenhdr
|
|
Packit |
1422b7 |
= snprintf(hdr, sizeof(hdr), "[PATHLEN:%d, PARSER CALLS gen:%d, literal:%d]",
|
|
Packit |
1422b7 |
npb->astats.pathlen, npb->astats.parser_calls,
|
|
Packit |
1422b7 |
npb->astats.lit_parser_calls);
|
|
Packit |
1422b7 |
es_addBuf(&npb->astats.exec_path, hdr, lenhdr);
|
|
Packit |
1422b7 |
char * cstr = es_str2cstr(npb->astats.exec_path, NULL);
|
|
Packit |
1422b7 |
value = json_object_new_string(cstr);
|
|
Packit |
1422b7 |
if (value != NULL) {
|
|
Packit |
1422b7 |
json_object_object_add(meta, EXEC_PATH_KEY, value);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
free(cstr);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
#endif
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(meta != NULL)
|
|
Packit |
1422b7 |
json_object_object_add(json, META_KEY, meta);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* add unparsed string to event.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static inline int
|
|
Packit |
1422b7 |
addUnparsedField(const char *str, const size_t strLen, const size_t offs, struct json_object *json)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 1;
|
|
Packit |
1422b7 |
struct json_object *value;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
CHKR(addOriginalMsg(str, strLen, json));
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
value = json_object_new_string(str + offs);
|
|
Packit |
1422b7 |
if (value == NULL) {
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
json_object_object_add(json, UNPARSED_DATA_KEY, value);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* Do some fixup to the json that we cannot do on a lower layer */
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
fixJSON(struct ln_pdag *dag,
|
|
Packit |
1422b7 |
struct json_object **value,
|
|
Packit |
1422b7 |
struct json_object *json,
|
|
Packit |
1422b7 |
const ln_parser_t *const prs)
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = LN_WRONGPARSER;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(prs->name == NULL) {
|
|
Packit |
1422b7 |
if (*value != NULL) {
|
|
Packit |
1422b7 |
/* Free the unneeded value */
|
|
Packit |
1422b7 |
json_object_put(*value);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else if(prs->name[0] == '.' && prs->name[1] == '\0') {
|
|
Packit |
1422b7 |
if(json_object_get_type(*value) == json_type_object) {
|
|
Packit |
1422b7 |
struct json_object_iterator it = json_object_iter_begin(*value);
|
|
Packit |
1422b7 |
struct json_object_iterator itEnd = json_object_iter_end(*value);
|
|
Packit |
1422b7 |
while (!json_object_iter_equal(&it, &itEnd)) {
|
|
Packit |
1422b7 |
struct json_object *const val = json_object_iter_peek_value(&it);
|
|
Packit |
1422b7 |
json_object_get(val);
|
|
Packit |
1422b7 |
json_object_object_add(json, json_object_iter_peek_name(&it), val);
|
|
Packit |
1422b7 |
json_object_iter_next(&it);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
json_object_put(*value);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "field name is '.', but json type is %s",
|
|
Packit |
1422b7 |
json_type_to_name(json_object_get_type(*value)));
|
|
Packit |
1422b7 |
json_object_object_add_ex(json, prs->name, *value,
|
|
Packit |
1422b7 |
JSON_C_OBJECT_ADD_KEY_IS_NEW|JSON_C_OBJECT_KEY_IS_CONSTANT);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
int isDotDot = 0;
|
|
Packit |
1422b7 |
struct json_object *valDotDot = NULL;
|
|
Packit |
1422b7 |
if(json_object_get_type(*value) == json_type_object) {
|
|
Packit |
1422b7 |
/* TODO: this needs to be speeded up by just checking the first
|
|
Packit |
1422b7 |
* member and ensuring there is only one member. This requires
|
|
Packit |
1422b7 |
* extensions to libfastjson.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
int nSubobj = 0;
|
|
Packit |
1422b7 |
struct json_object_iterator it = json_object_iter_begin(*value);
|
|
Packit |
1422b7 |
struct json_object_iterator itEnd = json_object_iter_end(*value);
|
|
Packit |
1422b7 |
while (!json_object_iter_equal(&it, &itEnd)) {
|
|
Packit |
1422b7 |
++nSubobj;
|
|
Packit |
1422b7 |
const char *key = json_object_iter_peek_name(&it);
|
|
Packit |
1422b7 |
if(key[0] == '.' && key[1] == '.' && key[2] == '\0') {
|
|
Packit |
1422b7 |
isDotDot = 1;
|
|
Packit |
1422b7 |
valDotDot = json_object_iter_peek_value(&it);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
isDotDot = 0;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
json_object_iter_next(&it);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(nSubobj != 1)
|
|
Packit |
1422b7 |
isDotDot = 0;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(isDotDot) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "subordinate field name is '..', combining");
|
|
Packit |
1422b7 |
json_object_get(valDotDot);
|
|
Packit |
1422b7 |
json_object_put(*value);
|
|
Packit |
1422b7 |
json_object_object_add_ex(json, prs->name, valDotDot,
|
|
Packit |
1422b7 |
JSON_C_OBJECT_ADD_KEY_IS_NEW|JSON_C_OBJECT_KEY_IS_CONSTANT);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
json_object_object_add_ex(json, prs->name, *value,
|
|
Packit |
1422b7 |
JSON_C_OBJECT_ADD_KEY_IS_NEW|JSON_C_OBJECT_KEY_IS_CONSTANT);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
// TODO: streamline prototype when done with changes
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
tryParser(npb_t *const __restrict__ npb,
|
|
Packit |
1422b7 |
struct ln_pdag *dag,
|
|
Packit |
1422b7 |
size_t *offs,
|
|
Packit |
1422b7 |
size_t *const __restrict__ pParsed,
|
|
Packit |
1422b7 |
struct json_object **value,
|
|
Packit |
1422b7 |
const ln_parser_t *const prs
|
|
Packit |
1422b7 |
)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r;
|
|
Packit |
1422b7 |
struct ln_pdag *endNode = NULL;
|
|
Packit |
1422b7 |
size_t parsedTo = npb->parsedTo;
|
|
Packit |
1422b7 |
# ifdef ADVANCED_STATS
|
|
Packit |
1422b7 |
char hdr[16];
|
|
Packit |
1422b7 |
const size_t lenhdr
|
|
Packit |
1422b7 |
= snprintf(hdr, sizeof(hdr), "%d:", npb->astats.recursion_level);
|
|
Packit |
1422b7 |
es_addBuf(&npb->astats.exec_path, hdr, lenhdr);
|
|
Packit |
1422b7 |
if(prs->prsid == PRS_LITERAL) {
|
|
Packit |
1422b7 |
es_addChar(&npb->astats.exec_path, '\'');
|
|
Packit |
1422b7 |
es_addBuf(&npb->astats.exec_path,
|
|
Packit |
1422b7 |
ln_DataForDisplayLiteral(dag->ctx,
|
|
Packit |
1422b7 |
prs->parser_data),
|
|
Packit |
1422b7 |
strlen(ln_DataForDisplayLiteral(dag->ctx,
|
|
Packit |
1422b7 |
prs->parser_data))
|
|
Packit |
1422b7 |
);
|
|
Packit |
1422b7 |
es_addChar(&npb->astats.exec_path, '\'');
|
|
Packit |
1422b7 |
} else if(parser_lookup_table[prs->prsid].parser
|
|
Packit |
1422b7 |
== ln_v2_parseCharTo) {
|
|
Packit |
1422b7 |
es_addBuf(&npb->astats.exec_path,
|
|
Packit |
1422b7 |
ln_DataForDisplayCharTo(dag->ctx,
|
|
Packit |
1422b7 |
prs->parser_data),
|
|
Packit |
1422b7 |
strlen(ln_DataForDisplayCharTo(dag->ctx,
|
|
Packit |
1422b7 |
prs->parser_data))
|
|
Packit |
1422b7 |
);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
es_addBuf(&npb->astats.exec_path,
|
|
Packit |
1422b7 |
parserName(prs->prsid),
|
|
Packit |
1422b7 |
strlen(parserName(prs->prsid)) );
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
es_addChar(&npb->astats.exec_path, ',');
|
|
Packit |
1422b7 |
# endif
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(prs->prsid == PRS_CUSTOM_TYPE) {
|
|
Packit |
1422b7 |
if(*value == NULL)
|
|
Packit |
1422b7 |
*value = json_object_new_object();
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "calling custom parser '%s'", prs->custType->name);
|
|
Packit |
1422b7 |
r = ln_normalizeRec(npb, prs->custType->pdag, *offs, 1, *value, &endNode);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "called CUSTOM PARSER '%s', result %d, "
|
|
Packit |
1422b7 |
"offs %zd, *pParsed %zd", prs->custType->name, r, *offs, *pParsed);
|
|
Packit |
1422b7 |
*pParsed = npb->parsedTo - *offs;
|
|
Packit |
1422b7 |
#ifdef ADVANCED_STATS
|
|
Packit |
1422b7 |
es_addBuf(&npb->astats.exec_path, hdr, lenhdr);
|
|
Packit |
1422b7 |
es_addBuf(&npb->astats.exec_path, "[R:USR],", 8);
|
|
Packit |
1422b7 |
#endif
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
r = parser_lookup_table[prs->prsid].parser(npb,
|
|
Packit |
1422b7 |
offs, prs->parser_data, pParsed, (prs->name == NULL) ? NULL : value);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
LN_DBGPRINTF(npb->ctx, "parser lookup returns %d, pParsed %zu", r, *pParsed);
|
|
Packit |
1422b7 |
npb->parsedTo = parsedTo;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
#ifdef ADVANCED_STATS
|
|
Packit |
1422b7 |
++advstats_parsers_called;
|
|
Packit |
1422b7 |
++npb->astats.parser_calls;
|
|
Packit |
1422b7 |
if(prs->prsid == PRS_LITERAL)
|
|
Packit |
1422b7 |
++npb->astats.lit_parser_calls;
|
|
Packit |
1422b7 |
if(r == 0)
|
|
Packit |
1422b7 |
++advstats_parsers_success;
|
|
Packit |
1422b7 |
if(prs->prsid != PRS_CUSTOM_TYPE) {
|
|
Packit |
1422b7 |
++parser_lookup_table[prs->prsid].called;
|
|
Packit |
1422b7 |
if(r == 0)
|
|
Packit |
1422b7 |
++parser_lookup_table[prs->prsid].success;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
#endif
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
static void
|
|
Packit |
1422b7 |
add_str_reversed(npb_t *const __restrict__ npb,
|
|
Packit |
1422b7 |
const char *const __restrict__ str,
|
|
Packit |
1422b7 |
const size_t len)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
ssize_t i;
|
|
Packit |
1422b7 |
for(i = len - 1 ; i >= 0 ; --i) {
|
|
Packit |
1422b7 |
es_addChar(&npb->rule, str[i]);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* Add the current parser to the mockup rule.
|
|
Packit |
1422b7 |
* Note: we add reversed strings, because we can call this
|
|
Packit |
1422b7 |
* function effectively only when walking upwards the tree.
|
|
Packit |
1422b7 |
* This means deepest entries come first. We solve this somewhat
|
|
Packit |
1422b7 |
* elegantly by reversion strings, and then reversion the string
|
|
Packit |
1422b7 |
* once more when we emit it, so that we get the right order.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static inline void
|
|
Packit |
1422b7 |
add_rule_to_mockup(npb_t *const __restrict__ npb,
|
|
Packit |
1422b7 |
const ln_parser_t *const __restrict__ prs)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
if(prs->prsid == PRS_LITERAL) {
|
|
Packit |
1422b7 |
const char *const val =
|
|
Packit |
1422b7 |
ln_DataForDisplayLiteral(npb->ctx,
|
|
Packit |
1422b7 |
prs->parser_data);
|
|
Packit |
1422b7 |
add_str_reversed(npb, val, strlen(val));
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
/* note: name/value order must also be reversed! */
|
|
Packit |
1422b7 |
es_addChar(&npb->rule, '%');
|
|
Packit |
1422b7 |
add_str_reversed(npb,
|
|
Packit |
1422b7 |
parserName(prs->prsid),
|
|
Packit |
1422b7 |
strlen(parserName(prs->prsid)) );
|
|
Packit |
1422b7 |
es_addChar(&npb->rule, ':');
|
|
Packit |
1422b7 |
if(prs->name == NULL) {
|
|
Packit |
1422b7 |
es_addChar(&npb->rule, '-');
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
add_str_reversed(npb, prs->name, strlen(prs->name));
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
es_addChar(&npb->rule, '%');
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Recursive step of the normalizer. It walks the parse dag and calls itself
|
|
Packit |
1422b7 |
* recursively when this is appropriate. It also implements backtracking in
|
|
Packit |
1422b7 |
* those (hopefully rare) cases where it is required.
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* @param[in] dag current tree to process
|
|
Packit |
1422b7 |
* @param[in] string string to be matched against (the to-be-normalized data)
|
|
Packit |
1422b7 |
* @param[in] strLen length of the to-be-matched string
|
|
Packit |
1422b7 |
* @param[in] offs start position in input data
|
|
Packit |
1422b7 |
* @param[out] pPrasedTo ptr to position up to which the the parsing succed in max
|
|
Packit |
1422b7 |
* @param[in/out] json ... that is being created during normalization
|
|
Packit |
1422b7 |
* @param[out] endNode if a match was found, this is the matching node (undefined otherwise)
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* @return regular liblognorm error code (0->OK, something else->error)
|
|
Packit |
1422b7 |
* TODO: can we use parameter block to prevent pushing params to the stack?
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
int
|
|
Packit |
1422b7 |
ln_normalizeRec(npb_t *const __restrict__ npb,
|
|
Packit |
1422b7 |
struct ln_pdag *dag,
|
|
Packit |
1422b7 |
const size_t offs,
|
|
Packit |
1422b7 |
const int bPartialMatch,
|
|
Packit |
1422b7 |
struct json_object *json,
|
|
Packit |
1422b7 |
struct ln_pdag **endNode
|
|
Packit |
1422b7 |
)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = LN_WRONGPARSER;
|
|
Packit |
1422b7 |
int localR;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
size_t iprs;
|
|
Packit |
1422b7 |
size_t parsedTo = npb->parsedTo;
|
|
Packit |
1422b7 |
size_t parsed = 0;
|
|
Packit |
1422b7 |
struct json_object *value;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "%zu: enter parser, dag node %p, json %p", offs, dag, json);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
++dag->stats.called;
|
|
Packit |
1422b7 |
#ifdef ADVANCED_STATS
|
|
Packit |
1422b7 |
++npb->astats.pathlen;
|
|
Packit |
1422b7 |
++npb->astats.recursion_level;
|
|
Packit |
1422b7 |
#endif
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* now try the parsers */
|
|
Packit |
1422b7 |
for(iprs = 0 ; iprs < dag->nparsers && r != 0 ; ++iprs) {
|
|
Packit |
1422b7 |
const ln_parser_t *const prs = dag->parsers + iprs;
|
|
Packit |
1422b7 |
if(dag->ctx->debug) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "%zu/%d:trying '%s' parser for field '%s', "
|
|
Packit |
1422b7 |
"data '%s'",
|
|
Packit |
1422b7 |
offs, bPartialMatch, parserName(prs->prsid), prs->name,
|
|
Packit |
1422b7 |
(prs->prsid == PRS_LITERAL)
|
|
Packit |
1422b7 |
? ln_DataForDisplayLiteral(dag->ctx, prs->parser_data)
|
|
Packit |
1422b7 |
: "UNKNOWN");
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
i = offs;
|
|
Packit |
1422b7 |
value = NULL;
|
|
Packit |
1422b7 |
localR = tryParser(npb, dag, &i, &parsed, &value, prs);
|
|
Packit |
1422b7 |
if(localR == 0) {
|
|
Packit |
1422b7 |
parsedTo = i + parsed;
|
|
Packit |
1422b7 |
/* potential hit, need to verify */
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "%zu: potential hit, trying subtree %p",
|
|
Packit |
1422b7 |
offs, prs->node);
|
|
Packit |
1422b7 |
r = ln_normalizeRec(npb, prs->node, parsedTo,
|
|
Packit |
1422b7 |
bPartialMatch, json, endNode);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "%zu: subtree returns %d, parsedTo %zu", offs, r, parsedTo);
|
|
Packit |
1422b7 |
if(r == 0) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "%zu: parser matches at %zu", offs, i);
|
|
Packit |
1422b7 |
CHKR(fixJSON(dag, &value, json, prs));
|
|
Packit |
1422b7 |
if(npb->ctx->opts & LN_CTXOPT_ADD_RULE) {
|
|
Packit |
1422b7 |
add_rule_to_mockup(npb, prs);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
++dag->stats.backtracked;
|
|
Packit |
1422b7 |
#ifdef ADVANCED_STATS
|
|
Packit |
1422b7 |
++npb->astats.backtracked;
|
|
Packit |
1422b7 |
es_addBuf(&npb->astats.exec_path, "[B]", 3);
|
|
Packit |
1422b7 |
#endif
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "%zu nonmatch, backtracking required, parsed to=%zu",
|
|
Packit |
1422b7 |
offs, parsedTo);
|
|
Packit |
1422b7 |
if (value != NULL) { /* Free the value if it was created */
|
|
Packit |
1422b7 |
json_object_put(value);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
/* did we have a longer parser --> then update */
|
|
Packit |
1422b7 |
if(parsedTo > npb->parsedTo)
|
|
Packit |
1422b7 |
npb->parsedTo = parsedTo;
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "parsedTo %zu, *pParsedTo %zu", parsedTo, npb->parsedTo);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "offs %zu, strLen %zu, isTerm %d", offs, npb->strLen, dag->flags.isTerminal);
|
|
Packit |
1422b7 |
if(dag->flags.isTerminal && (offs == npb->strLen || bPartialMatch)) {
|
|
Packit |
1422b7 |
*endNode = dag;
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
LN_DBGPRINTF(dag->ctx, "%zu returns %d, pParsedTo %zu, parsedTo %zu",
|
|
Packit |
1422b7 |
offs, r, npb->parsedTo, parsedTo);
|
|
Packit |
1422b7 |
# ifdef ADVANCED_STATS
|
|
Packit |
1422b7 |
--npb->astats.recursion_level;
|
|
Packit |
1422b7 |
# endif
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
int
|
|
Packit |
1422b7 |
ln_normalize(ln_ctx ctx, const char *str, const size_t strLen, struct json_object **json_p)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r;
|
|
Packit |
1422b7 |
struct ln_pdag *endNode = NULL;
|
|
Packit |
1422b7 |
/* old cruft */
|
|
Packit |
1422b7 |
if(ctx->version == 1) {
|
|
Packit |
1422b7 |
r = ln_v1_normalize(ctx, str, strLen, json_p);
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
/* end old cruft */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
npb_t npb;
|
|
Packit |
1422b7 |
memset(&npb, 0, sizeof(npb));
|
|
Packit |
1422b7 |
npb.ctx = ctx;
|
|
Packit |
1422b7 |
npb.str = str;
|
|
Packit |
1422b7 |
npb.strLen = strLen;
|
|
Packit |
1422b7 |
if(ctx->opts & LN_CTXOPT_ADD_RULE) {
|
|
Packit |
1422b7 |
npb.rule = es_newStr(1024);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
# ifdef ADVANCED_STATS
|
|
Packit |
1422b7 |
npb.astats.exec_path = es_newStr(1024);
|
|
Packit |
1422b7 |
# endif
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(*json_p == NULL) {
|
|
Packit |
1422b7 |
CHKN(*json_p = json_object_new_object());
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
r = ln_normalizeRec(&npb, ctx->pdag, 0, 0, *json_p, &endNode);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(ctx->debug) {
|
|
Packit |
1422b7 |
if(r == 0) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "final result for normalizer: parsedTo %zu, endNode %p, "
|
|
Packit |
1422b7 |
"isTerminal %d, tagbucket %p",
|
|
Packit |
1422b7 |
npb.parsedTo, endNode, endNode->flags.isTerminal, endNode->tags);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "final result for normalizer: parsedTo %zu, endNode %p",
|
|
Packit |
1422b7 |
npb.parsedTo, endNode);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "DONE, final return is %d", r);
|
|
Packit |
1422b7 |
if(r == 0 && endNode->flags.isTerminal) {
|
|
Packit |
1422b7 |
/* success, finalize event */
|
|
Packit |
1422b7 |
if(endNode->tags != NULL) {
|
|
Packit |
1422b7 |
/* add tags to an event */
|
|
Packit |
1422b7 |
json_object_get(endNode->tags);
|
|
Packit |
1422b7 |
json_object_object_add(*json_p, "event.tags", endNode->tags);
|
|
Packit |
1422b7 |
CHKR(ln_annotate(ctx, *json_p, endNode->tags));
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(ctx->opts & LN_CTXOPT_ADD_ORIGINALMSG) {
|
|
Packit |
1422b7 |
/* originalmsg must be kept outside of metadata for
|
|
Packit |
1422b7 |
* backward compatibility reasons.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
json_object_object_add(*json_p, ORIGINAL_MSG_KEY,
|
|
Packit |
1422b7 |
json_object_new_string_len(str, strLen));
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
addRuleMetadata(&npb, *json_p, endNode);
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
addUnparsedField(str, strLen, npb.parsedTo, *json_p);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(ctx->opts & LN_CTXOPT_ADD_RULE) {
|
|
Packit |
1422b7 |
es_deleteStr(npb.rule);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
#ifdef ADVANCED_STATS
|
|
Packit |
1422b7 |
if(r != 0)
|
|
Packit |
1422b7 |
es_addBuf(&npb.astats.exec_path, "[FAILED]", 8);
|
|
Packit |
1422b7 |
else if(!endNode->flags.isTerminal)
|
|
Packit |
1422b7 |
es_addBuf(&npb.astats.exec_path, "[FAILED:NON-TERMINAL]", 21);
|
|
Packit |
1422b7 |
if(npb.astats.pathlen < ADVSTATS_MAX_ENTITIES)
|
|
Packit |
1422b7 |
advstats_pathlens[npb.astats.pathlen]++;
|
|
Packit |
1422b7 |
if(npb.astats.pathlen > advstats_max_pathlen) {
|
|
Packit |
1422b7 |
advstats_max_pathlen = npb.astats.pathlen;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(npb.astats.backtracked < ADVSTATS_MAX_ENTITIES)
|
|
Packit |
1422b7 |
advstats_backtracks[npb.astats.backtracked]++;
|
|
Packit |
1422b7 |
if(npb.astats.backtracked > advstats_max_backtracked) {
|
|
Packit |
1422b7 |
advstats_max_backtracked = npb.astats.backtracked;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* parser calls */
|
|
Packit |
1422b7 |
if(npb.astats.parser_calls < ADVSTATS_MAX_ENTITIES)
|
|
Packit |
1422b7 |
advstats_parser_calls[npb.astats.parser_calls]++;
|
|
Packit |
1422b7 |
if(npb.astats.parser_calls > advstats_max_parser_calls) {
|
|
Packit |
1422b7 |
advstats_max_parser_calls = npb.astats.parser_calls;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(npb.astats.lit_parser_calls < ADVSTATS_MAX_ENTITIES)
|
|
Packit |
1422b7 |
advstats_lit_parser_calls[npb.astats.lit_parser_calls]++;
|
|
Packit |
1422b7 |
if(npb.astats.lit_parser_calls > advstats_max_lit_parser_calls) {
|
|
Packit |
1422b7 |
advstats_max_lit_parser_calls = npb.astats.lit_parser_calls;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
es_deleteStr(npb.astats.exec_path);
|
|
Packit |
1422b7 |
#endif
|
|
Packit |
1422b7 |
done: return r;
|
|
Packit |
1422b7 |
}
|