build administrativa
[m6w6/ext-psi] / src / parser.c
1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #else
29 # include "php_config.h"
30 #endif
31 #include <sys/mman.h>
32 #include <assert.h>
33 #include <errno.h>
34 #include <stdarg.h>
35
36 #include <Zend/zend_smart_str.h>
37
38 #include "parser.h"
39
40 struct psi_parser *psi_parser_init(struct psi_parser *P, psi_error_cb error,
41 unsigned flags)
42 {
43 if (!P) {
44 P = pemalloc(sizeof(*P), 1);
45 }
46 memset(P, 0, sizeof(*P));
47
48 psi_data_ctor_with_dtors(PSI_DATA(P), error, flags);
49
50 P->preproc = psi_cpp_init(P);
51
52 return P;
53 }
54
55 struct psi_parser_input *psi_parser_open_file(struct psi_parser *P,
56 const char *filename, bool report_errors)
57 {
58 struct stat sb;
59 FILE *fp;
60 struct psi_parser_input *fb;
61
62 if (stat(filename, &sb)) {
63 if (report_errors) {
64 P->error(PSI_DATA(P), NULL, PSI_WARNING,
65 "Could not stat '%s': %s",
66 filename, strerror(errno));
67 }
68 return NULL;
69 }
70
71 if (!(fb = pemalloc(sizeof(*fb) + sb.st_size + psi_parser_maxfill(), 1))) {
72 if (report_errors) {
73 P->error(PSI_DATA(P), NULL, PSI_WARNING,
74 "Could not allocate %zu bytes for reading '%s': %s",
75 sb.st_size + psi_parser_maxfill(), filename, strerror(errno));
76 }
77 return NULL;
78 }
79
80 if (!(fp = fopen(filename, "r"))) {
81 free(fb);
82 if (report_errors) {
83 P->error(PSI_DATA(P), NULL, PSI_WARNING,
84 "Could not open '%s' for reading: %s",
85 filename, strerror(errno));
86 }
87 return NULL;
88 }
89
90 if (sb.st_size != fread(fb->buffer, 1, sb.st_size, fp)) {
91 free(fb);
92 fclose(fp);
93 if (report_errors) {
94 P->error(PSI_DATA(P), NULL, PSI_WARNING,
95 "Could not read %zu bytes from '%s': %s",
96 sb.st_size + psi_parser_maxfill(), filename, strerror(errno));
97 }
98 return NULL;
99 }
100 fclose(fp);
101
102 memset(fb->buffer + sb.st_size, 0, psi_parser_maxfill());
103
104 fb->length = sb.st_size;
105 fb->file = psi_string_init_interned(filename, strlen(filename), 1);
106
107 return fb;
108 }
109
110 struct psi_parser_input *psi_parser_open_string(struct psi_parser *P,
111 const char *string, size_t length)
112 {
113 struct psi_parser_input *sb;
114
115 if (!(sb = pemalloc(sizeof(*sb) + length + psi_parser_maxfill(), 1))) {
116 P->error(PSI_DATA(P), NULL, PSI_WARNING,
117 "Could not allocate %zu bytes: %s",
118 length + psi_parser_maxfill(), strerror(errno));
119 return NULL;
120 }
121
122 memcpy(sb->buffer, string, length);
123 memset(sb->buffer + length, 0, psi_parser_maxfill());
124
125 sb->length = length;
126 sb->file = psi_string_init_interned("<stdin>", strlen("<stdin>"), 1);
127
128 return sb;
129 }
130
131 struct psi_plist *psi_parser_preprocess(struct psi_parser *P,
132 struct psi_plist **tokens)
133 {
134 if (psi_cpp_process(P->preproc, tokens)) {
135 return *tokens;
136 }
137 return NULL;
138 }
139
140 bool psi_parser_process(struct psi_parser *P, struct psi_plist *tokens,
141 size_t *processed)
142 {
143 if (psi_plist_count(tokens)) {
144 return 0 == psi_parser_proc_parse(P, tokens, processed);
145 }
146 return true;
147 }
148
149 static inline zend_string *macro_to_constant(struct psi_parser *parser,
150 zend_string *name, struct psi_validate_scope *scope)
151 {
152 smart_str str = {0};
153
154 size_t i = 0;
155 struct psi_token *tok;
156
157 #if HAVE_ASPRINTF
158 int persistent = 1;
159
160 smart_str_appendl_ex(&str, ZEND_STRL("const psi\\"), 1);
161 smart_str_append_ex(&str, name, 1);
162 smart_str_appendl_ex(&str, ZEND_STRL(" = "), 1);
163 #else
164 int persistent = 0;
165
166 smart_str_append_printf(&str, "const psi\\%s = ", name->val);
167 #endif
168 if (scope->macro->exp) {
169 #if HAVE_ASPRINTF
170 char *astr = NULL;
171 struct psi_dump dump = {{.hn = &astr},
172 .fun = (psi_dump_cb) asprintf};
173 #else
174 struct psi_dump dump = {{.hn = &str},
175 .fun = (psi_dump_cb) smart_str_append_printf};
176 #endif
177
178 psi_num_exp_dump(&dump, scope->macro->exp);
179
180 #if HAVE_ASPRINTF
181 smart_str_appends_ex(&str, astr, 1);
182 free(astr);
183 #endif
184 } else while (psi_plist_get(scope->macro->tokens, i++, &tok)) {
185 if (tok->type == PSI_T_QUOTED_STRING) {
186 smart_str_appendc_ex(&str, '"', persistent);
187 }
188 smart_str_append_ex(&str, tok->text, persistent);
189 if (tok->type == PSI_T_QUOTED_STRING) {
190 smart_str_appendc_ex(&str, '"', persistent);
191 }
192 smart_str_appendc_ex(&str, ' ', persistent);
193 }
194 smart_str_appendl_ex(&str, ";\n", 2, persistent);
195 return smart_str_extract(&str);
196 }
197
198 void psi_parser_postprocess(struct psi_parser *P)
199 {
200 unsigned flags;
201 zend_string *name;
202 struct psi_validate_scope scope = {0};
203
204 psi_validate_scope_ctor(&scope);
205 scope.cpp = P->preproc;
206
207 flags = P->flags;
208 P->flags |= PSI_SILENT;
209
210 ZEND_HASH_FOREACH_STR_KEY_PTR(&P->preproc->defs, name, scope.macro)
211 {
212 bool parsed;
213 size_t processed = 0;
214 struct psi_plist *scanned, *preproc;
215 struct psi_parser_input *I;
216 zend_string *cnst;
217
218 if (scope.macro->sig) {
219 continue;
220 } else if (!scope.macro->exp) {
221 struct psi_token *tok;
222 if (psi_plist_count(scope.macro->tokens) != 1) {
223 continue;
224 } else if (!psi_plist_get(scope.macro->tokens, 0, &tok)) {
225 continue;
226 } else if (tok->type != PSI_T_QUOTED_STRING) {
227 continue;
228 }
229 } else if (!psi_num_exp_validate(PSI_DATA(P), scope.macro->exp, &scope)) {
230 continue;
231 }
232
233 cnst = macro_to_constant(P, name, &scope);
234 if (!cnst) {
235 continue;
236 }
237 //fprintf(stderr, "PARSE: %s", ZSTR_VAL(cnst));
238 I = psi_parser_open_string(P, ZSTR_VAL(cnst), ZSTR_LEN(cnst));
239 zend_string_release(cnst);
240
241 if (!(scanned = psi_parser_scan(P, I))) {
242 psi_parser_input_free(&I);
243 continue;
244 }
245 psi_parser_input_free(&I);
246
247 if (!(preproc = psi_parser_preprocess(P, &scanned))) {
248 psi_plist_free(scanned);
249 continue;
250 }
251
252 parsed = psi_parser_process(P, preproc, &processed);
253 PSI_DEBUG_PRINT(PSI_DATA(P), "PSI: processed=%zu success=%d\n",
254 processed, (int) parsed);
255 psi_plist_free(preproc);
256 }
257 ZEND_HASH_FOREACH_END();
258
259 P->flags = flags;
260
261 psi_validate_scope_dtor(&scope);
262 }
263
264 bool psi_parser_parse(struct psi_parser *P, struct psi_parser_input *I)
265 {
266 struct psi_plist *scanned, *preproc;
267 size_t processed = 0;
268
269 if (!(scanned = psi_parser_scan(P, I))) {
270 return false;
271 }
272
273 if (!(preproc = psi_parser_preprocess(P, &scanned))) {
274 psi_plist_free(scanned);
275 return false;
276 }
277
278 if (!psi_parser_process(P, preproc, &processed)) {
279 psi_plist_free(preproc);
280 return false;
281 }
282
283 psi_parser_postprocess(P);
284
285 psi_plist_free(preproc);
286 return true;
287 }
288
289 void psi_parser_dtor(struct psi_parser *P)
290 {
291 psi_cpp_free(&P->preproc);
292 psi_data_dtor(PSI_DATA(P));
293
294 memset(P, 0, sizeof(*P));
295 }
296
297 void psi_parser_free(struct psi_parser **P)
298 {
299 if (*P) {
300 psi_parser_dtor(*P);
301 free(*P);
302 *P = NULL;
303 }
304 }
305