/src/pigeonhole/src/lib-sieve/sieve-ast.c
Line | Count | Source |
1 | | /* Copyright (c) Pigeonhole authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "str.h" |
5 | | #include "mempool.h" |
6 | | #include "array.h" |
7 | | |
8 | | #include "sieve-common.h" |
9 | | #include "sieve-script.h" |
10 | | #include "sieve-extensions.h" |
11 | | |
12 | | #include "sieve-ast.h" |
13 | | |
14 | | #include <stdio.h> |
15 | | |
16 | | /* |
17 | | * Forward declarations |
18 | | */ |
19 | | |
20 | | static struct sieve_ast_node * |
21 | | sieve_ast_node_create(struct sieve_ast *ast, struct sieve_ast_node *parent, |
22 | | enum sieve_ast_type type, unsigned int source_line); |
23 | | |
24 | | /* |
25 | | * Types |
26 | | */ |
27 | | |
28 | | /* Extensions to the AST */ |
29 | | |
30 | | struct sieve_ast_extension_reg { |
31 | | const struct sieve_extension *ext; |
32 | | const struct sieve_ast_extension *ast_ext; |
33 | | void *context; |
34 | | |
35 | | bool required:1; |
36 | | }; |
37 | | |
38 | | /* |
39 | | * AST object |
40 | | */ |
41 | | |
42 | | struct sieve_ast { |
43 | | pool_t pool; |
44 | | int refcount; |
45 | | |
46 | | struct sieve_instance *svinst; |
47 | | |
48 | | struct sieve_script *script; |
49 | | |
50 | | struct sieve_ast_node *root; |
51 | | |
52 | | ARRAY(const struct sieve_extension *) linked_extensions; |
53 | | ARRAY(struct sieve_ast_extension_reg) extensions; |
54 | | }; |
55 | | |
56 | | struct sieve_ast *sieve_ast_create(struct sieve_script *script) |
57 | 0 | { |
58 | 0 | pool_t pool; |
59 | 0 | struct sieve_ast *ast; |
60 | 0 | unsigned int ext_count; |
61 | |
|
62 | 0 | pool = pool_alloconly_create("sieve_ast", 32768); |
63 | 0 | ast = p_new(pool, struct sieve_ast, 1); |
64 | 0 | ast->pool = pool; |
65 | 0 | ast->refcount = 1; |
66 | |
|
67 | 0 | ast->script = script; |
68 | 0 | sieve_script_ref(script); |
69 | 0 | ast->svinst = sieve_script_svinst(script); |
70 | |
|
71 | 0 | ast->root = sieve_ast_node_create(ast, NULL, SAT_ROOT, 0); |
72 | 0 | ast->root->identifier = "ROOT"; |
73 | |
|
74 | 0 | ext_count = sieve_extensions_get_count(ast->svinst); |
75 | 0 | p_array_init(&ast->linked_extensions, pool, ext_count); |
76 | 0 | p_array_init(&ast->extensions, pool, ext_count); |
77 | |
|
78 | 0 | return ast; |
79 | 0 | } |
80 | | |
81 | | void sieve_ast_ref(struct sieve_ast *ast) |
82 | 0 | { |
83 | 0 | ast->refcount++; |
84 | 0 | } |
85 | | |
86 | | void sieve_ast_unref(struct sieve_ast **ast) |
87 | 0 | { |
88 | 0 | unsigned int i, ext_count; |
89 | 0 | const struct sieve_ast_extension_reg *extrs; |
90 | |
|
91 | 0 | i_assert((*ast)->refcount > 0); |
92 | | |
93 | 0 | if (--(*ast)->refcount != 0) |
94 | 0 | return; |
95 | | |
96 | | /* Release script reference */ |
97 | 0 | sieve_script_unref(&(*ast)->script); |
98 | | |
99 | | /* Signal registered extensions that the AST is being destroyed */ |
100 | 0 | extrs = array_get(&(*ast)->extensions, &ext_count); |
101 | 0 | for (i = 0; i < ext_count; i++) { |
102 | 0 | if (extrs[i].ast_ext != NULL && extrs[i].ast_ext->free != NULL) |
103 | 0 | extrs[i].ast_ext->free(extrs[i].ext, *ast, |
104 | 0 | extrs[i].context); |
105 | 0 | } |
106 | | |
107 | | /* Destroy AST */ |
108 | 0 | pool_unref(&(*ast)->pool); |
109 | |
|
110 | 0 | *ast = NULL; |
111 | 0 | } |
112 | | |
113 | | struct sieve_ast_node *sieve_ast_root(struct sieve_ast *ast) |
114 | 0 | { |
115 | 0 | return ast->root; |
116 | 0 | } |
117 | | |
118 | | pool_t sieve_ast_pool(struct sieve_ast *ast) |
119 | 0 | { |
120 | 0 | return ast->pool; |
121 | 0 | } |
122 | | |
123 | | struct sieve_script *sieve_ast_script(struct sieve_ast *ast) |
124 | 0 | { |
125 | 0 | return ast->script; |
126 | 0 | } |
127 | | |
128 | | /* |
129 | | * Extension support |
130 | | */ |
131 | | |
132 | | void sieve_ast_extension_link(struct sieve_ast *ast, |
133 | | const struct sieve_extension *ext, bool required) |
134 | 0 | { |
135 | 0 | unsigned int i, ext_count; |
136 | 0 | const struct sieve_extension *const *extensions; |
137 | 0 | struct sieve_ast_extension_reg *reg; |
138 | |
|
139 | 0 | if (ext->id < 0) |
140 | 0 | return; |
141 | | |
142 | | /* Initialize registration */ |
143 | 0 | reg = array_idx_get_space(&ast->extensions, (unsigned int)ext->id); |
144 | 0 | i_assert(reg->ext == NULL || reg->ext == ext); |
145 | 0 | reg->ext = ext; |
146 | 0 | reg->required = reg->required || required; |
147 | | |
148 | | /* Prevent duplicates */ |
149 | 0 | extensions = array_get(&ast->linked_extensions, &ext_count); |
150 | 0 | for (i = 0; i < ext_count; i++) { |
151 | 0 | if (extensions[i] == ext) |
152 | 0 | return; |
153 | 0 | } |
154 | | |
155 | | /* Add extension */ |
156 | 0 | array_append(&ast->linked_extensions, &ext, 1); |
157 | 0 | } |
158 | | |
159 | | const struct sieve_extension *const * |
160 | | sieve_ast_extensions_get(struct sieve_ast *ast, unsigned int *count_r) |
161 | 0 | { |
162 | 0 | return array_get(&ast->linked_extensions, count_r); |
163 | 0 | } |
164 | | |
165 | | void sieve_ast_extension_register(struct sieve_ast *ast, |
166 | | const struct sieve_extension *ext, |
167 | | const struct sieve_ast_extension *ast_ext, |
168 | | void *context) |
169 | 0 | { |
170 | 0 | struct sieve_ast_extension_reg *reg; |
171 | |
|
172 | 0 | if (ext->id < 0) |
173 | 0 | return; |
174 | | |
175 | | /* Initialize registration */ |
176 | 0 | reg = array_idx_get_space(&ast->extensions, (unsigned int)ext->id); |
177 | 0 | i_assert(reg->ext == NULL || reg->ext == ext); |
178 | 0 | reg->ext = ext; |
179 | 0 | reg->ast_ext = ast_ext; |
180 | 0 | reg->context = context; |
181 | 0 | } |
182 | | |
183 | | void sieve_ast_extension_set_context(struct sieve_ast *ast, |
184 | | const struct sieve_extension *ext, |
185 | | void *context) |
186 | 0 | { |
187 | 0 | struct sieve_ast_extension_reg *reg; |
188 | |
|
189 | 0 | if (ext->id < 0) |
190 | 0 | return; |
191 | | |
192 | 0 | reg = array_idx_get_space(&ast->extensions, (unsigned int)ext->id); |
193 | 0 | reg->context = context; |
194 | 0 | } |
195 | | |
196 | | void *sieve_ast_extension_get_context(struct sieve_ast *ast, |
197 | | const struct sieve_extension *ext) |
198 | 0 | { |
199 | 0 | const struct sieve_ast_extension_reg *reg; |
200 | |
|
201 | 0 | if (ext->id < 0 || ext->id >= (int)array_count(&ast->extensions)) |
202 | 0 | return NULL; |
203 | | |
204 | 0 | reg = array_idx(&ast->extensions, (unsigned int)ext->id); |
205 | |
|
206 | 0 | return reg->context; |
207 | 0 | } |
208 | | |
209 | | bool sieve_ast_extension_is_required |
210 | | (struct sieve_ast *ast, const struct sieve_extension *ext) |
211 | 0 | { |
212 | 0 | const struct sieve_ast_extension_reg *reg; |
213 | |
|
214 | 0 | i_assert(ext->id >= 0 && |
215 | 0 | ext->id < (int)array_count(&ast->extensions)); |
216 | | |
217 | 0 | reg = array_idx(&ast->extensions, (unsigned int)ext->id); |
218 | 0 | return reg->required; |
219 | 0 | } |
220 | | |
221 | | /* |
222 | | * AST list implementations |
223 | | */ |
224 | | |
225 | | /* Very simplistic linked list implementation |
226 | | FIXME: Merge with core |
227 | | */ |
228 | 0 | #define __LIST_CREATE(pool, type) { \ |
229 | 0 | type *list = p_new(pool, type, 1); \ |
230 | 0 | list->head = NULL; \ |
231 | 0 | list->tail = NULL; \ |
232 | 0 | list->len = 0; \ |
233 | 0 | return list; \ |
234 | 0 | } |
235 | | |
236 | 0 | #define __LIST_ADD(list, node) { \ |
237 | 0 | if (list->len + 1 < list->len) \ |
238 | 0 | return FALSE; \ |
239 | 0 | \ |
240 | 0 | node->next = NULL; \ |
241 | 0 | if (list->head == NULL) { \ |
242 | 0 | node->prev = NULL; \ |
243 | 0 | list->head = node; \ |
244 | 0 | list->tail = node; \ |
245 | 0 | } else { \ |
246 | 0 | list->tail->next = node; \ |
247 | 0 | node->prev = list->tail; \ |
248 | 0 | list->tail = node; \ |
249 | 0 | } \ |
250 | 0 | list->len++; \ |
251 | 0 | node->list = list; \ |
252 | 0 | return TRUE; \ |
253 | 0 | } |
254 | | |
255 | 0 | #define __LIST_INSERT(list, before, node) { \ |
256 | 0 | if (list->len + 1 < list->len) \ |
257 | 0 | return FALSE; \ |
258 | 0 | \ |
259 | 0 | node->next = before; \ |
260 | 0 | if (list->head == before) { \ |
261 | 0 | node->prev = NULL; \ |
262 | 0 | list->head = node; \ |
263 | 0 | } else if (before->prev != NULL) { \ |
264 | 0 | before->prev->next = node; \ |
265 | 0 | } \ |
266 | 0 | node->prev = before->prev; \ |
267 | 0 | before->prev = node; \ |
268 | 0 | list->len++; \ |
269 | 0 | node->list = list; \ |
270 | 0 | \ |
271 | 0 | return TRUE; \ |
272 | 0 | } |
273 | | |
274 | 0 | #define __LIST_JOIN(list, node_type, items) { \ |
275 | 0 | node_type *node; \ |
276 | 0 | \ |
277 | 0 | if (list->len + items->len < list->len) \ |
278 | 0 | return FALSE; \ |
279 | 0 | \ |
280 | 0 | if (items->len == 0) \ |
281 | 0 | return TRUE; \ |
282 | 0 | i_assert(items->head != NULL); \ |
283 | 0 | \ |
284 | 0 | if (list->head == NULL) { \ |
285 | 0 | list->head = items->head; \ |
286 | 0 | list->tail = items->tail; \ |
287 | 0 | } else { \ |
288 | 0 | list->tail->next = items->head; \ |
289 | 0 | items->head->prev = list->tail; \ |
290 | 0 | list->tail = items->tail; \ |
291 | 0 | } \ |
292 | 0 | list->len += items->len; \ |
293 | 0 | \ |
294 | 0 | node = items->head; \ |
295 | 0 | while (node != NULL) { \ |
296 | 0 | node->list = list; \ |
297 | 0 | node = node->next; \ |
298 | 0 | } \ |
299 | 0 | return TRUE; \ |
300 | 0 | } |
301 | | |
302 | 0 | #define __LIST_DETACH(first, node_type, count) { \ |
303 | 0 | node_type *last, *result; \ |
304 | 0 | unsigned int left; \ |
305 | 0 | \ |
306 | 0 | i_assert(first->list != NULL); \ |
307 | 0 | \ |
308 | 0 | left = count - 1; \ |
309 | 0 | last = first; \ |
310 | 0 | while (left > 0 && last->next != NULL) { \ |
311 | 0 | left--; \ |
312 | 0 | last = last->next; \ |
313 | 0 | } \ |
314 | 0 | \ |
315 | 0 | if (first->list->head == first) \ |
316 | 0 | first->list->head = last->next; \ |
317 | 0 | if (first->list->tail == last) \ |
318 | 0 | first->list->tail = first->prev; \ |
319 | 0 | \ |
320 | 0 | if (first->prev != NULL) \ |
321 | 0 | first->prev->next = last->next; \ |
322 | 0 | if (last->next != NULL) \ |
323 | 0 | last->next->prev = first->prev; \ |
324 | 0 | \ |
325 | 0 | first->list->len -= count - left; \ |
326 | 0 | \ |
327 | 0 | result = last->next; \ |
328 | 0 | first->prev = NULL; \ |
329 | 0 | last->next = NULL; \ |
330 | 0 | \ |
331 | 0 | return result; \ |
332 | 0 | } |
333 | | |
334 | | /* List of AST nodes */ |
335 | | |
336 | | static struct sieve_ast_list * |
337 | | sieve_ast_list_create(pool_t pool) |
338 | 0 | __LIST_CREATE(pool, struct sieve_ast_list) |
339 | | |
340 | | static bool |
341 | | sieve_ast_list_add(struct sieve_ast_list *list, struct sieve_ast_node *node) |
342 | 0 | __LIST_ADD(list, node) |
343 | | |
344 | | static struct sieve_ast_node * |
345 | | sieve_ast_list_detach(struct sieve_ast_node *first, unsigned int count) |
346 | 0 | __LIST_DETACH(first, struct sieve_ast_node, count) |
347 | | |
348 | | /* List of argument AST nodes */ |
349 | | |
350 | | struct sieve_ast_arg_list *sieve_ast_arg_list_create(pool_t pool) |
351 | 0 | __LIST_CREATE(pool, struct sieve_ast_arg_list) |
352 | | |
353 | | bool sieve_ast_arg_list_add(struct sieve_ast_arg_list *list, |
354 | | struct sieve_ast_argument *argument) |
355 | 0 | __LIST_ADD(list, argument) |
356 | | |
357 | | bool sieve_ast_arg_list_insert(struct sieve_ast_arg_list *list, |
358 | | struct sieve_ast_argument *before, |
359 | | struct sieve_ast_argument *argument) |
360 | 0 | __LIST_INSERT(list, before, argument) |
361 | | |
362 | | static bool |
363 | | sieve_ast_arg_list_join(struct sieve_ast_arg_list *list, |
364 | | struct sieve_ast_arg_list *items) |
365 | 0 | __LIST_JOIN(list, struct sieve_ast_argument, items) |
366 | | |
367 | | static struct sieve_ast_argument * |
368 | | sieve_ast_arg_list_detach(struct sieve_ast_argument *first, |
369 | | const unsigned int count) |
370 | 0 | __LIST_DETACH(first, struct sieve_ast_argument, count) |
371 | | |
372 | | void sieve_ast_arg_list_substitute(struct sieve_ast_arg_list *list, |
373 | | struct sieve_ast_argument *argument, |
374 | | struct sieve_ast_argument *replacement) |
375 | 0 | { |
376 | 0 | if (list->head == argument) |
377 | 0 | list->head = replacement; |
378 | 0 | if (list->tail == argument) |
379 | 0 | list->tail = replacement; |
380 | |
|
381 | 0 | if (argument->prev != NULL) |
382 | 0 | argument->prev->next = replacement; |
383 | 0 | if (argument->next != NULL) |
384 | 0 | argument->next->prev = replacement; |
385 | |
|
386 | 0 | replacement->prev = argument->prev; |
387 | 0 | replacement->next = argument->next; |
388 | 0 | replacement->list = argument->list; |
389 | |
|
390 | 0 | argument->next = NULL; |
391 | 0 | argument->prev = NULL; |
392 | 0 | } |
393 | | |
394 | | /* |
395 | | * AST node |
396 | | */ |
397 | | |
398 | | static struct sieve_ast_node * |
399 | | sieve_ast_node_create(struct sieve_ast *ast, struct sieve_ast_node *parent, |
400 | | enum sieve_ast_type type, unsigned int source_line) |
401 | 0 | { |
402 | 0 | struct sieve_ast_node *node = |
403 | 0 | p_new(ast->pool, struct sieve_ast_node, 1); |
404 | |
|
405 | 0 | node->ast = ast; |
406 | 0 | node->parent = parent; |
407 | 0 | node->type = type; |
408 | |
|
409 | 0 | node->prev = NULL; |
410 | 0 | node->next = NULL; |
411 | |
|
412 | 0 | node->arguments = NULL; |
413 | 0 | node->tests = NULL; |
414 | 0 | node->commands = NULL; |
415 | |
|
416 | 0 | node->test_list = FALSE; |
417 | 0 | node->block = FALSE; |
418 | |
|
419 | 0 | node->source_line = source_line; |
420 | |
|
421 | 0 | return node; |
422 | 0 | } |
423 | | |
424 | | static bool |
425 | | sieve_ast_node_add_command(struct sieve_ast_node *node, |
426 | | struct sieve_ast_node *command) |
427 | 0 | { |
428 | 0 | i_assert(command->type == SAT_COMMAND && |
429 | 0 | (node->type == SAT_ROOT || node->type == SAT_COMMAND)); |
430 | | |
431 | 0 | if (node->commands == NULL) |
432 | 0 | node->commands = sieve_ast_list_create(node->ast->pool); |
433 | |
|
434 | 0 | return sieve_ast_list_add(node->commands, command); |
435 | 0 | } |
436 | | |
437 | | static bool |
438 | | sieve_ast_node_add_test(struct sieve_ast_node *node, |
439 | | struct sieve_ast_node *test) |
440 | 0 | { |
441 | 0 | i_assert(test->type == SAT_TEST && |
442 | 0 | (node->type == SAT_TEST || node->type == SAT_COMMAND)); |
443 | | |
444 | 0 | if (node->tests == NULL) |
445 | 0 | node->tests = sieve_ast_list_create(node->ast->pool); |
446 | |
|
447 | 0 | return sieve_ast_list_add(node->tests, test); |
448 | 0 | } |
449 | | |
450 | | static bool |
451 | | sieve_ast_node_add_argument(struct sieve_ast_node *node, |
452 | | struct sieve_ast_argument *argument) |
453 | 0 | { |
454 | 0 | i_assert(node->type == SAT_TEST || node->type == SAT_COMMAND); |
455 | | |
456 | 0 | if (node->arguments == NULL) |
457 | 0 | node->arguments = sieve_ast_arg_list_create(node->ast->pool); |
458 | |
|
459 | 0 | return sieve_ast_arg_list_add(node->arguments, argument); |
460 | 0 | } |
461 | | |
462 | | struct sieve_ast_node *sieve_ast_node_detach(struct sieve_ast_node *first) |
463 | 0 | { |
464 | 0 | return sieve_ast_list_detach(first, 1); |
465 | 0 | } |
466 | | |
467 | | const char *sieve_ast_type_name(enum sieve_ast_type ast_type) |
468 | 0 | { |
469 | 0 | switch (ast_type) { |
470 | 0 | case SAT_NONE: |
471 | 0 | return "none"; |
472 | 0 | case SAT_ROOT: |
473 | 0 | return "ast root node"; |
474 | 0 | case SAT_COMMAND: |
475 | 0 | return "command"; |
476 | 0 | case SAT_TEST: |
477 | 0 | return "test"; |
478 | 0 | default: |
479 | 0 | return "??AST NODE??"; |
480 | 0 | } |
481 | 0 | } |
482 | | |
483 | | /* |
484 | | * Argument AST node |
485 | | */ |
486 | | |
487 | | struct sieve_ast_argument * |
488 | | sieve_ast_argument_create(struct sieve_ast *ast, unsigned int source_line) |
489 | 0 | { |
490 | 0 | struct sieve_ast_argument *arg = |
491 | 0 | p_new(ast->pool, struct sieve_ast_argument, 1); |
492 | |
|
493 | 0 | arg->ast = ast; |
494 | |
|
495 | 0 | arg->prev = NULL; |
496 | 0 | arg->next = NULL; |
497 | |
|
498 | 0 | arg->source_line = source_line; |
499 | |
|
500 | 0 | arg->argument = NULL; |
501 | |
|
502 | 0 | return arg; |
503 | 0 | } |
504 | | |
505 | | static void |
506 | | sieve_ast_argument_substitute(struct sieve_ast_argument *argument, |
507 | | struct sieve_ast_argument *replacement) |
508 | 0 | { |
509 | 0 | sieve_ast_arg_list_substitute(argument->list, argument, replacement); |
510 | 0 | } |
511 | | |
512 | | struct sieve_ast_argument * |
513 | | sieve_ast_argument_string_create_raw(struct sieve_ast *ast, string_t *str, |
514 | | unsigned int source_line) |
515 | 0 | { |
516 | 0 | struct sieve_ast_argument *argument = |
517 | 0 | sieve_ast_argument_create(ast, source_line); |
518 | |
|
519 | 0 | argument->type = SAAT_STRING; |
520 | 0 | argument->_value.str = str; |
521 | |
|
522 | 0 | return argument; |
523 | 0 | } |
524 | | |
525 | | struct sieve_ast_argument * |
526 | | sieve_ast_argument_string_create(struct sieve_ast_node *node, |
527 | | const string_t *str, unsigned int source_line) |
528 | 0 | { |
529 | 0 | struct sieve_ast_argument *argument; |
530 | 0 | string_t *newstr; |
531 | | |
532 | | /* Allocate new internal string buffer */ |
533 | 0 | newstr = str_new(node->ast->pool, str_len(str)); |
534 | | |
535 | | /* Clone string */ |
536 | 0 | str_append_str(newstr, str); |
537 | | |
538 | | /* Create string argument */ |
539 | 0 | argument = sieve_ast_argument_string_create_raw( |
540 | 0 | node->ast, newstr, source_line); |
541 | | |
542 | | /* Add argument to command/test node */ |
543 | 0 | sieve_ast_node_add_argument(node, argument); |
544 | |
|
545 | 0 | return argument; |
546 | 0 | } |
547 | | |
548 | | struct sieve_ast_argument * |
549 | | sieve_ast_argument_cstring_create(struct sieve_ast_node *node, const char *str, |
550 | | unsigned int source_line) |
551 | 0 | { |
552 | 0 | struct sieve_ast_argument *argument; |
553 | 0 | string_t *newstr; |
554 | | |
555 | | /* Allocate new internal string buffer */ |
556 | 0 | newstr = str_new(node->ast->pool, strlen(str)); |
557 | | |
558 | | /* Clone string */ |
559 | 0 | str_append(newstr, str); |
560 | | |
561 | | /* Create string argument */ |
562 | 0 | argument = sieve_ast_argument_string_create_raw( |
563 | 0 | node->ast, newstr, source_line); |
564 | | |
565 | | /* Add argument to command/test node */ |
566 | 0 | sieve_ast_node_add_argument(node, argument); |
567 | |
|
568 | 0 | return argument; |
569 | 0 | } |
570 | | |
571 | | void sieve_ast_argument_string_set(struct sieve_ast_argument *argument, |
572 | | string_t *newstr) |
573 | 0 | { |
574 | 0 | i_assert(argument->type == SAAT_STRING); |
575 | 0 | argument->_value.str = newstr; |
576 | 0 | } |
577 | | |
578 | | void sieve_ast_argument_string_setc(struct sieve_ast_argument *argument, |
579 | | const char *newstr) |
580 | 0 | { |
581 | 0 | i_assert(argument->type == SAAT_STRING); |
582 | | |
583 | 0 | str_truncate(argument->_value.str, 0); |
584 | 0 | str_append(argument->_value.str, newstr); |
585 | 0 | } |
586 | | |
587 | | void sieve_ast_argument_number_substitute(struct sieve_ast_argument *argument, |
588 | | sieve_number_t number) |
589 | 0 | { |
590 | 0 | argument->type = SAAT_NUMBER; |
591 | 0 | argument->_value.number = number; |
592 | 0 | } |
593 | | |
594 | | struct sieve_ast_argument * |
595 | | sieve_ast_argument_stringlist_create(struct sieve_ast_node *node, |
596 | | unsigned int source_line) |
597 | 0 | { |
598 | 0 | struct sieve_ast_argument *argument = |
599 | 0 | sieve_ast_argument_create(node->ast, source_line); |
600 | |
|
601 | 0 | argument->type = SAAT_STRING_LIST; |
602 | 0 | argument->_value.strlist = NULL; |
603 | |
|
604 | 0 | sieve_ast_node_add_argument(node, argument); |
605 | |
|
606 | 0 | return argument; |
607 | 0 | } |
608 | | |
609 | | struct sieve_ast_argument * |
610 | | sieve_ast_argument_stringlist_substitute(struct sieve_ast_node *node, |
611 | | struct sieve_ast_argument *arg) |
612 | 0 | { |
613 | 0 | struct sieve_ast_argument *argument = |
614 | 0 | sieve_ast_argument_create(node->ast, arg->source_line); |
615 | |
|
616 | 0 | argument->type = SAAT_STRING_LIST; |
617 | 0 | argument->_value.strlist = NULL; |
618 | |
|
619 | 0 | sieve_ast_argument_substitute(arg, argument); |
620 | |
|
621 | 0 | return argument; |
622 | 0 | } |
623 | | |
624 | | static inline bool |
625 | | _sieve_ast_stringlist_add_item(struct sieve_ast_argument *list, |
626 | | struct sieve_ast_argument *item) |
627 | 0 | { |
628 | 0 | i_assert(list->type == SAAT_STRING_LIST); |
629 | | |
630 | 0 | if (list->_value.strlist == NULL) { |
631 | 0 | list->_value.strlist = |
632 | 0 | sieve_ast_arg_list_create(list->ast->pool); |
633 | 0 | } |
634 | |
|
635 | 0 | return sieve_ast_arg_list_add(list->_value.strlist, item); |
636 | 0 | } |
637 | | |
638 | | static bool |
639 | | sieve_ast_stringlist_add_stringlist(struct sieve_ast_argument *list, |
640 | | struct sieve_ast_argument *items) |
641 | 0 | { |
642 | 0 | i_assert(list->type == SAAT_STRING_LIST); |
643 | 0 | i_assert(items->type == SAAT_STRING_LIST); |
644 | | |
645 | 0 | if (items->_value.strlist == NULL) |
646 | 0 | return TRUE; |
647 | 0 | if (list->_value.strlist == NULL) { |
648 | 0 | list->_value.strlist = |
649 | 0 | sieve_ast_arg_list_create(list->ast->pool); |
650 | 0 | } |
651 | |
|
652 | 0 | return sieve_ast_arg_list_join(list->_value.strlist, |
653 | 0 | items->_value.strlist); |
654 | 0 | } |
655 | | |
656 | | static bool |
657 | | _sieve_ast_stringlist_add_str(struct sieve_ast_argument *list, string_t *str, |
658 | | unsigned int source_line) |
659 | 0 | { |
660 | 0 | struct sieve_ast_argument *stritem; |
661 | |
|
662 | 0 | stritem = sieve_ast_argument_create(list->ast, source_line); |
663 | 0 | stritem->type = SAAT_STRING; |
664 | 0 | stritem->_value.str = str; |
665 | |
|
666 | 0 | return _sieve_ast_stringlist_add_item(list, stritem); |
667 | 0 | } |
668 | | |
669 | | bool sieve_ast_stringlist_add(struct sieve_ast_argument *list, |
670 | | const string_t *str, unsigned int source_line) |
671 | 0 | { |
672 | 0 | string_t *copied_str = str_new(list->ast->pool, str_len(str)); |
673 | 0 | str_append_str(copied_str, str); |
674 | |
|
675 | 0 | return _sieve_ast_stringlist_add_str(list, copied_str, source_line); |
676 | 0 | } |
677 | | |
678 | | bool sieve_ast_stringlist_add_strc(struct sieve_ast_argument *list, |
679 | | const char *str, unsigned int source_line) |
680 | 0 | { |
681 | 0 | string_t *copied_str = str_new(list->ast->pool, strlen(str)); |
682 | 0 | str_append(copied_str, str); |
683 | |
|
684 | 0 | return _sieve_ast_stringlist_add_str(list, copied_str, source_line); |
685 | 0 | } |
686 | | |
687 | | struct sieve_ast_argument * |
688 | | sieve_ast_argument_tag_create(struct sieve_ast_node *node, const char *tag, |
689 | | unsigned int source_line) |
690 | 0 | { |
691 | 0 | struct sieve_ast_argument *argument = |
692 | 0 | sieve_ast_argument_create(node->ast, source_line); |
693 | |
|
694 | 0 | argument->type = SAAT_TAG; |
695 | 0 | argument->_value.tag = p_strdup(node->ast->pool, tag); |
696 | |
|
697 | 0 | if (!sieve_ast_node_add_argument(node, argument)) |
698 | 0 | return NULL; |
699 | 0 | return argument; |
700 | 0 | } |
701 | | |
702 | | struct sieve_ast_argument * |
703 | | sieve_ast_argument_tag_insert(struct sieve_ast_argument *before, |
704 | | const char *tag, unsigned int source_line) |
705 | 0 | { |
706 | 0 | struct sieve_ast_argument *argument = |
707 | 0 | sieve_ast_argument_create(before->ast, source_line); |
708 | |
|
709 | 0 | argument->type = SAAT_TAG; |
710 | 0 | argument->_value.tag = p_strdup(before->ast->pool, tag); |
711 | |
|
712 | 0 | if (!sieve_ast_arg_list_insert(before->list, before, argument)) |
713 | 0 | return NULL; |
714 | 0 | return argument; |
715 | 0 | } |
716 | | |
717 | | struct sieve_ast_argument * |
718 | | sieve_ast_argument_number_create(struct sieve_ast_node *node, |
719 | | sieve_number_t number, |
720 | | unsigned int source_line) |
721 | 0 | { |
722 | 0 | struct sieve_ast_argument *argument = |
723 | 0 | sieve_ast_argument_create(node->ast, source_line); |
724 | |
|
725 | 0 | argument->type = SAAT_NUMBER; |
726 | 0 | argument->_value.number = number; |
727 | |
|
728 | 0 | if (!sieve_ast_node_add_argument(node, argument)) |
729 | 0 | return NULL; |
730 | 0 | return argument; |
731 | 0 | } |
732 | | |
733 | | void sieve_ast_argument_number_set(struct sieve_ast_argument *argument, |
734 | | sieve_number_t newnum) |
735 | 0 | { |
736 | 0 | i_assert(argument->type == SAAT_NUMBER); |
737 | 0 | argument->_value.number = newnum; |
738 | 0 | } |
739 | | |
740 | | struct sieve_ast_argument * |
741 | | sieve_ast_arguments_detach(struct sieve_ast_argument *first, |
742 | | unsigned int count) |
743 | 0 | { |
744 | 0 | return sieve_ast_arg_list_detach(first, count); |
745 | 0 | } |
746 | | |
747 | | bool sieve_ast_argument_attach(struct sieve_ast_node *node, |
748 | | struct sieve_ast_argument *argument) |
749 | 0 | { |
750 | 0 | return sieve_ast_node_add_argument(node, argument); |
751 | 0 | } |
752 | | |
753 | | const char *sieve_ast_argument_type_name(enum sieve_ast_argument_type arg_type) |
754 | 0 | { |
755 | 0 | switch (arg_type) { |
756 | 0 | case SAAT_NONE: |
757 | 0 | return "none"; |
758 | 0 | case SAAT_STRING_LIST: |
759 | 0 | return "a string list"; |
760 | 0 | case SAAT_STRING: |
761 | 0 | return "a string"; |
762 | 0 | case SAAT_NUMBER: |
763 | 0 | return "a number"; |
764 | 0 | case SAAT_TAG: |
765 | 0 | return "a tag"; |
766 | 0 | default: |
767 | 0 | return "??ARGUMENT??"; |
768 | 0 | } |
769 | 0 | } |
770 | | |
771 | | /* Test AST node */ |
772 | | |
773 | | struct sieve_ast_node * |
774 | | sieve_ast_test_create(struct sieve_ast_node *parent, const char *identifier, |
775 | | unsigned int source_line) |
776 | 0 | { |
777 | 0 | struct sieve_ast_node *test = sieve_ast_node_create( |
778 | 0 | parent->ast, parent, SAT_TEST, source_line); |
779 | |
|
780 | 0 | test->identifier = p_strdup(parent->ast->pool, identifier); |
781 | |
|
782 | 0 | if (!sieve_ast_node_add_test(parent, test)) |
783 | 0 | return NULL; |
784 | 0 | return test; |
785 | 0 | } |
786 | | |
787 | | /* Command AST node */ |
788 | | |
789 | | struct sieve_ast_node * |
790 | | sieve_ast_command_create(struct sieve_ast_node *parent, const char *identifier, |
791 | | unsigned int source_line) |
792 | 0 | { |
793 | 0 | struct sieve_ast_node *command = sieve_ast_node_create( |
794 | 0 | parent->ast, parent, SAT_COMMAND, source_line); |
795 | |
|
796 | 0 | command->identifier = p_strdup(parent->ast->pool, identifier); |
797 | |
|
798 | 0 | if (!sieve_ast_node_add_command(parent, command)) |
799 | 0 | return NULL; |
800 | 0 | return command; |
801 | 0 | } |
802 | | |
803 | | /* |
804 | | * Utility |
805 | | */ |
806 | | |
807 | | int sieve_ast_stringlist_map( |
808 | | struct sieve_ast_argument **listitem, void *context, |
809 | | int (*map_function)(void *context, struct sieve_ast_argument *arg)) |
810 | 0 | { |
811 | 0 | if (sieve_ast_argument_type(*listitem) == SAAT_STRING) { |
812 | | /* Single string */ |
813 | 0 | return map_function(context, *listitem); |
814 | 0 | } else if (sieve_ast_argument_type(*listitem) == SAAT_STRING_LIST) { |
815 | 0 | int ret = 0; |
816 | | |
817 | | /* String list */ |
818 | 0 | *listitem = sieve_ast_strlist_first(*listitem); |
819 | |
|
820 | 0 | while (*listitem != NULL) { |
821 | 0 | if ((ret = map_function(context, *listitem)) <= 0) |
822 | 0 | return ret; |
823 | | |
824 | 0 | *listitem = sieve_ast_strlist_next(*listitem); |
825 | 0 | } |
826 | | |
827 | 0 | return ret; |
828 | 0 | } |
829 | | |
830 | 0 | i_unreached(); |
831 | 0 | } |
832 | | |
833 | | struct sieve_ast_argument * |
834 | | sieve_ast_stringlist_join(struct sieve_ast_argument *list, |
835 | | struct sieve_ast_argument *items) |
836 | 0 | { |
837 | 0 | enum sieve_ast_argument_type list_type, items_type; |
838 | 0 | struct sieve_ast_argument *newlist; |
839 | |
|
840 | 0 | list_type = sieve_ast_argument_type(list); |
841 | 0 | items_type = sieve_ast_argument_type(items); |
842 | |
|
843 | 0 | switch (list_type) { |
844 | 0 | case SAAT_STRING: |
845 | 0 | switch (items_type) { |
846 | 0 | case SAAT_STRING: |
847 | 0 | newlist = sieve_ast_argument_create( |
848 | 0 | list->ast, list->source_line); |
849 | 0 | newlist->type = SAAT_STRING_LIST; |
850 | 0 | newlist->_value.strlist = NULL; |
851 | |
|
852 | 0 | sieve_ast_argument_substitute(list, newlist); |
853 | 0 | sieve_ast_arguments_detach(items, 1); |
854 | |
|
855 | 0 | if (!_sieve_ast_stringlist_add_item(newlist, list) || |
856 | 0 | !_sieve_ast_stringlist_add_item(newlist, items)) |
857 | 0 | return NULL; |
858 | 0 | return newlist; |
859 | 0 | case SAAT_STRING_LIST: |
860 | | /* Adding stringlist to string; make them swith places |
861 | | and add one to the other. |
862 | | */ |
863 | 0 | sieve_ast_arguments_detach(items, 1); |
864 | 0 | sieve_ast_argument_substitute(list, items); |
865 | 0 | if (!_sieve_ast_stringlist_add_item(items, list)) |
866 | 0 | return NULL; |
867 | 0 | return list; |
868 | 0 | default: |
869 | 0 | i_unreached(); |
870 | 0 | } |
871 | 0 | break; |
872 | 0 | case SAAT_STRING_LIST: |
873 | 0 | switch (items_type) { |
874 | 0 | case SAAT_STRING: |
875 | | /* Adding string to stringlist; straightforward add */ |
876 | 0 | sieve_ast_arguments_detach(items, 1); |
877 | 0 | if (!_sieve_ast_stringlist_add_item(list, items)) |
878 | 0 | return NULL; |
879 | 0 | return list; |
880 | 0 | case SAAT_STRING_LIST: |
881 | | /* Adding stringlist to stringlist; perform actual join |
882 | | */ |
883 | 0 | sieve_ast_arguments_detach(items, 1); |
884 | 0 | if (!sieve_ast_stringlist_add_stringlist(list, items)) |
885 | 0 | return NULL; |
886 | 0 | return list; |
887 | 0 | default: |
888 | 0 | i_unreached(); |
889 | 0 | } |
890 | 0 | break; |
891 | 0 | default: |
892 | 0 | i_unreached(); |
893 | 0 | } |
894 | 0 | return NULL; |
895 | 0 | } |
896 | | |
897 | | /* Debug */ |
898 | | |
899 | | /* Unparsing, currently implemented using plain printf()s */ |
900 | | |
901 | | static void sieve_ast_unparse_string(const string_t *strval) |
902 | 0 | { |
903 | 0 | char *str = t_strdup_noconst(str_c((string_t *)strval)); |
904 | |
|
905 | 0 | if (strchr(str, '\n') != NULL && str[strlen(str)-1] == '\n') { |
906 | | /* Print it as a multi-line string and do required dotstuffing |
907 | | */ |
908 | 0 | char *spos = str; |
909 | 0 | char *epos = strchr(str, '\n'); |
910 | 0 | printf("text:\n"); |
911 | |
|
912 | 0 | while (epos != NULL) { |
913 | 0 | *epos = '\0'; |
914 | 0 | if (*spos == '.') |
915 | 0 | printf("."); |
916 | |
|
917 | 0 | printf("%s\n", spos); |
918 | |
|
919 | 0 | spos = epos+1; |
920 | 0 | epos = strchr(spos, '\n'); |
921 | 0 | } |
922 | 0 | if (*spos == '.') |
923 | 0 | printf("."); |
924 | |
|
925 | 0 | printf("%s\n.\n", spos); |
926 | 0 | } else { |
927 | | /* Print it as a quoted string and escape " */ |
928 | 0 | char *spos = str; |
929 | 0 | char *epos = strchr(str, '"'); |
930 | 0 | printf("\""); |
931 | |
|
932 | 0 | while (epos != NULL) { |
933 | 0 | *epos = '\0'; |
934 | 0 | printf("%s\\\"", spos); |
935 | |
|
936 | 0 | spos = epos+1; |
937 | 0 | epos = strchr(spos, '"'); |
938 | 0 | } |
939 | |
|
940 | 0 | printf("%s\"", spos); |
941 | 0 | } |
942 | 0 | } |
943 | | |
944 | | static void |
945 | | sieve_ast_unparse_argument(struct sieve_ast_argument *argument, int level); |
946 | | |
947 | | static void |
948 | | sieve_ast_unparse_stringlist(struct sieve_ast_argument *strlist, int level) |
949 | 0 | { |
950 | 0 | struct sieve_ast_argument *stritem; |
951 | |
|
952 | 0 | if (sieve_ast_strlist_count(strlist) > 1) { |
953 | 0 | int i; |
954 | |
|
955 | 0 | printf("[\n"); |
956 | | |
957 | | /* Create indent */ |
958 | 0 | for (i = 0; i < level+2; i++) |
959 | 0 | printf(" "); |
960 | |
|
961 | 0 | stritem = sieve_ast_strlist_first(strlist); |
962 | 0 | if (stritem != NULL) { |
963 | 0 | sieve_ast_unparse_string( |
964 | 0 | sieve_ast_strlist_str(stritem)); |
965 | |
|
966 | 0 | stritem = sieve_ast_strlist_next(stritem); |
967 | 0 | while (stritem != NULL) { |
968 | 0 | printf(",\n"); |
969 | 0 | for (i = 0; i < level+2; i++) |
970 | 0 | printf(" "); |
971 | 0 | sieve_ast_unparse_string( |
972 | 0 | sieve_ast_strlist_str(stritem)); |
973 | 0 | stritem = sieve_ast_strlist_next(stritem); |
974 | 0 | } |
975 | 0 | } |
976 | |
|
977 | 0 | printf(" ]"); |
978 | 0 | } else { |
979 | 0 | stritem = sieve_ast_strlist_first(strlist); |
980 | 0 | if (stritem != NULL) { |
981 | 0 | sieve_ast_unparse_string( |
982 | 0 | sieve_ast_strlist_str(stritem)); |
983 | 0 | } |
984 | 0 | } |
985 | 0 | } |
986 | | |
987 | | static void |
988 | | sieve_ast_unparse_argument(struct sieve_ast_argument *argument, int level) |
989 | 0 | { |
990 | 0 | switch (argument->type) { |
991 | 0 | case SAAT_STRING: |
992 | 0 | sieve_ast_unparse_string(sieve_ast_argument_str(argument)); |
993 | 0 | break; |
994 | 0 | case SAAT_STRING_LIST: |
995 | 0 | sieve_ast_unparse_stringlist(argument, level+1); |
996 | 0 | break; |
997 | 0 | case SAAT_NUMBER: |
998 | 0 | printf("%"SIEVE_PRI_NUMBER, |
999 | 0 | sieve_ast_argument_number(argument)); |
1000 | 0 | break; |
1001 | 0 | case SAAT_TAG: |
1002 | 0 | printf(":%s", sieve_ast_argument_tag(argument)); |
1003 | 0 | break; |
1004 | 0 | default: |
1005 | 0 | printf("??ARGUMENT??"); |
1006 | 0 | break; |
1007 | 0 | } |
1008 | 0 | } |
1009 | | |
1010 | | static void sieve_ast_unparse_test(struct sieve_ast_node *node, int level); |
1011 | | |
1012 | | static void sieve_ast_unparse_tests(struct sieve_ast_node *node, int level) |
1013 | 0 | { |
1014 | 0 | struct sieve_ast_node *test; |
1015 | |
|
1016 | 0 | if (sieve_ast_test_count(node) > 1) { |
1017 | 0 | int i; |
1018 | |
|
1019 | 0 | printf(" (\n"); |
1020 | | |
1021 | | /* Create indent */ |
1022 | 0 | for (i = 0; i < level+2; i++) |
1023 | 0 | printf(" "); |
1024 | |
|
1025 | 0 | test = sieve_ast_test_first(node); |
1026 | 0 | sieve_ast_unparse_test(test, level+1); |
1027 | |
|
1028 | 0 | test = sieve_ast_test_next(test); |
1029 | 0 | while (test != NULL) { |
1030 | 0 | printf(", \n"); |
1031 | 0 | for (i = 0; i < level+2; i++) |
1032 | 0 | printf(" "); |
1033 | 0 | sieve_ast_unparse_test(test, level+1); |
1034 | 0 | test = sieve_ast_test_next(test); |
1035 | 0 | } |
1036 | |
|
1037 | 0 | printf(" )"); |
1038 | 0 | } else { |
1039 | 0 | test = sieve_ast_test_first(node); |
1040 | 0 | if (test != NULL) |
1041 | 0 | sieve_ast_unparse_test(test, level); |
1042 | 0 | } |
1043 | 0 | } |
1044 | | |
1045 | | static void sieve_ast_unparse_test(struct sieve_ast_node *node, int level) |
1046 | 0 | { |
1047 | 0 | struct sieve_ast_argument *argument; |
1048 | |
|
1049 | 0 | printf(" %s", node->identifier); |
1050 | |
|
1051 | 0 | argument = sieve_ast_argument_first(node); |
1052 | 0 | while (argument != NULL) { |
1053 | 0 | printf(" "); |
1054 | 0 | sieve_ast_unparse_argument(argument, level); |
1055 | 0 | argument = sieve_ast_argument_next(argument); |
1056 | 0 | } |
1057 | |
|
1058 | 0 | sieve_ast_unparse_tests(node, level); |
1059 | 0 | } |
1060 | | |
1061 | | static void sieve_ast_unparse_command(struct sieve_ast_node *node, int level) |
1062 | 0 | { |
1063 | 0 | struct sieve_ast_node *command; |
1064 | 0 | struct sieve_ast_argument *argument; |
1065 | |
|
1066 | 0 | int i; |
1067 | | |
1068 | | /* Create indent */ |
1069 | 0 | for (i = 0; i < level; i++) |
1070 | 0 | printf(" "); |
1071 | |
|
1072 | 0 | printf("%s", node->identifier); |
1073 | |
|
1074 | 0 | argument = sieve_ast_argument_first(node); |
1075 | 0 | while (argument != NULL) { |
1076 | 0 | printf(" "); |
1077 | 0 | sieve_ast_unparse_argument(argument, level); |
1078 | 0 | argument = sieve_ast_argument_next(argument); |
1079 | 0 | } |
1080 | |
|
1081 | 0 | sieve_ast_unparse_tests(node, level); |
1082 | |
|
1083 | 0 | command = sieve_ast_command_first(node); |
1084 | 0 | if (command != NULL) { |
1085 | 0 | printf(" {\n"); |
1086 | |
|
1087 | 0 | while (command != NULL) { |
1088 | 0 | sieve_ast_unparse_command(command, level+1); |
1089 | 0 | command = sieve_ast_command_next(command); |
1090 | 0 | } |
1091 | |
|
1092 | 0 | for (i = 0; i < level; i++) |
1093 | 0 | printf(" "); |
1094 | 0 | printf("}\n"); |
1095 | 0 | } else |
1096 | 0 | printf(";\n"); |
1097 | 0 | } |
1098 | | |
1099 | | void sieve_ast_unparse(struct sieve_ast *ast) |
1100 | 0 | { |
1101 | 0 | struct sieve_ast_node *command; |
1102 | |
|
1103 | 0 | printf("Unparsing Abstract Syntax Tree:\n"); |
1104 | |
|
1105 | 0 | T_BEGIN { |
1106 | 0 | command = sieve_ast_command_first(sieve_ast_root(ast)); |
1107 | 0 | while (command != NULL) { |
1108 | 0 | sieve_ast_unparse_command(command, 0); |
1109 | 0 | command = sieve_ast_command_next(command); |
1110 | 0 | } |
1111 | 0 | } T_END; |
1112 | 0 | } |