summaryrefslogtreecommitdiff
path: root/src/sp_config_scanner.re
diff options
context:
space:
mode:
authorBen Fuhrmannek2021-08-16 15:47:01 +0200
committerBen Fuhrmannek2021-08-16 15:47:01 +0200
commit5148ded7268b569fd5e720f90b44645c83ac3e9e (patch)
tree9d5c3035a7a85ffc27de7c32b441994a21a6347a /src/sp_config_scanner.re
parent9dc6b23a2219e809e665bac7d82567533751d39d (diff)
fincy new scanner/parser for config rules + fixed a few bugs along the way + fixed related unittests
Diffstat (limited to 'src/sp_config_scanner.re')
-rw-r--r--src/sp_config_scanner.re139
1 files changed, 139 insertions, 0 deletions
diff --git a/src/sp_config_scanner.re b/src/sp_config_scanner.re
new file mode 100644
index 0000000..075c343
--- /dev/null
+++ b/src/sp_config_scanner.re
@@ -0,0 +1,139 @@
1#include "php_snuffleupagus.h"
2
3/*!types:re2c*/
4
5#define cs_error_log(fmt, ...) sp_log_err("config", fmt, ##__VA_ARGS__)
6
7zend_string *sp_get_arg_string(sp_parsed_keyword *kw) {
8 if (!kw || !kw->arg) {
9 return NULL;
10 }
11 zend_string *ret = zend_string_init(kw->arg, kw->arglen, 1);
12 char *pin, *pout;
13 pin = pout = ZSTR_VAL(ret);
14 char *pend = pin + ZSTR_LEN(ret);
15
16 while (pin < pend) {
17 if (*pin == '\\') {
18 pin++;
19 }
20 *pout = *pin;
21 pin++; pout++;
22 }
23
24 if (pin != pout) {
25 size_t len = pout - ZSTR_VAL(ret);
26 ret = zend_string_truncate(ret, len, 1);
27 ZSTR_VAL(ret)[len] = 0;
28 }
29
30 return ret;
31}
32
33zend_string *sp_get_textual_representation(sp_parsed_keyword *parsed_rule) {
34 // a rule is "sp.keyword...keyword(arg);\0"
35 size_t len = 3; // sp + ;
36 sp_parsed_keyword *kw;
37 for (kw = parsed_rule; kw->kw; kw++) {
38 len++; // .
39 len += kw->kwlen;
40 if (kw->argtype == SP_ARGTYPE_EMPTY) {
41 len += 2; // ()
42 } else if (kw->argtype == SP_ARGTYPE_STR) {
43 len += 4;
44 len += kw->arglen;
45 }
46 }
47 zend_string *ret = zend_string_alloc(len, 1);
48 char *ptr = ZSTR_VAL(ret);
49 memcpy(ptr, "sp", 2); ptr += 2;
50 for (kw = parsed_rule; kw->kw; kw++) {
51 *ptr++ = '.';
52 memcpy(ptr, kw->kw, kw->kwlen); ptr += kw->kwlen;
53 if (kw->argtype == SP_ARGTYPE_EMPTY || kw->argtype == SP_ARGTYPE_STR || kw->argtype == SP_ARGTYPE_UNKNOWN) {
54 *ptr++ = '(';
55 }
56 if (kw->argtype == SP_ARGTYPE_STR && kw->arg) {
57 *ptr++ = '"';
58 memcpy(ptr, kw->arg, kw->arglen); ptr += kw->arglen;
59 *ptr++ = '"';
60 }
61 if (kw->argtype == SP_ARGTYPE_EMPTY || kw->argtype == SP_ARGTYPE_STR || kw->argtype == SP_ARGTYPE_UNKNOWN) {
62 *ptr++ = ')';
63 }
64 }
65 *ptr++ = ';';
66 *ptr = 0;
67 return ret;
68}
69
70zend_result sp_config_scan(char *data, zend_result (*process_rule)(sp_parsed_keyword*))
71{
72 const char *YYCURSOR = data;
73 const char *YYMARKER, *t1, *t2, *t3, *t4;
74 /*!stags:re2c format = 'const char *@@;\n'; */
75
76 const int max_keywords = 16;
77 sp_parsed_keyword parsed_rule[max_keywords+1];
78 int kw_i = 0;
79
80 int cond = yycinit;
81 long lineno = 1;
82
83 /*!re2c
84 re2c:define:YYCTYPE = char;
85 // re2c:define:YYCURSOR = data;
86 re2c:yyfill:enable = 0;
87 re2c:flags:tags = 1;
88 re2c:api:style = free-form;
89 re2c:define:YYGETCONDITION = "cond";
90 re2c:define:YYSETCONDITION = "cond = @@;";
91
92 end = "\x00";
93 nl = "\r"?"\n";
94 ws = [ \t];
95 keyword = [a-zA-Z_][a-zA-Z0-9_]*;
96 string = "\"" ("\\\"" | [^"\r\n])* "\"";
97
98 <init> * { cs_error_log("Parser error on line %d", lineno); return FAILURE; }
99 <init> ws+ { goto yyc_init; }
100 <init> [;#] .* { goto yyc_init; }
101 <init> nl { lineno++; goto yyc_init; }
102 <init> "sp" { kw_i = 0; goto yyc_rule; }
103 <init> end { return SUCCESS; }
104
105 <rule> ws+ { goto yyc_rule; }
106 <rule> nl / ( nl | ws )* "." { lineno++; goto yyc_rule; }
107 <rule> "." @t1 keyword @t2 ( "(" @t3 string? @t4 ")" )? {
108 if (kw_i == max_keywords) {
109 cs_error_log("Too many keywords in rule (more than %d) on line %d", max_keywords, lineno);
110 return FAILURE;
111 }
112 sp_parsed_keyword kw = {.kw = (char*)t1, .kwlen = t2-t1, .arg = (char*)t3, .arglen = t4-t3, .argtype = SP_ARGTYPE_UNKNOWN, .lineno = lineno};
113 if (t3 && t4) {
114 if (t3 == t4) {
115 kw.argtype = SP_ARGTYPE_EMPTY;
116 } else if (t4-t2 >= 2) {
117 kw.arg = (char*)t3 + 1;
118 kw.arglen = t4 - t3 - 2;
119 kw.argtype = SP_ARGTYPE_STR;
120 }
121 } else {
122 kw.argtype = SP_ARGTYPE_NONE;
123 }
124 parsed_rule[kw_i++] = kw;
125 goto yyc_rule;
126 }
127 <rule> ";" {
128 end_of_rule:
129 parsed_rule[kw_i++] = (sp_parsed_keyword){0, 0, 0, 0, 0, 0};
130 if (process_rule && process_rule(parsed_rule) != SUCCESS) {
131 return FAILURE;
132 }
133 goto yyc_init;
134 }
135 <rule> * { goto end_of_rule; }
136
137 */
138 return FAILURE;
139} \ No newline at end of file