RpnFilter¶
Introduction¶
The RpnFilter is stack based state machine that is intended to filter elosd events.
Filter Syntax¶
The Filter Syntax is based on RPN (Reverse Polish Notation, used for example in some HP calculators), a very simple stack based notation style that is easy to parse while still being able to do everything the normal algebraic notation style can do.
The notation works by putting values on a stack (e.g. 1, 42) that are followed by a command (e.g. EQ). The command will consume one or more values from the stack (most consume 2 values, e.g. ADD and EQ) and place its own return value on it, which, in turn, can be consumed by commands that follow it.
A filter string of “1 1 EQ” would compare 1 with 1 (both values get removed from the stack) and insert a 1 (for true) in turn.
A filter string of “1 2 ADD 4 EQ” would first place 1 and 2 on the stack, add them (which removes 1 and 2 and places a 3 on the stack instead) place a 4 after the ADD’s 3 and then compare the two values (3 == 4), removing the values and placing a 0 (false) on the stack after it.
Semantic rules¶
The RpnFilter currently supports 4 different semantics: Numbers, Strings, Locations and Commands.
Numbers¶
Any number that would be valid as INT32, e.g. 42
Strings¶
A sequence of characters bracketed by ‘ or “, e.g. ‘foo’, ‘test123’, ‘hello world’, “foo”, “foo ‘bar’ baz”, ‘foo “bar” baz’. Note: Character escaping (like “ or ‘) is currently not supported.
Locations¶
Locations are written with a ‘.’ followed by a positive number (e.g. “.1”). These are intended for multiple purposes, but their scope is currently limited to accessing the input parameters that are given to the filter when its run. A “.1” refers to the first input parameter, a “.2” to the second and so on.
Commands¶
A sequence of [A-Z] characters that indicate the operations to run with the data on the stack (e.g. ADD, EQ).
Currently supported commands:
EQ -> equal (==)
NE -> not equal (!=)
LT -> lesser than (<)
GT -> greater than (>)
LE -> lesser or equal (<=)
GE -> greater or equal (>=)
AND -> bitwise AND (&&)
OR -> bitwise OR (||)
XOR -> bitwise XOR (^)
NOT -> bitwise NOT (~)
ADD -> addition (+)
SUB -> substraction (-)
DIV -> division (/)
MUL -> multiplication (*)
STRCMP -> string compare (strcmp())
REGEX -> string analysis (regexec())
Examples¶
Here a few basic examples with their C-Style notation to the right:
.1 1 EQ ==> (input->entry[0] == 1)
1 2 ADD 3 SUB 0 EQ ==> (((1 + 2) - 3) == 0)
.1 64 EQ .2 42 EQ AND ==> ((input->entry[0] == 64) && (input->entry[1] == 42))
.1 'foo' STRCMP ==> (strcmp(input->entry[0], "foo") == 0)
Interface¶
The following functions are defined for the RpnFilter interface
elosRpnFilterInit¶
Initializes an existing elosRpnFilter_t.
Info: Needs to be freed with elosRpnFilterDeleteMembers() after usage
Function:
elosRpnFilterResultE_t elosRpnFilterInit(
elosRpnFilter_t *filter
)
Parameters:
[in+out]
filter -> Pointer a an existing elosRpnFilter_t that will be initialized
Returns:
FILTER_RESULT_OK for success, FILTER_RESULT_ERROR on failure
elosRpnFilterNew¶
Allocates an elosRpnFilter.
Info: Needs to be freed with elosRpnFilterDelete()
after usage
Function:
elosRpnFilterResultE_t elosRpnFilterNew(
elosRpnFilter_t **filter
);
Parameters:
[in+out]
filter -> Pointer to a pointer that will contain the newly allocated elosRpnFilter after calling the function
Returns:
FILTER_RESULT_OK for success, FILTER_RESULT_ERROR on failure
elosRpnFilterDeepCopy¶
Makes a deep copy of elosRpnFilter. The copy is completely independent of the original.
Info: ‘to’ needs to be freed with elosRpnFilterDeleteMembers() after usage
Function:
elosRpnFilterResultE_t elosRpnFilterDeepCopy(
elosRpnFilter_t *to,
const elosRpnFilter_t *from
);
Parameters:
[in+out]
to -> pointer to where the elosRpnFilter_t shall be copied[in]
from -> pointer to elosRpnFilter_t that shall be copied from
Returns:
FILTER_RESULT_OK for success, FILTER_RESULT_ERROR on failure
elosRpnFilterClone¶
Duplicates elosRpnFilter into a newly allocated memory region. The copy is completely independent of the original and needs to be freed separately.
Info: ‘to’ needs to be freed with elosRpnFilterDelete()
Function:
elosRpnFilterResultE_t elosRpnFilterClone(
elosRpnFilter_t **to,
const elosRpnFilter_t *from
);
Parameters:
[in+out]
to -> pointer to a pointer which will contain the new elosRpnFilter_t[in]
from -> pointer to elosRpnFilter_t that shall be copied from
Returns:
FILTER_RESULT_OK for success, FILTER_RESULT_ERROR on failure
elosRpnFilterDeleteMembers¶
Frees memory used by elosRpnFilter members
Info:
Function:
elosRpnFilterResultE_t elosRpnFilterDeleteMembers(
elosRpnFilter_t *filter
);
Parameters:
[in+out]
filter -> Pointer to the elosRpnFilter_t to free
Returns:
FILTER_RESULT_OK for success, FILTER_RESULT_ERROR on failure
elosRpnFilterDelete¶
Frees memory used by a elosRpnFilter_t
Info:
Function:
elosRpnFilterResultE_t elosRpnFilterDelete(
elosRpnFilter_t *filter
);
Parameters:
[in+out]
filter -> Pointer to the memory area that will be freed
Returns:
FILTER_RESULT_OK for success, FILTER_RESULT_ERROR on failure
elosRpnFilterCreate¶
Create new filter to be used with elosRpnFilterExecute
Info: Needs to be freed after use with elosRpnFilterDeleteMembers()
Function:
elosRpnFilterResultE_t elosRpnFilterCreate(
elosRpnFilter_t *filter,
const elosRpnFilterParam_t *param
);
Parameters:
[in+out]
filter -> Initialized elosRpnFilter and parameters[in]
param -> Filter creation parameters, including a filter string
Returns:
FILTER_RESULT_OK for success, FILTER_RESULT_ERROR on failure
elosRpnFilterExecute¶
Runs an elosRpnFilter on the given data
Info:
Function:
elosRpnFilterResultE_t elosRpnFilterExecute(
const elosRpnFilter_t *filter,
const elosRpnFilterStack_t *input
);
Parameters:
[in]
filter -> elosRpnFilter_t created with elosRpnFilterCreate()[in]
input -> A stack with values to be used with the filter
Returns:
FILTER_RESULT_MATCH on success with a match, FILTER_RESULT_NO_MATCH on success with no match, FILTER_RESULT_ERROR on failure
elosRpnFilterExecuteResult¶
Runs an elosRpnFilter on the given data and returns the remaining values on the filter stack.
Info:
Function:
elosRpnFilterResultE_t elosRpnFilterExecuteResult(
const elosRpnFilter_t *filter,
const elosRpnFilterStack_t *input,
elosRpnFilterStack_t *output
);
Parameters:
[in]
filter -> elosRpnFilter_t created with elosRpnFilterCreate()[in]
input -> A stack with values to be used with the filter[out]
output -> A stack with values generated by the filter
Returns:
FILTER_RESULT_MATCH on success with a match, FILTER_RESULT_NO_MATCH on success with no match, FILTER_RESULT_ERROR on failure
Usage¶
Here’s a simple example that will do a string compare.
Note: There will be helper functions for stack building and handling in the future.
// Create the filter
elosRpnFilter_t filter = ELOS_RPNFILTER_INIT;
elosRpnFilterParam_t param = {.filterString = ".1 'foo' STRCMP"};
elosRpnFilterCreate(&filter, ¶m);
// Execute the filter, for which we need to create a stack of values that is passed into the rpnfilter
elosRpnFilterResultE_t result;
size_t stackSize = 1;
size_t stackMemSize = sizeof(elosRpnFilterStack_t) + (sizeof(elosRpnFilterStackEntry_t) * stackSize);
elosRpnFilterStack_t *input = safuAllocMem(NULL, stackMemSize);
input->count = stackSize;
input->entry[0].type = FILTER_VALUE_STRING;
input->entry[0].data = "foo";
result = elosRpnFilterExecute(&filter, input);
if (result == FILTER_RESULT_MATCH) {
printf("match!");
} else {
printf("no match!");
}
// Free the resources used by the filter object
elosRpnFilterDeleteMembers(&filter);