diff --git a/src/parser.c b/src/parser.c index 32289a7..bb84f0a 100644 --- a/src/parser.c +++ b/src/parser.c @@ -25,6 +25,7 @@ #include "config.h" #include #include +#include #include #include #include @@ -2406,12 +2407,17 @@ static int parseNameValue(npb_t *const npb, size_t *const __restrict__ offs, struct json_object *const __restrict__ valroot, - const char sep, const char ass) + const char sep, const char ass, const bool ignore_ws) { int r = LN_WRONGPARSER; size_t i = *offs; char *name = NULL; + /* Ignore whitespaces if option enabled */ + if( ignore_ws ) + while( isspace(npb->str[i]) ) + i++; + const size_t iName = i; /* If the assignator character is specified, search for it @@ -2422,9 +2428,18 @@ parseNameValue(npb_t *const npb, if(i == iName || ((ass != 0) ? (npb->str[i] != ass) : (npb->str[i] != '='))) goto done; /* no name at all! */ - const size_t lenName = i - iName; + size_t lenName = i - iName; + /* Sub-routine to trim whitespaces if option is enabled */ + if( ignore_ws ) + while( isspace(npb->str[(iName+lenName)-1]) ) + lenName--; + ++i; /* skip assignator */ + if( ignore_ws ) + while( isspace(npb->str[i]) ) + i++; + char quoting = npb->str[i]; if(i < npb->strLen && (quoting == '"' || quoting == '\'')) i++; @@ -2489,8 +2504,10 @@ parseNameValue(npb_t *const npb, else if(quoting) goto done; - - const size_t lenVal = i - iVal - (quoting ? 1 : 0); + size_t lenVal = i - iVal - (quoting ? 1 : 0); + if( ignore_ws && !quoting ) + while( isspace(npb->str[(iVal+lenVal)-1]) ) + lenVal--; /* parsing OK */ *offs = i; @@ -2572,6 +2589,7 @@ PARSER_Parse(CEESyslog) struct data_NameValue { char sep; /* separator (between key/value couples) */ char ass; /* assignator (between key and value) */ + bool ignore_whitespaces; /* ignore whitespace(s) at beginning and end of key and value */ }; /** @@ -2591,13 +2609,15 @@ PARSER_Parse(NameValue) struct data_NameValue *const data = (struct data_NameValue*) pdata; const char sep = data->sep; const char ass = data->ass; + const char ignore_ws = data->ignore_whitespaces; LN_DBGPRINTF(npb->ctx, "in parse_NameValue, separator is '%c'(0x%02x) assignator is '%c'(0x%02x)" - ,sep, sep, ass, ass); + "ignore_whitespaces is '%s'(%d)" + ,sep, sep, ass, ass, (ignore_ws?"true":"false"), ignore_ws); /* stage one */ while(i < npb->strLen) { - if (parseNameValue(npb, &i, NULL, sep, ass) == 0 ) { + if (parseNameValue(npb, &i, NULL, sep, ass, ignore_ws) == 0 ) { // Check if there is at least one time the separator after value if( i < npb->strLen && !(sep == 0 ? (isspace(npb->str[i])) : (npb->str[i] == sep)) ) break; @@ -2619,7 +2639,7 @@ PARSER_Parse(NameValue) i = *offs; CHKN(*value = json_object_new_object()); while(i < npb->strLen) { - if (parseNameValue(npb, &i, *value, sep, ass) == 0 ) { + if (parseNameValue(npb, &i, *value, sep, ass, ignore_ws) == 0 ) { // Check if there is at least one time the separator after value if( i < npb->strLen && !(sep == 0 ? (isspace(npb->str[i])) : (npb->str[i] == sep)) ) break; @@ -2642,6 +2662,7 @@ PARSER_Construct(NameValue) LN_DBGPRINTF(ctx, "in parser_construct NameValue"); struct data_NameValue *data = (struct data_NameValue*) calloc(1, sizeof(struct data_NameValue)); struct json_object *obj; + json_bool bool_obj; const char *str; if(json_object_object_get_ex(json, "extradata", &obj) != 0) { @@ -2683,6 +2704,19 @@ PARSER_Construct(NameValue) } } + if(json_object_object_get_ex(json, "ignore_whitespaces", &obj) != 0) { + LN_DBGPRINTF(ctx, "found 'ignore_whitespaces' in fields"); + if(json_object_is_type(obj, json_type_boolean) == 1) { + bool_obj = json_object_get_boolean(obj); + data->ignore_whitespaces = (bool)bool_obj; + } + else { + ln_errprintf(ctx, 0, "name-value-list's 'ignore_whitespaces' field should be boolean"); + r = LN_BADCONFIG; + goto done; + } + } + *pdata = data; done: if(r != 0) diff --git a/tests/field_name_value_whitespace.sh b/tests/field_name_value_whitespace.sh new file mode 100755 index 0000000..ece7102 --- /dev/null +++ b/tests/field_name_value_whitespace.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# added 2022-03-28 by @KGuillemot +# This file is part of the liblognorm project, released under ASL 2.0 +. $srcdir/exec.sh + +test_def $0 "name/value parser" +add_rule 'version=2' +add_rule 'rule=:%{"name":"f", "type":"name-value-list", "separator":",", "assignator":":", "ignore_whitespaces":true}%' + +execute 'name:value' +assert_output_json_eq '{ "f": { "name": "value" } }' + +execute 'name1:value1,name2:value2,name3:value3' +assert_output_json_eq '{ "f": { "name1": "value1", "name2": "value2", "name3": "value3" } }' + +execute ' name1: abcd, name2 : value2 ,name3 :value3 ' +assert_output_json_eq '{ "f": { "name1": "abcd", "name2": "value2", "name3": "value3" } }' + +# Check old behavior (default) +reset_rules +add_rule 'version=2' +add_rule 'rule=:%{"name":"f", "type":"name-value-list", "separator":",", "assignator":":"}%' + +execute ' name1: abcd, name2 : value2 ,name3 :value3 ' +assert_output_json_eq '{ "f": { " name1": " abcd", " name2 ": " value2 ", "name3 ": "value3 " } }' + +cleanup_tmp_files +