durable_rules 0.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/Rakefile +34 -0
- data/deps/hiredis/COPYING +29 -0
- data/deps/hiredis/Makefile +148 -0
- data/deps/hiredis/async.c +622 -0
- data/deps/hiredis/async.h +125 -0
- data/deps/hiredis/dict.c +338 -0
- data/deps/hiredis/dict.h +126 -0
- data/deps/hiredis/fmacros.h +16 -0
- data/deps/hiredis/hiredis.c +1285 -0
- data/deps/hiredis/hiredis.h +210 -0
- data/deps/hiredis/net.c +299 -0
- data/deps/hiredis/net.h +47 -0
- data/deps/hiredis/sds.c +882 -0
- data/deps/hiredis/sds.h +100 -0
- data/deps/hiredis/test.c +654 -0
- data/deps/hiredis/zmalloc.h +13 -0
- data/librb/durable.rb +549 -0
- data/librb/engine.rb +1015 -0
- data/librb/interface.rb +64 -0
- data/src/rules/Makefile +55 -0
- data/src/rules/events.c +1848 -0
- data/src/rules/json.c +423 -0
- data/src/rules/json.h +24 -0
- data/src/rules/net.c +2559 -0
- data/src/rules/net.h +141 -0
- data/src/rules/rete.c +1726 -0
- data/src/rules/rete.h +133 -0
- data/src/rules/rules.h +171 -0
- data/src/rules/state.c +412 -0
- data/src/rules/state.h +57 -0
- data/src/rulesrb/extconf.rb +37 -0
- data/src/rulesrb/rules.c +644 -0
- metadata +120 -0
data/src/rules/net.h
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
|
2
|
+
#include "rete.h"
|
3
|
+
#ifdef _WIN32
|
4
|
+
#include "../../deps/hiredis_win/hiredis.h"
|
5
|
+
#include "../../deps/hiredis_win/sds.h"
|
6
|
+
#else
|
7
|
+
#include "../../deps/hiredis/hiredis.h"
|
8
|
+
#include "../../deps/hiredis/sds.h"
|
9
|
+
#endif
|
10
|
+
|
11
|
+
#define HASH_LENGTH 40
|
12
|
+
#define MAX_MESSAGE_BATCH 64
|
13
|
+
|
14
|
+
#define ACTION_ASSERT_FACT 1
|
15
|
+
#define ACTION_ASSERT_EVENT 2
|
16
|
+
#define ACTION_RETRACT_FACT 3
|
17
|
+
#define ACTION_RETRACT_EVENT 4
|
18
|
+
#define ACTION_ADD_FACT 5
|
19
|
+
#define ACTION_ADD_EVENT 6
|
20
|
+
#define ACTION_REMOVE_FACT 7
|
21
|
+
#define ACTION_REMOVE_EVENT 8
|
22
|
+
|
23
|
+
typedef char functionHash[HASH_LENGTH + 1];
|
24
|
+
|
25
|
+
typedef struct binding {
|
26
|
+
redisContext *reContext;
|
27
|
+
functionHash evalMessageHash;
|
28
|
+
functionHash addMessageHash;
|
29
|
+
functionHash peekActionHash;
|
30
|
+
functionHash removeActionHash;
|
31
|
+
functionHash partitionHash;
|
32
|
+
functionHash timersHash;
|
33
|
+
char *sessionHashset;
|
34
|
+
char *factsHashset;
|
35
|
+
char *eventsHashset;
|
36
|
+
char *timersSortedset;
|
37
|
+
} binding;
|
38
|
+
|
39
|
+
typedef struct bindingsList {
|
40
|
+
binding *bindings;
|
41
|
+
unsigned int bindingsLength;
|
42
|
+
unsigned int lastBinding;
|
43
|
+
unsigned int lastTimersBinding;
|
44
|
+
} bindingsList;
|
45
|
+
|
46
|
+
unsigned int getBindingIndex(ruleset *tree,
|
47
|
+
unsigned int sidHash,
|
48
|
+
unsigned int *bindingIndex);
|
49
|
+
|
50
|
+
unsigned int formatEvalMessage(void *rulesBinding,
|
51
|
+
char *sid,
|
52
|
+
char *mid,
|
53
|
+
char *message,
|
54
|
+
jsonProperty *allProperties,
|
55
|
+
unsigned int propertiesLength,
|
56
|
+
unsigned char actionType,
|
57
|
+
char **keys,
|
58
|
+
unsigned int keysLength,
|
59
|
+
char **command);
|
60
|
+
|
61
|
+
unsigned int formatStoreMessage(void *rulesBinding,
|
62
|
+
char *sid,
|
63
|
+
char *message,
|
64
|
+
jsonProperty *allProperties,
|
65
|
+
unsigned int propertiesLength,
|
66
|
+
unsigned char storeFact,
|
67
|
+
char **keys,
|
68
|
+
unsigned int keysLength,
|
69
|
+
char **command);
|
70
|
+
|
71
|
+
unsigned int formatStoreSession(void *rulesBinding,
|
72
|
+
char *sid,
|
73
|
+
char *state,
|
74
|
+
unsigned char tryExists,
|
75
|
+
char **command);
|
76
|
+
|
77
|
+
unsigned int formatStoreSessionFact(void *rulesBinding,
|
78
|
+
char *sid,
|
79
|
+
char *message,
|
80
|
+
unsigned char tryExists,
|
81
|
+
char **command);
|
82
|
+
|
83
|
+
unsigned int formatRemoveTimer(void *rulesBinding,
|
84
|
+
char *timer,
|
85
|
+
char **command);
|
86
|
+
|
87
|
+
unsigned int formatRemoveAction(void *rulesBinding,
|
88
|
+
char *sid,
|
89
|
+
char **command);
|
90
|
+
|
91
|
+
unsigned int formatRemoveMessage(void *rulesBinding,
|
92
|
+
char *sid,
|
93
|
+
char *mid,
|
94
|
+
unsigned char removeFact,
|
95
|
+
char **command);
|
96
|
+
|
97
|
+
unsigned int formatPeekAction(void *rulesBinding,
|
98
|
+
char *sid,
|
99
|
+
char **command);
|
100
|
+
|
101
|
+
unsigned int executeBatch(void *rulesBinding,
|
102
|
+
char **commands,
|
103
|
+
unsigned int commandCount);
|
104
|
+
|
105
|
+
unsigned int executeBatchWithReply(void *rulesBinding,
|
106
|
+
unsigned int expectedReplies,
|
107
|
+
char **commands,
|
108
|
+
unsigned int commandCount,
|
109
|
+
redisReply **lastReply);
|
110
|
+
|
111
|
+
unsigned int startNonBlockingBatch(void *rulesBinding,
|
112
|
+
char **commands,
|
113
|
+
unsigned int commandCount,
|
114
|
+
unsigned int *replyCount);
|
115
|
+
|
116
|
+
unsigned int completeNonBlockingBatch(void *rulesBinding,
|
117
|
+
unsigned int replyCount);
|
118
|
+
|
119
|
+
unsigned int removeMessage(void *rulesBinding,
|
120
|
+
char *sid,
|
121
|
+
char *mid);
|
122
|
+
|
123
|
+
unsigned int peekAction(ruleset *tree,
|
124
|
+
void **bindingContext,
|
125
|
+
redisReply **reply);
|
126
|
+
|
127
|
+
unsigned int peekTimers(ruleset *tree,
|
128
|
+
void **bindingContext,
|
129
|
+
redisReply **reply);
|
130
|
+
|
131
|
+
unsigned int registerTimer(void *rulesBinding,
|
132
|
+
unsigned int duration,
|
133
|
+
char *timer);
|
134
|
+
|
135
|
+
unsigned int deleteBindingsList(ruleset *tree);
|
136
|
+
|
137
|
+
unsigned int getSession(void *rulesBinding,
|
138
|
+
char *sid,
|
139
|
+
char **state);
|
140
|
+
|
141
|
+
|
data/src/rules/rete.c
ADDED
@@ -0,0 +1,1726 @@
|
|
1
|
+
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <stdlib.h>
|
4
|
+
#include <time.h>
|
5
|
+
#include <string.h>
|
6
|
+
#include "rules.h"
|
7
|
+
#include "net.h"
|
8
|
+
#include "json.h"
|
9
|
+
|
10
|
+
#define HASH_ALL 193486302 // all
|
11
|
+
#define HASH_ANY 193486381 // any
|
12
|
+
#define HASH_PRI 193502832 // pri
|
13
|
+
#define HASH_COUNT 255678574 // count
|
14
|
+
#define HASH_SPAN 2090731639 // span
|
15
|
+
#define HASH_CAP 193488121 // cap
|
16
|
+
#define HASH_BY 5863264 // by
|
17
|
+
#define HASH_LT 193419881 // $lt
|
18
|
+
#define HASH_LTE 2087888878 // $lte
|
19
|
+
#define HASH_GT 193419716 // $gt
|
20
|
+
#define HASH_GTE 2087883433 // $gte
|
21
|
+
#define HASH_EQ 193419647 // $eq
|
22
|
+
#define HASH_NEQ 2087890573 // $neq
|
23
|
+
#define HASH_EX 193419654 // $ex
|
24
|
+
#define HASH_NEX 2087890580 // $nex
|
25
|
+
#define HASH_OR 193419978 // $or
|
26
|
+
#define HASH_AND 2087876700 // $and
|
27
|
+
#define HASH_S 5861212 // $s
|
28
|
+
#define HASH_NAME 2090536006 // name
|
29
|
+
#define HASH_ADD 2087876370 // $add
|
30
|
+
#define HASH_SUB 2087896531 // $sub
|
31
|
+
#define HASH_MUL 2087890007 // $mul
|
32
|
+
#define HASH_DIV 2087879820 // $div
|
33
|
+
#define HASH_L 5861205 // $l
|
34
|
+
#define HASH_R 5861211 //$r
|
35
|
+
|
36
|
+
typedef struct path {
|
37
|
+
unsigned char operator;
|
38
|
+
struct path **parents;
|
39
|
+
unsigned int parentsLength;
|
40
|
+
unsigned short count;
|
41
|
+
expression *expressions;
|
42
|
+
unsigned int expressionsLength;
|
43
|
+
} path;
|
44
|
+
|
45
|
+
typedef struct any {
|
46
|
+
struct all **nodes;
|
47
|
+
unsigned int nodesLength;
|
48
|
+
} any;
|
49
|
+
|
50
|
+
typedef struct all {
|
51
|
+
unsigned short count;
|
52
|
+
unsigned int *expressions;
|
53
|
+
unsigned short expressionsLength;
|
54
|
+
} all;
|
55
|
+
|
56
|
+
static unsigned int validateAlgebra(char *rule);
|
57
|
+
|
58
|
+
static unsigned int createBeta(ruleset *tree,
|
59
|
+
char *rule,
|
60
|
+
unsigned char operator,
|
61
|
+
unsigned int nextOffset,
|
62
|
+
path *nextPath,
|
63
|
+
path **outPath);
|
64
|
+
|
65
|
+
static unsigned int storeString(ruleset *tree,
|
66
|
+
char *newString,
|
67
|
+
unsigned int *stringOffset,
|
68
|
+
unsigned int length) {
|
69
|
+
|
70
|
+
unsigned int newStringLength = length + 1;
|
71
|
+
if (!tree->stringPool) {
|
72
|
+
tree->stringPool = malloc(newStringLength * sizeof(char));
|
73
|
+
if (!tree->stringPool) {
|
74
|
+
return ERR_OUT_OF_MEMORY;
|
75
|
+
}
|
76
|
+
|
77
|
+
*stringOffset = 0;
|
78
|
+
tree->stringPoolLength = newStringLength;
|
79
|
+
} else {
|
80
|
+
tree->stringPool = realloc(tree->stringPool, (tree->stringPoolLength + newStringLength) * sizeof(char));
|
81
|
+
if (!tree->stringPool) {
|
82
|
+
return ERR_OUT_OF_MEMORY;
|
83
|
+
}
|
84
|
+
|
85
|
+
*stringOffset = tree->stringPoolLength;
|
86
|
+
tree->stringPoolLength = tree->stringPoolLength + newStringLength;
|
87
|
+
}
|
88
|
+
|
89
|
+
strncpy(tree->stringPool + *stringOffset, newString, length);
|
90
|
+
tree->stringPool[tree->stringPoolLength - 1] = '\0';
|
91
|
+
return RULES_OK;
|
92
|
+
}
|
93
|
+
|
94
|
+
static unsigned int storeExpression(ruleset *tree,
|
95
|
+
expression **newExpression,
|
96
|
+
unsigned int *expressionOffset) {
|
97
|
+
|
98
|
+
if (!tree->expressionPool) {
|
99
|
+
tree->expressionPool = malloc(sizeof(expression));
|
100
|
+
if (!tree->expressionPool) {
|
101
|
+
return ERR_OUT_OF_MEMORY;
|
102
|
+
}
|
103
|
+
|
104
|
+
*expressionOffset = 0;
|
105
|
+
*newExpression = &tree->expressionPool[0];
|
106
|
+
tree->expressionOffset = 1;
|
107
|
+
} else {
|
108
|
+
tree->expressionPool = realloc(tree->expressionPool, (tree->expressionOffset + 1) * sizeof(expression));
|
109
|
+
if (!tree->expressionPool) {
|
110
|
+
return ERR_OUT_OF_MEMORY;
|
111
|
+
}
|
112
|
+
|
113
|
+
*expressionOffset = tree->expressionOffset;
|
114
|
+
*newExpression = &tree->expressionPool[tree->expressionOffset];
|
115
|
+
tree->expressionOffset = tree->expressionOffset + 1;
|
116
|
+
}
|
117
|
+
|
118
|
+
return RULES_OK;
|
119
|
+
}
|
120
|
+
|
121
|
+
static unsigned int storeIdiom(ruleset *tree,
|
122
|
+
idiom **newIdiom,
|
123
|
+
unsigned int *idiomOffset) {
|
124
|
+
|
125
|
+
if (!tree->idiomPool) {
|
126
|
+
tree->idiomPool = malloc(sizeof(idiom));
|
127
|
+
if (!tree->idiomPool) {
|
128
|
+
return ERR_OUT_OF_MEMORY;
|
129
|
+
}
|
130
|
+
|
131
|
+
*idiomOffset = 0;
|
132
|
+
*newIdiom = &tree->idiomPool[0];
|
133
|
+
tree->idiomOffset = 1;
|
134
|
+
} else {
|
135
|
+
tree->idiomPool = realloc(tree->idiomPool, (tree->idiomOffset + 1) * sizeof(idiom));
|
136
|
+
if (!tree->idiomPool) {
|
137
|
+
return ERR_OUT_OF_MEMORY;
|
138
|
+
}
|
139
|
+
|
140
|
+
*idiomOffset = tree->idiomOffset;
|
141
|
+
*newIdiom = &tree->idiomPool[tree->idiomOffset];
|
142
|
+
tree->idiomOffset = tree->idiomOffset + 1;
|
143
|
+
}
|
144
|
+
|
145
|
+
return RULES_OK;
|
146
|
+
}
|
147
|
+
|
148
|
+
static unsigned int appendTerm(expression *expr, unsigned int nodeOffset) {
|
149
|
+
if (expr->termsLength == 0) {
|
150
|
+
expr->termsLength = 1;
|
151
|
+
expr->t.termsPointer = malloc(sizeof(unsigned int));
|
152
|
+
if (!expr->t.termsPointer) {
|
153
|
+
return ERR_OUT_OF_MEMORY;
|
154
|
+
}
|
155
|
+
|
156
|
+
expr->t.termsPointer[0] = nodeOffset;
|
157
|
+
}
|
158
|
+
else {
|
159
|
+
expr->termsLength = expr->termsLength + 1;
|
160
|
+
expr->t.termsPointer = realloc(expr->t.termsPointer, expr->termsLength * sizeof(unsigned int));
|
161
|
+
if (!expr->t.termsPointer) {
|
162
|
+
return ERR_OUT_OF_MEMORY;
|
163
|
+
}
|
164
|
+
|
165
|
+
expr->t.termsPointer[expr->termsLength - 1] = nodeOffset;
|
166
|
+
}
|
167
|
+
|
168
|
+
return RULES_OK;
|
169
|
+
}
|
170
|
+
|
171
|
+
static unsigned int storeJoin(ruleset *tree,
|
172
|
+
join **newJoin,
|
173
|
+
unsigned int *joinOffset) {
|
174
|
+
|
175
|
+
if (!tree->joinPool) {
|
176
|
+
tree->joinPool = malloc(sizeof(join));
|
177
|
+
if (!tree->joinPool) {
|
178
|
+
return ERR_OUT_OF_MEMORY;
|
179
|
+
}
|
180
|
+
|
181
|
+
*joinOffset = 0;
|
182
|
+
*newJoin = &tree->joinPool[0];
|
183
|
+
tree->joinOffset = 1;
|
184
|
+
} else {
|
185
|
+
tree->joinPool = realloc(tree->joinPool, (tree->joinOffset + 1) * sizeof(join));
|
186
|
+
if (!tree->joinPool) {
|
187
|
+
return ERR_OUT_OF_MEMORY;
|
188
|
+
}
|
189
|
+
|
190
|
+
*joinOffset = tree->joinOffset;
|
191
|
+
*newJoin = &tree->joinPool[tree->joinOffset];
|
192
|
+
tree->joinOffset = tree->joinOffset + 1;
|
193
|
+
}
|
194
|
+
|
195
|
+
return RULES_OK;
|
196
|
+
}
|
197
|
+
|
198
|
+
static unsigned int storeNode(ruleset *tree,
|
199
|
+
node **newNode,
|
200
|
+
unsigned int *nodeOffset) {
|
201
|
+
|
202
|
+
if (!tree->nodePool) {
|
203
|
+
tree->nodePool = malloc(sizeof(node));
|
204
|
+
if (!tree->nodePool) {
|
205
|
+
return ERR_OUT_OF_MEMORY;
|
206
|
+
}
|
207
|
+
|
208
|
+
*nodeOffset = 0;
|
209
|
+
*newNode = &tree->nodePool[0];
|
210
|
+
tree->nodeOffset = 1;
|
211
|
+
} else {
|
212
|
+
tree->nodePool = realloc(tree->nodePool, (tree->nodeOffset + 1) * sizeof(node));
|
213
|
+
if (!tree->nodePool) {
|
214
|
+
return ERR_OUT_OF_MEMORY;
|
215
|
+
}
|
216
|
+
|
217
|
+
*nodeOffset = tree->nodeOffset;
|
218
|
+
*newNode = &tree->nodePool[tree->nodeOffset];
|
219
|
+
tree->nodeOffset = tree->nodeOffset + 1;
|
220
|
+
}
|
221
|
+
|
222
|
+
return RULES_OK;
|
223
|
+
}
|
224
|
+
|
225
|
+
static unsigned int storeAlpha(ruleset *tree,
|
226
|
+
node **newNode,
|
227
|
+
unsigned int *nodeOffset) {
|
228
|
+
|
229
|
+
unsigned int result = storeNode(tree, newNode, nodeOffset);
|
230
|
+
if (result != RULES_OK) {
|
231
|
+
return result;
|
232
|
+
}
|
233
|
+
|
234
|
+
(*newNode)->value.a.nextListOffset = 0;
|
235
|
+
(*newNode)->value.a.betaListOffset = 0;
|
236
|
+
(*newNode)->value.a.nextOffset = 0;
|
237
|
+
return RULES_OK;
|
238
|
+
}
|
239
|
+
|
240
|
+
static unsigned int allocateNext(ruleset *tree,
|
241
|
+
unsigned int length,
|
242
|
+
unsigned int *offset) {
|
243
|
+
|
244
|
+
if (!tree->nextPool) {
|
245
|
+
tree->nextPool = malloc((length + 1) * sizeof(unsigned int));
|
246
|
+
if (!tree->nextPool) {
|
247
|
+
return ERR_OUT_OF_MEMORY;
|
248
|
+
}
|
249
|
+
|
250
|
+
memset(tree->nextPool, 0, (length + 1) * sizeof(unsigned int));
|
251
|
+
*offset = 1;
|
252
|
+
tree->nextOffset = length + 1;
|
253
|
+
} else {
|
254
|
+
tree->nextPool = realloc(tree->nextPool, (tree->nextOffset + length) * sizeof(unsigned int));
|
255
|
+
if (!tree->nextPool) {
|
256
|
+
return ERR_OUT_OF_MEMORY;
|
257
|
+
}
|
258
|
+
|
259
|
+
memset(&tree->nextPool[tree->nextOffset], 0, length * sizeof(unsigned int));
|
260
|
+
*offset = tree->nextOffset;
|
261
|
+
tree->nextOffset = tree->nextOffset + length;
|
262
|
+
}
|
263
|
+
|
264
|
+
return RULES_OK;
|
265
|
+
}
|
266
|
+
|
267
|
+
|
268
|
+
static unsigned int ensureNextHashset(ruleset *tree, node *newNode) {
|
269
|
+
if (!newNode->value.a.nextOffset) {
|
270
|
+
return allocateNext(tree, NEXT_BUCKET_LENGTH, &newNode->value.a.nextOffset);
|
271
|
+
}
|
272
|
+
|
273
|
+
return RULES_OK;
|
274
|
+
}
|
275
|
+
|
276
|
+
static unsigned int ensureNextList(ruleset *tree, node *newNode) {
|
277
|
+
if (!newNode->value.a.nextListOffset) {
|
278
|
+
return allocateNext(tree, NEXT_LIST_LENGTH, &newNode->value.a.nextListOffset);
|
279
|
+
}
|
280
|
+
|
281
|
+
return RULES_OK;
|
282
|
+
}
|
283
|
+
|
284
|
+
static unsigned int ensureBetaList(ruleset *tree, node *newNode) {
|
285
|
+
if (!newNode->value.a.betaListOffset) {
|
286
|
+
return allocateNext(tree, BETA_LIST_LENGTH, &newNode->value.a.betaListOffset);
|
287
|
+
}
|
288
|
+
|
289
|
+
return RULES_OK;
|
290
|
+
}
|
291
|
+
|
292
|
+
static void copyValue(ruleset *tree,
|
293
|
+
jsonValue *right,
|
294
|
+
char *first,
|
295
|
+
char *last,
|
296
|
+
unsigned int idiomOffset,
|
297
|
+
reference *ref,
|
298
|
+
unsigned char type) {
|
299
|
+
right->type = type;
|
300
|
+
unsigned int leftLength;
|
301
|
+
char temp;
|
302
|
+
switch(type) {
|
303
|
+
case JSON_EVENT_PROPERTY:
|
304
|
+
case JSON_STATE_PROPERTY:
|
305
|
+
right->value.property.hash = ref->hash;
|
306
|
+
right->value.property.nameOffset = ref->nameOffset;
|
307
|
+
right->value.property.idOffset = ref->idOffset;
|
308
|
+
break;
|
309
|
+
case JSON_STATE_IDIOM:
|
310
|
+
case JSON_EVENT_IDIOM:
|
311
|
+
right->value.idiomOffset = idiomOffset;
|
312
|
+
break;
|
313
|
+
case JSON_STRING:
|
314
|
+
leftLength = last - first;
|
315
|
+
storeString(tree, first, &right->value.stringOffset, leftLength);
|
316
|
+
break;
|
317
|
+
case JSON_INT:
|
318
|
+
temp = last[1];
|
319
|
+
last[1] = '\0';
|
320
|
+
right->value.i = atol(first);
|
321
|
+
last[1] = temp;
|
322
|
+
break;
|
323
|
+
case JSON_DOUBLE:
|
324
|
+
temp = last[1];
|
325
|
+
last[1] = '\0';
|
326
|
+
right->value.d = atof(first);
|
327
|
+
last[1] = temp;
|
328
|
+
break;
|
329
|
+
case JSON_BOOL:
|
330
|
+
leftLength = last - first + 1;
|
331
|
+
unsigned char leftb = 1;
|
332
|
+
if (leftLength == 5 && strncmp("false", first, 5) == 0) {
|
333
|
+
leftb = 0;
|
334
|
+
}
|
335
|
+
right->value.b = leftb;
|
336
|
+
break;
|
337
|
+
}
|
338
|
+
}
|
339
|
+
|
340
|
+
static unsigned char compareValue(ruleset *tree,
|
341
|
+
jsonValue *right,
|
342
|
+
char *first,
|
343
|
+
char *last,
|
344
|
+
reference *ref,
|
345
|
+
unsigned char type) {
|
346
|
+
|
347
|
+
if (right->type != type) {
|
348
|
+
return 0;
|
349
|
+
}
|
350
|
+
|
351
|
+
unsigned int leftLength;
|
352
|
+
char temp;
|
353
|
+
switch(type) {
|
354
|
+
case JSON_EVENT_PROPERTY:
|
355
|
+
case JSON_STATE_PROPERTY:
|
356
|
+
if (right->value.property.hash == ref->hash &&
|
357
|
+
right->value.property.nameOffset == ref->nameOffset &&
|
358
|
+
right->value.property.idOffset == ref->idOffset)
|
359
|
+
return 1;
|
360
|
+
|
361
|
+
return 0;
|
362
|
+
case JSON_STATE_IDIOM:
|
363
|
+
case JSON_EVENT_IDIOM:
|
364
|
+
return 0;
|
365
|
+
case JSON_STRING:
|
366
|
+
leftLength = last - first;
|
367
|
+
char *rightString = &tree->stringPool[right->value.stringOffset];
|
368
|
+
unsigned int rightLength = strlen(rightString);
|
369
|
+
return (leftLength == rightLength ? !strncmp(rightString, first, rightLength): 0);
|
370
|
+
case JSON_INT:
|
371
|
+
temp = last[1];
|
372
|
+
last[1] = '\0';
|
373
|
+
long lefti = atol(first);
|
374
|
+
last[1] = temp;
|
375
|
+
return (right->value.i == lefti);
|
376
|
+
case JSON_DOUBLE:
|
377
|
+
temp = last[1];
|
378
|
+
last[1] = '\0';
|
379
|
+
double leftd = atof(first);
|
380
|
+
last[1] = temp;
|
381
|
+
return (right->value.d == leftd);
|
382
|
+
case JSON_BOOL:
|
383
|
+
leftLength = last - first + 1;
|
384
|
+
unsigned char leftb = 1;
|
385
|
+
if (leftLength == 5 && strncmp("false", first, 5) == 0) {
|
386
|
+
leftb = 0;
|
387
|
+
}
|
388
|
+
return (right->value.b == leftb);
|
389
|
+
}
|
390
|
+
|
391
|
+
return 0;
|
392
|
+
}
|
393
|
+
|
394
|
+
static unsigned int validateSetting(unsigned int settingHash, char *rule, unsigned char targetType) {
|
395
|
+
char *first;
|
396
|
+
char *last;
|
397
|
+
unsigned int hash;
|
398
|
+
unsigned char type;
|
399
|
+
unsigned int result = readNextName(rule, &first, &last, &hash);
|
400
|
+
while (result == PARSE_OK) {
|
401
|
+
if (hash == settingHash) {
|
402
|
+
result = readNextValue(last, &first, &last, &type);
|
403
|
+
if (type != targetType) {
|
404
|
+
return ERR_UNEXPECTED_TYPE;
|
405
|
+
}
|
406
|
+
|
407
|
+
return PARSE_OK;
|
408
|
+
}
|
409
|
+
|
410
|
+
result = readNextName(last, &first, &last, &hash);
|
411
|
+
}
|
412
|
+
|
413
|
+
return ERR_SETTING_NOT_FOUND;
|
414
|
+
}
|
415
|
+
|
416
|
+
static unsigned int validateReference(char *rule, unsigned char *referenceType) {
|
417
|
+
char *first;
|
418
|
+
char *last;
|
419
|
+
unsigned char type;
|
420
|
+
unsigned int hash;
|
421
|
+
unsigned int result;
|
422
|
+
|
423
|
+
result = readNextName(rule, &first, &last, &hash);
|
424
|
+
if (result != PARSE_OK) {
|
425
|
+
return result;
|
426
|
+
}
|
427
|
+
|
428
|
+
if (hash != HASH_S) {
|
429
|
+
*referenceType = JSON_EVENT_PROPERTY;
|
430
|
+
result = readNextString(last, &first, &last, &hash);
|
431
|
+
if (result != PARSE_OK) {
|
432
|
+
return result;
|
433
|
+
}
|
434
|
+
} else {
|
435
|
+
*referenceType = JSON_STATE_PROPERTY;
|
436
|
+
if (readNextString(last, &first, &last, &hash) != PARSE_OK) {
|
437
|
+
result = readNextValue(last, &first, &last, &type);
|
438
|
+
if (result != PARSE_OK) {
|
439
|
+
return result;
|
440
|
+
}
|
441
|
+
|
442
|
+
unsigned int result = readNextName(first, &first, &last, &hash);
|
443
|
+
while (result == PARSE_OK) {
|
444
|
+
switch (hash) {
|
445
|
+
case HASH_NAME:
|
446
|
+
result = readNextString(last, &first, &last, &hash);
|
447
|
+
break;
|
448
|
+
case HASH_ID:
|
449
|
+
result = readNextValue(last, &first, &last, &type);
|
450
|
+
break;
|
451
|
+
default:
|
452
|
+
result = readNextValue(last, &first, &last, &type);
|
453
|
+
break;
|
454
|
+
}
|
455
|
+
|
456
|
+
if (result != PARSE_OK) {
|
457
|
+
return result;
|
458
|
+
}
|
459
|
+
result = readNextName(last, &first, &last, &hash);
|
460
|
+
}
|
461
|
+
}
|
462
|
+
}
|
463
|
+
|
464
|
+
return PARSE_OK;
|
465
|
+
}
|
466
|
+
|
467
|
+
static unsigned int validateIdiom(char *rule, unsigned char *idiomType) {
|
468
|
+
char *first;
|
469
|
+
char *last;
|
470
|
+
unsigned char type;
|
471
|
+
unsigned int hash;
|
472
|
+
unsigned int result;
|
473
|
+
|
474
|
+
result = readNextName(rule, &first, &last, &hash);
|
475
|
+
if (result != PARSE_OK) {
|
476
|
+
return result;
|
477
|
+
}
|
478
|
+
|
479
|
+
if (hash != HASH_ADD && hash != HASH_SUB &&
|
480
|
+
hash != HASH_MUL && hash != HASH_DIV) {
|
481
|
+
return validateReference(rule, idiomType);
|
482
|
+
} else {
|
483
|
+
result = readNextValue(last, &first, &last, &type);
|
484
|
+
if (result != PARSE_OK) {
|
485
|
+
return result;
|
486
|
+
}
|
487
|
+
|
488
|
+
*idiomType = 0;
|
489
|
+
result = readNextName(first, &first, &last, &hash);
|
490
|
+
while (result == PARSE_OK) {
|
491
|
+
unsigned char newIdiomType = 0;
|
492
|
+
result = readNextValue(last, &first, &last, &type);
|
493
|
+
if (result != PARSE_OK) {
|
494
|
+
return result;
|
495
|
+
}
|
496
|
+
|
497
|
+
if (type == JSON_OBJECT) {
|
498
|
+
result = validateIdiom(first, &newIdiomType);
|
499
|
+
if (result != PARSE_OK) {
|
500
|
+
return result;
|
501
|
+
}
|
502
|
+
}
|
503
|
+
|
504
|
+
if (newIdiomType == JSON_EVENT_PROPERTY || newIdiomType == JSON_EVENT_IDIOM) {
|
505
|
+
if (*idiomType == JSON_STATE_PROPERTY || *idiomType == JSON_STATE_IDIOM) {
|
506
|
+
return ERR_UNEXPECTED_TYPE;
|
507
|
+
}
|
508
|
+
|
509
|
+
*idiomType = JSON_EVENT_IDIOM;
|
510
|
+
}
|
511
|
+
|
512
|
+
if (newIdiomType == JSON_STATE_PROPERTY || newIdiomType == JSON_STATE_IDIOM) {
|
513
|
+
if (*idiomType == JSON_EVENT_PROPERTY || *idiomType == JSON_EVENT_IDIOM) {
|
514
|
+
return ERR_UNEXPECTED_TYPE;
|
515
|
+
}
|
516
|
+
|
517
|
+
*idiomType = JSON_STATE_IDIOM;
|
518
|
+
}
|
519
|
+
|
520
|
+
if (hash != HASH_L && hash != HASH_R) {
|
521
|
+
return ERR_UNEXPECTED_NAME;
|
522
|
+
}
|
523
|
+
|
524
|
+
result = readNextName(last, &first, &last, &hash);
|
525
|
+
}
|
526
|
+
}
|
527
|
+
|
528
|
+
return PARSE_OK;
|
529
|
+
}
|
530
|
+
|
531
|
+
|
532
|
+
static unsigned int validateExpression(char *rule) {
|
533
|
+
char *first;
|
534
|
+
char *last;
|
535
|
+
unsigned char type;
|
536
|
+
unsigned char operator = OP_NOP;
|
537
|
+
unsigned int hash;
|
538
|
+
unsigned int result = readNextName(rule, &first, &last, &hash);
|
539
|
+
if (result != PARSE_OK) {
|
540
|
+
return result;
|
541
|
+
}
|
542
|
+
|
543
|
+
switch (hash) {
|
544
|
+
case HASH_EQ:
|
545
|
+
operator = OP_EQ;
|
546
|
+
break;
|
547
|
+
case HASH_NEQ:
|
548
|
+
operator = OP_NEQ;
|
549
|
+
break;
|
550
|
+
case HASH_GT:
|
551
|
+
operator = OP_GT;
|
552
|
+
break;
|
553
|
+
case HASH_GTE:
|
554
|
+
operator = OP_GTE;
|
555
|
+
break;
|
556
|
+
case HASH_EX:
|
557
|
+
operator = OP_EX;
|
558
|
+
break;
|
559
|
+
case HASH_NEX:
|
560
|
+
operator = OP_NEX;
|
561
|
+
break;
|
562
|
+
case HASH_LT:
|
563
|
+
operator = OP_LT;
|
564
|
+
break;
|
565
|
+
case HASH_LTE:
|
566
|
+
operator = OP_LTE;
|
567
|
+
break;
|
568
|
+
case HASH_AND:
|
569
|
+
case HASH_OR:
|
570
|
+
result = readNextValue(last, &first, &last, &type);
|
571
|
+
if (type != JSON_ARRAY) {
|
572
|
+
return ERR_UNEXPECTED_TYPE;
|
573
|
+
}
|
574
|
+
|
575
|
+
result = readNextArrayValue(first, &first, &last, &type);
|
576
|
+
while (result == PARSE_OK) {
|
577
|
+
result = validateExpression(first);
|
578
|
+
if (result != PARSE_OK) {
|
579
|
+
return result;
|
580
|
+
}
|
581
|
+
|
582
|
+
result = readNextArrayValue(last, &first, &last, &type);
|
583
|
+
}
|
584
|
+
|
585
|
+
return (result == PARSE_END ? RULES_OK: result);
|
586
|
+
}
|
587
|
+
|
588
|
+
if (operator == OP_NOP) {
|
589
|
+
operator = OP_EQ;
|
590
|
+
first = rule;
|
591
|
+
} else {
|
592
|
+
result = readNextValue(last, &first, &last, &type);
|
593
|
+
if (result != PARSE_OK) {
|
594
|
+
return result;
|
595
|
+
}
|
596
|
+
if (type != JSON_OBJECT) {
|
597
|
+
return ERR_UNEXPECTED_TYPE;
|
598
|
+
}
|
599
|
+
}
|
600
|
+
|
601
|
+
result = readNextName(first, &first, &last, &hash);
|
602
|
+
if (result != PARSE_OK) {
|
603
|
+
return result;
|
604
|
+
}
|
605
|
+
|
606
|
+
// Validating expression rValue
|
607
|
+
result = readNextValue(last, &first, &last, &type);
|
608
|
+
if (result != PARSE_OK) {
|
609
|
+
return result;
|
610
|
+
}
|
611
|
+
|
612
|
+
if (type == JSON_ARRAY) {
|
613
|
+
return ERR_UNEXPECTED_TYPE;
|
614
|
+
}
|
615
|
+
|
616
|
+
if (type == JSON_OBJECT) {
|
617
|
+
unsigned char idiomType = 0;
|
618
|
+
result = validateIdiom(first, &idiomType);
|
619
|
+
if (result != PARSE_OK) {
|
620
|
+
return result;
|
621
|
+
}
|
622
|
+
}
|
623
|
+
|
624
|
+
return PARSE_OK;
|
625
|
+
}
|
626
|
+
|
627
|
+
static unsigned int validateAlgebra(char *rule) {
|
628
|
+
char *first;
|
629
|
+
char *last;
|
630
|
+
char *lastArrayValue;
|
631
|
+
unsigned int hash;
|
632
|
+
unsigned char type;
|
633
|
+
unsigned char reenter = 0;
|
634
|
+
unsigned int result = readNextArrayValue(rule, &first, &lastArrayValue, &type);
|
635
|
+
while (result == PARSE_OK) {
|
636
|
+
result = readNextName(first, &first, &last, &hash);
|
637
|
+
unsigned int nameLength = last - first;
|
638
|
+
if (nameLength >= 4) {
|
639
|
+
if (!strncmp("$all", last - 4, 4)) {
|
640
|
+
nameLength = nameLength - 4;
|
641
|
+
reenter = 1;
|
642
|
+
} else if (!strncmp("$any", last - 4, 4)) {
|
643
|
+
nameLength = nameLength - 4;
|
644
|
+
reenter = 1;
|
645
|
+
} else if (!strncmp("$not", last - 4, 4)) {
|
646
|
+
nameLength = nameLength - 4;
|
647
|
+
}
|
648
|
+
|
649
|
+
if (nameLength == 0) {
|
650
|
+
return ERR_RULE_WITHOUT_QUALIFIER;
|
651
|
+
}
|
652
|
+
}
|
653
|
+
|
654
|
+
result = readNextValue(last, &first, &last, &type);
|
655
|
+
if (result != PARSE_OK) {
|
656
|
+
return result;
|
657
|
+
}
|
658
|
+
|
659
|
+
if (!reenter) {
|
660
|
+
result = validateExpression(first);
|
661
|
+
}
|
662
|
+
else {
|
663
|
+
result = validateAlgebra(first);
|
664
|
+
reenter = 0;
|
665
|
+
}
|
666
|
+
|
667
|
+
if (result != PARSE_OK) {
|
668
|
+
return result;
|
669
|
+
}
|
670
|
+
|
671
|
+
result = readNextArrayValue(lastArrayValue, &first, &lastArrayValue, &type);
|
672
|
+
}
|
673
|
+
|
674
|
+
return (result == PARSE_END ? PARSE_OK: result);
|
675
|
+
}
|
676
|
+
|
677
|
+
static unsigned int validateRuleset(char *rules) {
|
678
|
+
char *first;
|
679
|
+
char *last;
|
680
|
+
char *firstName;
|
681
|
+
char *lastName;
|
682
|
+
char *lastRuleValue;
|
683
|
+
unsigned char type;
|
684
|
+
unsigned int hash;
|
685
|
+
unsigned int result;
|
686
|
+
result = readNextName(rules, &firstName, &lastName, &hash);
|
687
|
+
while (result == PARSE_OK) {
|
688
|
+
result = readNextValue(lastName, &first, &lastRuleValue, &type);
|
689
|
+
if (result != PARSE_OK) {
|
690
|
+
return result;
|
691
|
+
}
|
692
|
+
if (type != JSON_OBJECT) {
|
693
|
+
return ERR_UNEXPECTED_TYPE;
|
694
|
+
}
|
695
|
+
|
696
|
+
unsigned int countResult = validateSetting(HASH_COUNT, first, JSON_INT);
|
697
|
+
if (countResult != PARSE_OK && countResult != ERR_SETTING_NOT_FOUND) {
|
698
|
+
return countResult;
|
699
|
+
}
|
700
|
+
|
701
|
+
unsigned int spanResult = validateSetting(HASH_SPAN, first, JSON_INT);
|
702
|
+
if (spanResult != PARSE_OK && spanResult != ERR_SETTING_NOT_FOUND) {
|
703
|
+
return spanResult;
|
704
|
+
}
|
705
|
+
|
706
|
+
unsigned int capResult = validateSetting(HASH_CAP, first, JSON_INT);
|
707
|
+
if (capResult != PARSE_OK && capResult != ERR_SETTING_NOT_FOUND) {
|
708
|
+
return capResult;
|
709
|
+
}
|
710
|
+
|
711
|
+
if ((spanResult == PARSE_OK && (countResult == PARSE_OK || capResult == PARSE_OK)) ||
|
712
|
+
(countResult == PARSE_OK && capResult == PARSE_OK)) {
|
713
|
+
return ERR_UNEXPECTED_NAME;
|
714
|
+
}
|
715
|
+
|
716
|
+
result = validateSetting(HASH_BY, first, JSON_STRING);
|
717
|
+
if (result != PARSE_OK && result != ERR_SETTING_NOT_FOUND) {
|
718
|
+
return result;
|
719
|
+
}
|
720
|
+
|
721
|
+
result = validateSetting(HASH_PRI, first, JSON_INT);
|
722
|
+
if (result != PARSE_OK && result != ERR_SETTING_NOT_FOUND) {
|
723
|
+
return result;
|
724
|
+
}
|
725
|
+
|
726
|
+
result = readNextName(first, &first, &last, &hash);
|
727
|
+
while (result == PARSE_OK) {
|
728
|
+
result = readNextValue(last, &first, &last, &type);
|
729
|
+
if (result != PARSE_OK) {
|
730
|
+
return result;
|
731
|
+
}
|
732
|
+
|
733
|
+
if (hash == HASH_ALL || hash == HASH_ANY) {
|
734
|
+
result = validateAlgebra(first);
|
735
|
+
if (result != RULES_OK && result != PARSE_END) {
|
736
|
+
return result;
|
737
|
+
}
|
738
|
+
} else if (hash != HASH_COUNT && hash != HASH_PRI && hash != HASH_SPAN && hash != HASH_CAP && hash != HASH_BY) {
|
739
|
+
return ERR_UNEXPECTED_NAME;
|
740
|
+
}
|
741
|
+
|
742
|
+
result = readNextName(last, &first, &last, &hash);
|
743
|
+
}
|
744
|
+
|
745
|
+
result = readNextName(lastRuleValue, &firstName, &lastName, &hash);
|
746
|
+
}
|
747
|
+
|
748
|
+
return (result == PARSE_END ? PARSE_OK: result);
|
749
|
+
}
|
750
|
+
|
751
|
+
static unsigned int linkAlpha(ruleset *tree,
|
752
|
+
unsigned int parentOffset,
|
753
|
+
unsigned int nextOffset) {
|
754
|
+
unsigned int result;
|
755
|
+
unsigned int entry;
|
756
|
+
node *parentAlpha = &tree->nodePool[parentOffset];
|
757
|
+
node *nextNode = &tree->nodePool[nextOffset];
|
758
|
+
if (nextNode->type != NODE_ALPHA) {
|
759
|
+
result = ensureBetaList(tree, parentAlpha);
|
760
|
+
if (result != RULES_OK) {
|
761
|
+
return result;
|
762
|
+
}
|
763
|
+
|
764
|
+
unsigned int *parentBetaList = &tree->nextPool[parentAlpha->value.a.betaListOffset];
|
765
|
+
for (entry = 0; parentBetaList[entry] != 0; ++entry) {
|
766
|
+
if (entry == BETA_LIST_LENGTH) {
|
767
|
+
return ERR_RULE_BETA_LIMIT_EXCEEDED;
|
768
|
+
}
|
769
|
+
}
|
770
|
+
|
771
|
+
parentBetaList[entry] = nextOffset;
|
772
|
+
}
|
773
|
+
else if (nextNode->value.a.operator == OP_NEX) {
|
774
|
+
result = ensureNextList(tree, parentAlpha);
|
775
|
+
if (result != RULES_OK) {
|
776
|
+
return result;
|
777
|
+
}
|
778
|
+
|
779
|
+
unsigned int *parentNextList = &tree->nextPool[parentAlpha->value.a.nextListOffset];
|
780
|
+
unsigned int entry;
|
781
|
+
for (entry = 0; parentNextList[entry] != 0; ++entry) {
|
782
|
+
if (entry == NEXT_LIST_LENGTH) {
|
783
|
+
return ERR_RULE_EXISTS_LIMIT_EXCEEDED;
|
784
|
+
}
|
785
|
+
}
|
786
|
+
|
787
|
+
parentNextList[entry] = nextOffset;
|
788
|
+
}
|
789
|
+
else {
|
790
|
+
result = ensureNextHashset(tree, parentAlpha);
|
791
|
+
if (result != RULES_OK) {
|
792
|
+
return result;
|
793
|
+
}
|
794
|
+
|
795
|
+
unsigned int *parentNext = &tree->nextPool[parentAlpha->value.a.nextOffset];
|
796
|
+
unsigned int hash = nextNode->value.a.hash;
|
797
|
+
for (entry = hash & HASH_MASK; parentNext[entry] != 0; entry = (entry + 1) % NEXT_BUCKET_LENGTH) {
|
798
|
+
if ((entry + 1) % NEXT_BUCKET_LENGTH == (hash & HASH_MASK)) {
|
799
|
+
return ERR_RULE_LIMIT_EXCEEDED;
|
800
|
+
}
|
801
|
+
}
|
802
|
+
|
803
|
+
parentNext[entry] = nextOffset;
|
804
|
+
}
|
805
|
+
|
806
|
+
return RULES_OK;
|
807
|
+
}
|
808
|
+
|
809
|
+
static unsigned char readReference(ruleset *tree, char *rule, reference *ref) {
|
810
|
+
char *first;
|
811
|
+
char *last;
|
812
|
+
unsigned char type;
|
813
|
+
unsigned int hash;
|
814
|
+
unsigned char returnType = JSON_EVENT_PROPERTY;
|
815
|
+
|
816
|
+
ref->idOffset = 0;
|
817
|
+
readNextName(rule, &first, &last, &hash);
|
818
|
+
if (hash != HASH_S) {
|
819
|
+
storeString(tree, first, &ref->idOffset, last - first);
|
820
|
+
readNextString(last, &first, &last, &hash);
|
821
|
+
ref->hash = hash;
|
822
|
+
storeString(tree, first, &ref->nameOffset, last - first);
|
823
|
+
} else {
|
824
|
+
returnType = JSON_STATE_PROPERTY;
|
825
|
+
if (readNextString(last, &first, &last, &hash) == PARSE_OK) {
|
826
|
+
ref->hash = hash;
|
827
|
+
storeString(tree, first, &ref->nameOffset, last - first);
|
828
|
+
}
|
829
|
+
else {
|
830
|
+
readNextValue(last, &first, &last, &type);
|
831
|
+
unsigned int result = readNextName(first, &first, &last, &hash);
|
832
|
+
while (result == PARSE_OK) {
|
833
|
+
switch (hash) {
|
834
|
+
case HASH_NAME:
|
835
|
+
readNextString(last, &first, &last, &hash);
|
836
|
+
ref->hash = hash;
|
837
|
+
storeString(tree, first, &ref->nameOffset, last - first);
|
838
|
+
break;
|
839
|
+
case HASH_ID:
|
840
|
+
readNextValue(last, &first, &last, &type);
|
841
|
+
if (type == JSON_STRING) {
|
842
|
+
storeString(tree, first, &ref->idOffset, last - first);
|
843
|
+
} else{
|
844
|
+
storeString(tree, first, &ref->idOffset, last - first + 1);
|
845
|
+
}
|
846
|
+
|
847
|
+
break;
|
848
|
+
default:
|
849
|
+
readNextValue(last, &first, &last, &type);
|
850
|
+
break;
|
851
|
+
}
|
852
|
+
|
853
|
+
result = readNextName(last, &first, &last, &hash);
|
854
|
+
}
|
855
|
+
}
|
856
|
+
}
|
857
|
+
|
858
|
+
return returnType;
|
859
|
+
}
|
860
|
+
|
861
|
+
static unsigned int readIdiom(ruleset *tree, char *rule, unsigned char *idiomType, unsigned int *idiomOffset, reference *ref) {
|
862
|
+
char *first;
|
863
|
+
char *last;
|
864
|
+
unsigned char type = 0;
|
865
|
+
unsigned char operator = OP_NOP;
|
866
|
+
unsigned int hash;
|
867
|
+
unsigned int result;
|
868
|
+
|
869
|
+
readNextName(rule, &first, &last, &hash);
|
870
|
+
switch (hash) {
|
871
|
+
case HASH_ADD:
|
872
|
+
operator = OP_ADD;
|
873
|
+
break;
|
874
|
+
case HASH_SUB:
|
875
|
+
operator = OP_SUB;
|
876
|
+
break;
|
877
|
+
case HASH_MUL:
|
878
|
+
operator = OP_MUL;
|
879
|
+
break;
|
880
|
+
case HASH_DIV:
|
881
|
+
operator = OP_DIV;
|
882
|
+
break;
|
883
|
+
}
|
884
|
+
|
885
|
+
if (operator == OP_NOP) {
|
886
|
+
*idiomType = readReference(tree, rule, ref);
|
887
|
+
} else {
|
888
|
+
idiom *newIdiom = NULL;
|
889
|
+
result = storeIdiom(tree, &newIdiom, idiomOffset);
|
890
|
+
if (result != RULES_OK) {
|
891
|
+
return result;
|
892
|
+
}
|
893
|
+
|
894
|
+
*idiomType = JSON_STATE_IDIOM;
|
895
|
+
newIdiom->operator = operator;
|
896
|
+
readNextValue(last, &first, &last, &type);
|
897
|
+
result = readNextName(first, &first, &last, &hash);
|
898
|
+
while (result == PARSE_OK) {
|
899
|
+
unsigned int newIdiomOffset = 0;
|
900
|
+
reference newRef;
|
901
|
+
readNextValue(last, &first, &last, &type);
|
902
|
+
if (type == JSON_OBJECT) {
|
903
|
+
result = readIdiom(tree, first, &type, &newIdiomOffset, &newRef);
|
904
|
+
if (result != RULES_OK) {
|
905
|
+
return result;
|
906
|
+
}
|
907
|
+
}
|
908
|
+
|
909
|
+
if (type == JSON_EVENT_PROPERTY || type == JSON_EVENT_IDIOM) {
|
910
|
+
*idiomType = JSON_EVENT_IDIOM;
|
911
|
+
}
|
912
|
+
|
913
|
+
// newIdiom address might have changed after readIdiom
|
914
|
+
newIdiom = &tree->idiomPool[*idiomOffset];
|
915
|
+
switch (hash) {
|
916
|
+
case HASH_L:
|
917
|
+
copyValue(tree, &newIdiom->left, first, last, newIdiomOffset, &newRef, type);
|
918
|
+
break;
|
919
|
+
case HASH_R:
|
920
|
+
copyValue(tree, &newIdiom->right, first, last, newIdiomOffset, &newRef, type);
|
921
|
+
break;
|
922
|
+
}
|
923
|
+
|
924
|
+
result = readNextName(last, &first, &last, &hash);
|
925
|
+
}
|
926
|
+
}
|
927
|
+
|
928
|
+
return RULES_OK;
|
929
|
+
}
|
930
|
+
|
931
|
+
static unsigned int findAlpha(ruleset *tree,
|
932
|
+
unsigned int parentOffset,
|
933
|
+
unsigned char operator,
|
934
|
+
char *rule,
|
935
|
+
expression *expr,
|
936
|
+
unsigned int *resultOffset) {
|
937
|
+
char *first;
|
938
|
+
char *last;
|
939
|
+
char *firstName;
|
940
|
+
char *lastName;
|
941
|
+
unsigned char type;
|
942
|
+
unsigned int entry;
|
943
|
+
unsigned int hash;
|
944
|
+
unsigned int idiomOffset;
|
945
|
+
unsigned int result;
|
946
|
+
reference ref;
|
947
|
+
|
948
|
+
readNextName(rule, &firstName, &lastName, &hash);
|
949
|
+
readNextValue(lastName, &first, &last, &type);
|
950
|
+
if (type == JSON_OBJECT) {
|
951
|
+
result = readIdiom(tree, first, &type, &idiomOffset, &ref);
|
952
|
+
if (result != RULES_OK) {
|
953
|
+
return result;
|
954
|
+
}
|
955
|
+
}
|
956
|
+
|
957
|
+
node *parent = &tree->nodePool[parentOffset];
|
958
|
+
unsigned int *parentNext;
|
959
|
+
if (parent->value.a.nextOffset) {
|
960
|
+
parentNext = &tree->nextPool[parent->value.a.nextOffset];
|
961
|
+
for (entry = hash & HASH_MASK; parentNext[entry] != 0; entry = (entry + 1) % NEXT_BUCKET_LENGTH) {
|
962
|
+
node *currentNode = &tree->nodePool[parentNext[entry]];
|
963
|
+
if (currentNode->value.a.hash == hash &&
|
964
|
+
currentNode->value.a.operator == operator) {
|
965
|
+
if (compareValue(tree, ¤tNode->value.a.right, first, last, &ref, type)) {
|
966
|
+
*resultOffset = parentNext[entry];
|
967
|
+
return RULES_OK;
|
968
|
+
}
|
969
|
+
}
|
970
|
+
}
|
971
|
+
}
|
972
|
+
|
973
|
+
if (parent->value.a.nextListOffset) {
|
974
|
+
parentNext = &tree->nextPool[parent->value.a.nextListOffset];
|
975
|
+
for (entry = 0; parentNext[entry] != 0; ++entry) {
|
976
|
+
node *currentNode = &tree->nodePool[parentNext[entry]];
|
977
|
+
if (currentNode->value.a.hash == hash&&
|
978
|
+
currentNode->value.a.operator == operator) {
|
979
|
+
if (compareValue(tree, ¤tNode->value.a.right, first, last, &ref, type)) {
|
980
|
+
*resultOffset = parentNext[entry];
|
981
|
+
return RULES_OK;
|
982
|
+
}
|
983
|
+
}
|
984
|
+
}
|
985
|
+
}
|
986
|
+
|
987
|
+
unsigned int stringOffset;
|
988
|
+
result = storeString(tree, firstName, &stringOffset, lastName - firstName);
|
989
|
+
if (result != RULES_OK) {
|
990
|
+
return result;
|
991
|
+
}
|
992
|
+
|
993
|
+
node *newAlpha;
|
994
|
+
result = storeAlpha(tree, &newAlpha, resultOffset);
|
995
|
+
if (result != RULES_OK) {
|
996
|
+
return result;
|
997
|
+
}
|
998
|
+
|
999
|
+
newAlpha->nameOffset = stringOffset;
|
1000
|
+
newAlpha->type = NODE_ALPHA;
|
1001
|
+
newAlpha->value.a.hash = hash;
|
1002
|
+
newAlpha->value.a.operator = operator;
|
1003
|
+
copyValue(tree, &newAlpha->value.a.right, first, last, idiomOffset, &ref, type);
|
1004
|
+
if (type == JSON_EVENT_PROPERTY || type == JSON_EVENT_IDIOM) {
|
1005
|
+
result = appendTerm(expr, *resultOffset);
|
1006
|
+
if (result != RULES_OK) {
|
1007
|
+
return result;
|
1008
|
+
}
|
1009
|
+
}
|
1010
|
+
|
1011
|
+
return linkAlpha(tree, parentOffset, *resultOffset);
|
1012
|
+
}
|
1013
|
+
|
1014
|
+
static void getSymbolSetting(unsigned int settingHash, char *rule, unsigned int *symbolHash) {
|
1015
|
+
char *first;
|
1016
|
+
char *last;
|
1017
|
+
unsigned int hash;
|
1018
|
+
unsigned char type;
|
1019
|
+
unsigned int result = readNextName(rule, &first, &last, &hash);
|
1020
|
+
while (result == PARSE_OK) {
|
1021
|
+
if (hash == settingHash) {
|
1022
|
+
readNextString(last, &first, &last, symbolHash);
|
1023
|
+
break;
|
1024
|
+
} else {
|
1025
|
+
readNextValue(last, &first, &last, &type);
|
1026
|
+
result = readNextName(last, &first, &last, &hash);
|
1027
|
+
}
|
1028
|
+
}
|
1029
|
+
}
|
1030
|
+
|
1031
|
+
static void getSetting(unsigned int settingHash, char *rule, unsigned short *value) {
|
1032
|
+
char *first;
|
1033
|
+
char *last;
|
1034
|
+
char temp;
|
1035
|
+
unsigned int hash;
|
1036
|
+
unsigned char type;
|
1037
|
+
unsigned int result = readNextName(rule, &first, &last, &hash);
|
1038
|
+
while (result == PARSE_OK) {
|
1039
|
+
readNextValue(last, &first, &last, &type);
|
1040
|
+
if (hash == settingHash) {
|
1041
|
+
temp = first[last - first + 1];
|
1042
|
+
first[last - first + 1] = '\0';
|
1043
|
+
*value = atoi(first);
|
1044
|
+
first[last - first + 1] = temp;
|
1045
|
+
break;
|
1046
|
+
}
|
1047
|
+
result = readNextName(last, &first, &last, &hash);
|
1048
|
+
}
|
1049
|
+
}
|
1050
|
+
|
1051
|
+
static unsigned int createAlpha(ruleset *tree,
|
1052
|
+
char *rule,
|
1053
|
+
expression *expr,
|
1054
|
+
unsigned int nextOffset,
|
1055
|
+
unsigned int *newOffset) {
|
1056
|
+
char *first;
|
1057
|
+
char *last;
|
1058
|
+
unsigned char type;
|
1059
|
+
unsigned char operator = OP_NOP;
|
1060
|
+
unsigned int hash;
|
1061
|
+
unsigned int result;
|
1062
|
+
unsigned int parentOffset = *newOffset;
|
1063
|
+
readNextName(rule, &first, &last, &hash);
|
1064
|
+
switch (hash) {
|
1065
|
+
case HASH_EQ:
|
1066
|
+
operator = OP_EQ;
|
1067
|
+
break;
|
1068
|
+
case HASH_NEQ:
|
1069
|
+
operator = OP_NEQ;
|
1070
|
+
break;
|
1071
|
+
case HASH_GT:
|
1072
|
+
operator = OP_GT;
|
1073
|
+
break;
|
1074
|
+
case HASH_GTE:
|
1075
|
+
operator = OP_GTE;
|
1076
|
+
break;
|
1077
|
+
case HASH_EX:
|
1078
|
+
operator = OP_EX;
|
1079
|
+
break;
|
1080
|
+
case HASH_NEX:
|
1081
|
+
operator = OP_NEX;
|
1082
|
+
break;
|
1083
|
+
case HASH_LT:
|
1084
|
+
operator = OP_LT;
|
1085
|
+
break;
|
1086
|
+
case HASH_LTE:
|
1087
|
+
operator = OP_LTE;
|
1088
|
+
break;
|
1089
|
+
case HASH_AND:
|
1090
|
+
result = appendTerm(expr, tree->andNodeOffset);
|
1091
|
+
if (result != RULES_OK) {
|
1092
|
+
return result;
|
1093
|
+
}
|
1094
|
+
|
1095
|
+
readNextValue(last, &first, &last, &type);
|
1096
|
+
unsigned int previousOffset = 0;
|
1097
|
+
unsigned int resultOffset = parentOffset;
|
1098
|
+
result = readNextArrayValue(first, &first, &last, &type);
|
1099
|
+
while (result == PARSE_OK) {
|
1100
|
+
createAlpha(tree, first, expr, 0, &resultOffset);
|
1101
|
+
previousOffset = resultOffset;
|
1102
|
+
result = readNextArrayValue(last, &first, &last, &type);
|
1103
|
+
}
|
1104
|
+
|
1105
|
+
result = appendTerm(expr, tree->endNodeOffset);
|
1106
|
+
if (result != RULES_OK) {
|
1107
|
+
return result;
|
1108
|
+
}
|
1109
|
+
return linkAlpha(tree, previousOffset, nextOffset);
|
1110
|
+
case HASH_OR:
|
1111
|
+
result = appendTerm(expr, tree->orNodeOffset);
|
1112
|
+
if (result != RULES_OK) {
|
1113
|
+
return result;
|
1114
|
+
}
|
1115
|
+
|
1116
|
+
readNextValue(last, &first, &last, &type);
|
1117
|
+
result = readNextArrayValue(first, &first, &last, &type);
|
1118
|
+
while (result == PARSE_OK) {
|
1119
|
+
unsigned int single_offset = parentOffset;
|
1120
|
+
createAlpha(tree, first, expr, nextOffset, &single_offset);
|
1121
|
+
result = readNextArrayValue(last, &first, &last, &type);
|
1122
|
+
}
|
1123
|
+
|
1124
|
+
result = appendTerm(expr, tree->endNodeOffset);
|
1125
|
+
if (result != RULES_OK) {
|
1126
|
+
return result;
|
1127
|
+
}
|
1128
|
+
return RULES_OK;
|
1129
|
+
}
|
1130
|
+
|
1131
|
+
if (operator == OP_NOP) {
|
1132
|
+
operator = OP_EQ;
|
1133
|
+
first = rule;
|
1134
|
+
} else {
|
1135
|
+
readNextValue(last, &first, &last, &type);
|
1136
|
+
}
|
1137
|
+
|
1138
|
+
if (nextOffset == 0) {
|
1139
|
+
return findAlpha(tree, parentOffset, operator, first, expr, newOffset);
|
1140
|
+
} else {
|
1141
|
+
unsigned int result = findAlpha(tree, parentOffset, operator, first, expr, newOffset);
|
1142
|
+
if (result != RULES_OK) {
|
1143
|
+
return result;
|
1144
|
+
}
|
1145
|
+
|
1146
|
+
return linkAlpha(tree, *newOffset, nextOffset);
|
1147
|
+
}
|
1148
|
+
}
|
1149
|
+
|
1150
|
+
static unsigned int createBetaConnector(ruleset *tree,
|
1151
|
+
char *rule,
|
1152
|
+
path *betaPath,
|
1153
|
+
unsigned int nextOffset) {
|
1154
|
+
char *first;
|
1155
|
+
char *last;
|
1156
|
+
char *lastArrayValue;
|
1157
|
+
unsigned int hash;
|
1158
|
+
unsigned char type;
|
1159
|
+
unsigned int result = readNextArrayValue(rule, &first, &lastArrayValue, &type);
|
1160
|
+
while (result == PARSE_OK) {
|
1161
|
+
readNextName(first, &first, &last, &hash);
|
1162
|
+
unsigned int nameLength = last - first;
|
1163
|
+
unsigned char operator = OP_NOP;
|
1164
|
+
if (nameLength >= 4) {
|
1165
|
+
if (!strncmp("$all", last - 4, 4)) {
|
1166
|
+
operator = OP_ALL;
|
1167
|
+
} else if (!strncmp("$any", last - 4, 4)) {
|
1168
|
+
operator = OP_ANY;
|
1169
|
+
} else if (!strncmp("$not", last - 4, 4)) {
|
1170
|
+
operator = OP_NOT;
|
1171
|
+
}
|
1172
|
+
|
1173
|
+
if (operator == OP_ALL || operator == OP_ANY || operator == OP_NOT) {
|
1174
|
+
nameLength = nameLength - 4;
|
1175
|
+
hash = djbHash(first, nameLength);
|
1176
|
+
}
|
1177
|
+
}
|
1178
|
+
|
1179
|
+
unsigned int stringOffset;
|
1180
|
+
result = storeString(tree, first, &stringOffset, nameLength);
|
1181
|
+
if (result != RULES_OK) {
|
1182
|
+
return result;
|
1183
|
+
}
|
1184
|
+
|
1185
|
+
node *connector;
|
1186
|
+
unsigned int connectorOffset;
|
1187
|
+
result = storeNode(tree, &connector, &connectorOffset);
|
1188
|
+
if (result != RULES_OK) {
|
1189
|
+
return result;
|
1190
|
+
}
|
1191
|
+
|
1192
|
+
expression *expr;
|
1193
|
+
connector->nameOffset = stringOffset;
|
1194
|
+
connector->type = NODE_BETA_CONNECTOR;
|
1195
|
+
connector->value.b.nextOffset = nextOffset;
|
1196
|
+
connector->value.b.not = (operator == OP_NOT) ? 1 : 0;
|
1197
|
+
connector->value.b.hash = hash;
|
1198
|
+
if (betaPath->expressionsLength == 0) {
|
1199
|
+
betaPath->expressionsLength = 1;
|
1200
|
+
betaPath->expressions = malloc(sizeof(expression));
|
1201
|
+
if (!betaPath->expressions) {
|
1202
|
+
return ERR_OUT_OF_MEMORY;
|
1203
|
+
}
|
1204
|
+
|
1205
|
+
expr = betaPath->expressions;
|
1206
|
+
}
|
1207
|
+
else {
|
1208
|
+
betaPath->expressionsLength = betaPath->expressionsLength + 1;
|
1209
|
+
betaPath->expressions = realloc(betaPath->expressions, betaPath->expressionsLength * sizeof(expression));
|
1210
|
+
if (!betaPath->expressions) {
|
1211
|
+
return ERR_OUT_OF_MEMORY;
|
1212
|
+
}
|
1213
|
+
|
1214
|
+
expr = &betaPath->expressions[betaPath->expressionsLength - 1];
|
1215
|
+
}
|
1216
|
+
|
1217
|
+
expr->nameOffset = stringOffset;
|
1218
|
+
expr->aliasOffset = stringOffset;
|
1219
|
+
expr->not = (operator == OP_NOT) ? 1 : 0;
|
1220
|
+
expr->termsLength = 0;
|
1221
|
+
expr->t.termsPointer = NULL;
|
1222
|
+
if (operator == OP_NOP || operator == OP_NOT) {
|
1223
|
+
unsigned int resultOffset = NODE_M_OFFSET;
|
1224
|
+
readNextValue(last, &first, &last, &type);
|
1225
|
+
result = createAlpha(tree, first, expr, connectorOffset, &resultOffset);
|
1226
|
+
}
|
1227
|
+
else {
|
1228
|
+
readNextValue(last, &first, &last, &type);
|
1229
|
+
result = createBeta(tree, first, operator, connectorOffset, betaPath, NULL);
|
1230
|
+
}
|
1231
|
+
|
1232
|
+
if (result != RULES_OK) {
|
1233
|
+
return result;
|
1234
|
+
}
|
1235
|
+
|
1236
|
+
result = readNextArrayValue(lastArrayValue, &first, &lastArrayValue, &type);
|
1237
|
+
}
|
1238
|
+
|
1239
|
+
return (result == PARSE_END ? RULES_OK: result);
|
1240
|
+
}
|
1241
|
+
|
1242
|
+
static unsigned int createBeta(ruleset *tree,
|
1243
|
+
char *rule,
|
1244
|
+
unsigned char operator,
|
1245
|
+
unsigned int nextOffset,
|
1246
|
+
path *nextPath,
|
1247
|
+
path **outPath) {
|
1248
|
+
|
1249
|
+
path *betaPath = malloc(sizeof(path));
|
1250
|
+
if (!betaPath) {
|
1251
|
+
return ERR_OUT_OF_MEMORY;
|
1252
|
+
}
|
1253
|
+
|
1254
|
+
betaPath->operator = operator;
|
1255
|
+
betaPath->expressionsLength = 0;
|
1256
|
+
betaPath->expressions = NULL;
|
1257
|
+
betaPath->parents = NULL;
|
1258
|
+
betaPath->parentsLength = 0;
|
1259
|
+
|
1260
|
+
if (nextPath) {
|
1261
|
+
if (nextPath->parentsLength == 0) {
|
1262
|
+
nextPath->parentsLength = nextPath->expressionsLength;
|
1263
|
+
nextPath->parents = calloc(nextPath->expressionsLength, sizeof(path*));
|
1264
|
+
if (!nextPath->parents) {
|
1265
|
+
return ERR_OUT_OF_MEMORY;
|
1266
|
+
}
|
1267
|
+
|
1268
|
+
nextPath->parents[nextPath->expressionsLength - 1] = betaPath;
|
1269
|
+
} else {
|
1270
|
+
int lengthDiff = nextPath->expressionsLength - nextPath->parentsLength;
|
1271
|
+
nextPath->parents = realloc(nextPath->parents, sizeof(path*) * nextPath->expressionsLength);
|
1272
|
+
if (!nextPath->parents) {
|
1273
|
+
return ERR_OUT_OF_MEMORY;
|
1274
|
+
}
|
1275
|
+
|
1276
|
+
for (int i = 0; i < lengthDiff -1; ++i) {
|
1277
|
+
nextPath->parents[nextPath->parentsLength + i] = NULL;
|
1278
|
+
}
|
1279
|
+
|
1280
|
+
nextPath->parentsLength = nextPath->expressionsLength;
|
1281
|
+
nextPath->parents[nextPath->parentsLength - 1] = betaPath;
|
1282
|
+
}
|
1283
|
+
}
|
1284
|
+
|
1285
|
+
if (outPath) {
|
1286
|
+
*outPath = betaPath;
|
1287
|
+
}
|
1288
|
+
|
1289
|
+
return createBetaConnector(tree, rule, betaPath, nextOffset);
|
1290
|
+
}
|
1291
|
+
|
1292
|
+
static unsigned int add(any *right, any *left, any **result) {
|
1293
|
+
right->nodes = realloc(right->nodes, (right->nodesLength + left->nodesLength) * sizeof(all*));
|
1294
|
+
if (!right->nodes) {
|
1295
|
+
return ERR_OUT_OF_MEMORY;
|
1296
|
+
}
|
1297
|
+
for (unsigned int i = 0; i < left->nodesLength; ++i) {
|
1298
|
+
right->nodes[right->nodesLength + i] = left->nodes[i];
|
1299
|
+
}
|
1300
|
+
right->nodesLength = right->nodesLength + left->nodesLength;
|
1301
|
+
free(left->nodes);
|
1302
|
+
free(left);
|
1303
|
+
*result = right;
|
1304
|
+
return RULES_OK;
|
1305
|
+
}
|
1306
|
+
|
1307
|
+
static unsigned int multiply(ruleset *tree, any *right, any *left, any **result) {
|
1308
|
+
any *product = malloc(sizeof(any));
|
1309
|
+
product->nodesLength = right->nodesLength * left->nodesLength;
|
1310
|
+
product->nodes = malloc(sizeof(all*) * product->nodesLength);
|
1311
|
+
|
1312
|
+
for (unsigned int i = 0; i < left->nodesLength; ++i) {
|
1313
|
+
all *leftAll = left->nodes[i];
|
1314
|
+
for (unsigned int ii = 0; ii < right->nodesLength; ++ii) {
|
1315
|
+
all *rightAll = right->nodes[ii];
|
1316
|
+
all *newAll = malloc(sizeof(all));
|
1317
|
+
if (!newAll) {
|
1318
|
+
return ERR_OUT_OF_MEMORY;
|
1319
|
+
}
|
1320
|
+
|
1321
|
+
newAll->count = (leftAll->count > rightAll->count ? leftAll->count: rightAll->count);
|
1322
|
+
newAll->expressions = malloc((rightAll->expressionsLength + leftAll->expressionsLength) * sizeof(unsigned int));
|
1323
|
+
if (!newAll->expressions) {
|
1324
|
+
return ERR_OUT_OF_MEMORY;
|
1325
|
+
}
|
1326
|
+
|
1327
|
+
for (unsigned int iii = 0; iii < rightAll->expressionsLength; ++iii) {
|
1328
|
+
newAll->expressions[iii] = rightAll->expressions[iii];
|
1329
|
+
}
|
1330
|
+
|
1331
|
+
for (unsigned int iii = 0; iii < leftAll->expressionsLength; ++iii) {
|
1332
|
+
newAll->expressions[rightAll->expressionsLength + iii] = leftAll->expressions[iii];
|
1333
|
+
}
|
1334
|
+
|
1335
|
+
newAll->expressionsLength = rightAll->expressionsLength + leftAll->expressionsLength;
|
1336
|
+
product->nodes[i + ii * left->nodesLength] = newAll;
|
1337
|
+
}
|
1338
|
+
|
1339
|
+
free(leftAll->expressions);
|
1340
|
+
free(leftAll);
|
1341
|
+
}
|
1342
|
+
|
1343
|
+
for (unsigned int i = 0; i < right->nodesLength; ++i) {
|
1344
|
+
all *rightAll = right->nodes[i];
|
1345
|
+
free(rightAll->expressions);
|
1346
|
+
free(rightAll);
|
1347
|
+
}
|
1348
|
+
|
1349
|
+
free(right->nodes);
|
1350
|
+
free(right);
|
1351
|
+
free(left->nodes);
|
1352
|
+
free(left);
|
1353
|
+
*result = product;
|
1354
|
+
return RULES_OK;
|
1355
|
+
}
|
1356
|
+
|
1357
|
+
static unsigned int createSingleQuery(ruleset *tree,
|
1358
|
+
char *name,
|
1359
|
+
expression *expr,
|
1360
|
+
any **resultAny) {
|
1361
|
+
any *newAny = malloc(sizeof(any));
|
1362
|
+
if (!newAny) {
|
1363
|
+
return ERR_OUT_OF_MEMORY;
|
1364
|
+
}
|
1365
|
+
|
1366
|
+
newAny->nodesLength = 1;
|
1367
|
+
newAny->nodes = malloc(sizeof(all*));
|
1368
|
+
if (!newAny->nodes) {
|
1369
|
+
return ERR_OUT_OF_MEMORY;
|
1370
|
+
}
|
1371
|
+
|
1372
|
+
newAny->nodes[0] = malloc(sizeof(all));
|
1373
|
+
if (!newAny->nodes[0]) {
|
1374
|
+
return ERR_OUT_OF_MEMORY;
|
1375
|
+
}
|
1376
|
+
|
1377
|
+
newAny->nodes[0]->expressionsLength = 1;
|
1378
|
+
newAny->nodes[0]->expressions = malloc(sizeof(unsigned int));
|
1379
|
+
if (!newAny->nodes[0]->expressions) {
|
1380
|
+
return ERR_OUT_OF_MEMORY;
|
1381
|
+
}
|
1382
|
+
|
1383
|
+
expression *newExpression;
|
1384
|
+
unsigned int result = storeExpression(tree, &newExpression, newAny->nodes[0]->expressions);
|
1385
|
+
if (result != RULES_OK) {
|
1386
|
+
return result;
|
1387
|
+
}
|
1388
|
+
|
1389
|
+
result = storeString(tree, name, &newExpression->nameOffset, strlen(name));
|
1390
|
+
if (result != RULES_OK) {
|
1391
|
+
return result;
|
1392
|
+
}
|
1393
|
+
|
1394
|
+
newExpression->aliasOffset = expr->aliasOffset;
|
1395
|
+
newExpression->termsLength = expr->termsLength;
|
1396
|
+
newExpression->not = expr->not;
|
1397
|
+
if (expr->termsLength) {
|
1398
|
+
result = allocateNext(tree, expr->termsLength, &newExpression->t.termsOffset);
|
1399
|
+
if (result != RULES_OK) {
|
1400
|
+
return result;
|
1401
|
+
}
|
1402
|
+
|
1403
|
+
for (unsigned short i = 0; i < expr->termsLength; ++i) {
|
1404
|
+
tree->nextPool[newExpression->t.termsOffset + i] = expr->t.termsPointer[i];
|
1405
|
+
}
|
1406
|
+
|
1407
|
+
free(expr->t.termsPointer);
|
1408
|
+
}
|
1409
|
+
|
1410
|
+
*resultAny = newAny;
|
1411
|
+
return RULES_OK;
|
1412
|
+
}
|
1413
|
+
|
1414
|
+
static unsigned int createQueries(ruleset *tree,
|
1415
|
+
char *postfix,
|
1416
|
+
path *betaPath,
|
1417
|
+
any **anyResult) {
|
1418
|
+
any *currentAny = NULL;
|
1419
|
+
for (unsigned short i = 0; i < betaPath->expressionsLength; ++ i) {
|
1420
|
+
unsigned int result;
|
1421
|
+
expression *expr = &betaPath->expressions[i];
|
1422
|
+
if (betaPath->operator == OP_NOP) {
|
1423
|
+
result = createSingleQuery(tree, postfix, expr, anyResult);
|
1424
|
+
if (result != RULES_OK) {
|
1425
|
+
return result;
|
1426
|
+
}
|
1427
|
+
|
1428
|
+
free(betaPath->expressions);
|
1429
|
+
free(betaPath);
|
1430
|
+
return RULES_OK;
|
1431
|
+
}
|
1432
|
+
|
1433
|
+
char *name = &tree->stringPool[expr->nameOffset];
|
1434
|
+
int nameLength = strlen(name);
|
1435
|
+
#ifdef _WIN32
|
1436
|
+
char *nextPostfix = (char *)_alloca(sizeof(char)*(strlen(postfix) + nameLength + 2));
|
1437
|
+
#else
|
1438
|
+
char nextPostfix[strlen(postfix) + nameLength + 2];
|
1439
|
+
#endif
|
1440
|
+
strcpy(nextPostfix, name);
|
1441
|
+
nextPostfix[nameLength] = '!';
|
1442
|
+
strcpy(&nextPostfix[nameLength + 1], postfix);
|
1443
|
+
|
1444
|
+
any *newAny = NULL;
|
1445
|
+
if (i >= betaPath->parentsLength || !betaPath->parents[i]) {
|
1446
|
+
result = createSingleQuery(tree, nextPostfix, expr, &newAny);
|
1447
|
+
if (result != RULES_OK) {
|
1448
|
+
return result;
|
1449
|
+
}
|
1450
|
+
}
|
1451
|
+
else {
|
1452
|
+
result = createQueries(tree, nextPostfix, betaPath->parents[i], &newAny);
|
1453
|
+
if (result != RULES_OK) {
|
1454
|
+
return result;
|
1455
|
+
}
|
1456
|
+
}
|
1457
|
+
|
1458
|
+
if (!currentAny) {
|
1459
|
+
currentAny = newAny;
|
1460
|
+
}
|
1461
|
+
else if (betaPath->operator == OP_ANY) {
|
1462
|
+
result = add(currentAny, newAny, ¤tAny);
|
1463
|
+
if (result != RULES_OK) {
|
1464
|
+
return result;
|
1465
|
+
}
|
1466
|
+
}
|
1467
|
+
else if (betaPath->operator == OP_ALL) {
|
1468
|
+
result = multiply(tree, currentAny, newAny, ¤tAny);
|
1469
|
+
if (result != RULES_OK) {
|
1470
|
+
return result;
|
1471
|
+
}
|
1472
|
+
}
|
1473
|
+
}
|
1474
|
+
|
1475
|
+
free(betaPath->expressions);
|
1476
|
+
free(betaPath->parents);
|
1477
|
+
free(betaPath);
|
1478
|
+
*anyResult = currentAny;
|
1479
|
+
return RULES_OK;
|
1480
|
+
}
|
1481
|
+
|
1482
|
+
static unsigned int fixupQueries(ruleset *tree, unsigned int actionOffset, char* postfix, path *betaPath) {
|
1483
|
+
node *actionNode = &tree->nodePool[actionOffset];
|
1484
|
+
#ifdef _WIN32
|
1485
|
+
char *copyPostfix = (char *)_alloca(sizeof(char)*(strlen(postfix) + 1));
|
1486
|
+
#else
|
1487
|
+
char copyPostfix[strlen(postfix) + 1];
|
1488
|
+
#endif
|
1489
|
+
|
1490
|
+
strcpy(copyPostfix, postfix);
|
1491
|
+
|
1492
|
+
any *query;
|
1493
|
+
unsigned int result = createQueries(tree, copyPostfix, betaPath, &query);
|
1494
|
+
if (result != RULES_OK) {
|
1495
|
+
return result;
|
1496
|
+
}
|
1497
|
+
|
1498
|
+
actionNode->value.c.joinsLength = query->nodesLength;
|
1499
|
+
result = allocateNext(tree, query->nodesLength, &actionNode->value.c.joinsOffset);
|
1500
|
+
if (result != RULES_OK) {
|
1501
|
+
return result;
|
1502
|
+
}
|
1503
|
+
|
1504
|
+
for (unsigned int i = 0; i < query->nodesLength; ++i) {
|
1505
|
+
all *currentAll = query->nodes[i];
|
1506
|
+
|
1507
|
+
join *newJoin;
|
1508
|
+
result = storeJoin(tree, &newJoin, &tree->nextPool[actionNode->value.c.joinsOffset + i]);
|
1509
|
+
if (result != RULES_OK) {
|
1510
|
+
return result;
|
1511
|
+
}
|
1512
|
+
|
1513
|
+
newJoin->expressionsLength = currentAll->expressionsLength;
|
1514
|
+
result = allocateNext(tree, currentAll->expressionsLength, &newJoin->expressionsOffset);
|
1515
|
+
if (result != RULES_OK) {
|
1516
|
+
return result;
|
1517
|
+
}
|
1518
|
+
|
1519
|
+
for (unsigned int ii = 0; ii < currentAll->expressionsLength; ++ii) {
|
1520
|
+
tree->nextPool[newJoin->expressionsOffset + ii] = currentAll->expressions[ii];
|
1521
|
+
}
|
1522
|
+
|
1523
|
+
free(currentAll->expressions);
|
1524
|
+
free(currentAll);
|
1525
|
+
}
|
1526
|
+
|
1527
|
+
free(query->nodes);
|
1528
|
+
free(query);
|
1529
|
+
return RULES_OK;
|
1530
|
+
}
|
1531
|
+
|
1532
|
+
static unsigned int createTree(ruleset *tree, char *rules) {
|
1533
|
+
char *first;
|
1534
|
+
char *last;
|
1535
|
+
char *lastRuleValue;
|
1536
|
+
char *firstName;
|
1537
|
+
char *lastName;
|
1538
|
+
unsigned char type;
|
1539
|
+
unsigned int hash;
|
1540
|
+
unsigned int result = readNextName(rules, &firstName, &lastName, &hash);
|
1541
|
+
while (result == PARSE_OK) {
|
1542
|
+
path *betaPath = NULL;
|
1543
|
+
node *ruleAction;
|
1544
|
+
unsigned int actionOffset;
|
1545
|
+
result = storeNode(tree, &ruleAction, &actionOffset);
|
1546
|
+
if (result != RULES_OK) {
|
1547
|
+
return result;
|
1548
|
+
}
|
1549
|
+
|
1550
|
+
ruleAction->value.c.index = tree->actionCount;
|
1551
|
+
++tree->actionCount;
|
1552
|
+
ruleAction->type = NODE_ACTION;
|
1553
|
+
|
1554
|
+
// tree->stringPool can change after storing strings
|
1555
|
+
// need to resolve namespace every time it is used.
|
1556
|
+
char *namespace = &tree->stringPool[tree->nameOffset];
|
1557
|
+
int namespaceLength = strlen(namespace);
|
1558
|
+
#ifdef _WIN32
|
1559
|
+
char *runtimeActionName = (char *)_alloca(sizeof(char)*(namespaceLength + lastName - firstName + 2));
|
1560
|
+
#else
|
1561
|
+
char runtimeActionName[namespaceLength + lastName - firstName + 2];
|
1562
|
+
#endif
|
1563
|
+
|
1564
|
+
strncpy(runtimeActionName, firstName, lastName - firstName);
|
1565
|
+
runtimeActionName[lastName - firstName] = '!';
|
1566
|
+
strncpy(&runtimeActionName[lastName - firstName + 1], namespace, namespaceLength);
|
1567
|
+
runtimeActionName[namespaceLength + lastName - firstName + 1] = '\0';
|
1568
|
+
result = storeString(tree, runtimeActionName, &ruleAction->nameOffset, namespaceLength + lastName - firstName + 1);
|
1569
|
+
if (result != RULES_OK) {
|
1570
|
+
return result;
|
1571
|
+
}
|
1572
|
+
|
1573
|
+
readNextValue(lastName, &first, &lastRuleValue, &type);
|
1574
|
+
ruleAction->value.c.priority = 0;
|
1575
|
+
ruleAction->value.c.count = 0;
|
1576
|
+
ruleAction->value.c.span = 0;
|
1577
|
+
ruleAction->value.c.cap = 0;
|
1578
|
+
ruleAction->value.c.partitionBy = 0;
|
1579
|
+
getSetting(HASH_PRI, first, &ruleAction->value.c.priority);
|
1580
|
+
getSetting(HASH_COUNT, first, &ruleAction->value.c.count);
|
1581
|
+
getSetting(HASH_SPAN, first, &ruleAction->value.c.span);
|
1582
|
+
getSetting(HASH_CAP, first, &ruleAction->value.c.cap);
|
1583
|
+
getSymbolSetting(HASH_BY, first, &ruleAction->value.c.partitionBy);
|
1584
|
+
if (!ruleAction->value.c.count && !ruleAction->value.c.span && !ruleAction->value.c.cap) {
|
1585
|
+
ruleAction->value.c.count = 1;
|
1586
|
+
}
|
1587
|
+
|
1588
|
+
result = readNextName(first, &first, &last, &hash);
|
1589
|
+
while (result == PARSE_OK) {
|
1590
|
+
readNextValue(last, &first, &last, &type);
|
1591
|
+
switch (hash) {
|
1592
|
+
case HASH_ANY:
|
1593
|
+
result = createBeta(tree, first, OP_ANY, actionOffset, NULL, &betaPath);
|
1594
|
+
break;
|
1595
|
+
case HASH_ALL:
|
1596
|
+
result = createBeta(tree, first, OP_ALL, actionOffset, NULL, &betaPath);
|
1597
|
+
break;
|
1598
|
+
}
|
1599
|
+
result = readNextName(last, &first, &last, &hash);
|
1600
|
+
}
|
1601
|
+
|
1602
|
+
result = fixupQueries(tree, actionOffset, runtimeActionName, betaPath);
|
1603
|
+
if (result != RULES_OK) {
|
1604
|
+
return result;
|
1605
|
+
}
|
1606
|
+
|
1607
|
+
result = readNextName(lastRuleValue, &firstName, &lastName, &hash);
|
1608
|
+
}
|
1609
|
+
|
1610
|
+
return RULES_OK;
|
1611
|
+
}
|
1612
|
+
|
1613
|
+
unsigned int createRuleset(void **handle, char *name, char *rules, unsigned int stateCaheSize) {
|
1614
|
+
node *newNode;
|
1615
|
+
unsigned int stringOffset;
|
1616
|
+
unsigned int nodeOffset;
|
1617
|
+
unsigned int result = validateRuleset(rules);
|
1618
|
+
if (result != PARSE_OK) {
|
1619
|
+
return result;
|
1620
|
+
}
|
1621
|
+
|
1622
|
+
ruleset *tree = malloc(sizeof(ruleset));
|
1623
|
+
if (!tree) {
|
1624
|
+
return ERR_OUT_OF_MEMORY;
|
1625
|
+
}
|
1626
|
+
|
1627
|
+
tree->stringPool = NULL;
|
1628
|
+
tree->stringPoolLength = 0;
|
1629
|
+
tree->nodePool = NULL;
|
1630
|
+
tree->nodeOffset = 0;
|
1631
|
+
tree->nextPool = NULL;
|
1632
|
+
tree->nextOffset = 0;
|
1633
|
+
tree->expressionPool = NULL;
|
1634
|
+
tree->expressionOffset = 0;
|
1635
|
+
tree->idiomPool = NULL;
|
1636
|
+
tree->idiomOffset = 0;
|
1637
|
+
tree->joinPool = NULL;
|
1638
|
+
tree->joinOffset = 0;
|
1639
|
+
tree->actionCount = 0;
|
1640
|
+
tree->bindingsList = NULL;
|
1641
|
+
tree->stateLength = 0;
|
1642
|
+
tree->state = calloc(stateCaheSize, sizeof(stateEntry));
|
1643
|
+
tree->maxStateLength = stateCaheSize;
|
1644
|
+
tree->stateBucketsLength = stateCaheSize / 4;
|
1645
|
+
tree->stateBuckets = malloc(tree->stateBucketsLength * sizeof(unsigned int));
|
1646
|
+
memset(tree->stateBuckets, 0xFF, tree->stateBucketsLength * sizeof(unsigned int));
|
1647
|
+
tree->lruStateOffset = UNDEFINED_HASH_OFFSET;
|
1648
|
+
tree->mruStateOffset = UNDEFINED_HASH_OFFSET;
|
1649
|
+
|
1650
|
+
result = storeString(tree, name, &tree->nameOffset, strlen(name));
|
1651
|
+
if (result != RULES_OK) {
|
1652
|
+
return result;
|
1653
|
+
}
|
1654
|
+
|
1655
|
+
result = storeString(tree, "m", &stringOffset, 1);
|
1656
|
+
if (result != RULES_OK) {
|
1657
|
+
return result;
|
1658
|
+
}
|
1659
|
+
|
1660
|
+
result = storeAlpha(tree, &newNode, &nodeOffset);
|
1661
|
+
if (result != RULES_OK) {
|
1662
|
+
return result;
|
1663
|
+
}
|
1664
|
+
|
1665
|
+
newNode->nameOffset = stringOffset;
|
1666
|
+
newNode->type = NODE_ALPHA;
|
1667
|
+
newNode->value.a.operator = OP_TYPE;
|
1668
|
+
result = storeAlpha(tree, &newNode, &tree->andNodeOffset);
|
1669
|
+
if (result != RULES_OK) {
|
1670
|
+
return result;
|
1671
|
+
}
|
1672
|
+
|
1673
|
+
newNode->nameOffset = 0;
|
1674
|
+
newNode->type = NODE_ALPHA;
|
1675
|
+
newNode->value.a.operator = OP_AND;
|
1676
|
+
result = storeAlpha(tree, &newNode, &tree->orNodeOffset);
|
1677
|
+
if (result != RULES_OK) {
|
1678
|
+
return result;
|
1679
|
+
}
|
1680
|
+
|
1681
|
+
newNode->nameOffset = 0;
|
1682
|
+
newNode->type = NODE_ALPHA;
|
1683
|
+
newNode->value.a.operator = OP_OR;
|
1684
|
+
result = storeAlpha(tree, &newNode, &tree->endNodeOffset);
|
1685
|
+
if (result != RULES_OK) {
|
1686
|
+
return result;
|
1687
|
+
}
|
1688
|
+
|
1689
|
+
newNode->nameOffset = 0;
|
1690
|
+
newNode->type = NODE_ALPHA;
|
1691
|
+
newNode->value.a.operator = OP_END;
|
1692
|
+
|
1693
|
+
*handle = tree;
|
1694
|
+
|
1695
|
+
// will use random numbers for state stored event mids
|
1696
|
+
srand(time(NULL));
|
1697
|
+
return createTree(tree, rules);
|
1698
|
+
}
|
1699
|
+
|
1700
|
+
unsigned int deleteRuleset(void *handle) {
|
1701
|
+
ruleset *tree = (ruleset*)(handle);
|
1702
|
+
deleteBindingsList(tree);
|
1703
|
+
free(tree->nodePool);
|
1704
|
+
free(tree->nextPool);
|
1705
|
+
free(tree->stringPool);
|
1706
|
+
free(tree->expressionPool);
|
1707
|
+
free(tree->idiomPool);
|
1708
|
+
free(tree->joinPool);
|
1709
|
+
free(tree->stateBuckets);
|
1710
|
+
for (unsigned int i = 0; i < tree->stateLength; ++i) {
|
1711
|
+
stateEntry *entry = &tree->state[i];
|
1712
|
+
if (entry->state) {
|
1713
|
+
free(entry->state);
|
1714
|
+
}
|
1715
|
+
|
1716
|
+
if (entry->sid) {
|
1717
|
+
free(entry->sid);
|
1718
|
+
}
|
1719
|
+
}
|
1720
|
+
free(tree->state);
|
1721
|
+
free(tree);
|
1722
|
+
return RULES_OK;
|
1723
|
+
}
|
1724
|
+
|
1725
|
+
|
1726
|
+
|