fix printf with threaded parser; replace SUCCESS/FAILURE with bool
[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 #if PSI_THREADED_PARSER
150 static void psi_smart_str_printf(smart_str *ss, const char *fmt, ...)
151 {
152 va_list argv;
153 char *buf;
154 int len;
155
156 va_start(argv, fmt);
157 len = vasprintf(&buf, fmt, argv);
158 va_end(argv);
159
160 if (len != -1) {
161 smart_str_appendl_ex(ss, buf, len, 1);
162 free(buf);
163 }
164 }
165 #else
166 # define psi_smart_str_printf smart_str_append_printf
167 #endif
168
169 static inline zend_string *macro_to_constant(struct psi_parser *parser,
170 zend_string *name, struct psi_validate_scope *scope)
171 {
172 smart_str str = {0};
173 size_t i = 0;
174 struct psi_token *tok;
175 #if PSI_THREADED_PARSER
176 int persistent = 1;
177 #else
178 int persistent = 0;
179 #endif
180
181 psi_smart_str_printf(&str, "const psi\\%s = ", name->val);
182 if (scope->macro->exp) {
183 struct psi_dump dump = {{.hn = &str},
184 .fun = (psi_dump_cb) psi_smart_str_printf};
185
186 psi_num_exp_dump(&dump, scope->macro->exp);
187
188 } else while (psi_plist_get(scope->macro->tokens, i++, &tok)) {
189 if (tok->type == PSI_T_QUOTED_STRING) {
190 smart_str_appendc_ex(&str, '"', persistent);
191 }
192 smart_str_append_ex(&str, tok->text, persistent);
193 if (tok->type == PSI_T_QUOTED_STRING) {
194 smart_str_appendc_ex(&str, '"', persistent);
195 }
196 smart_str_appendc_ex(&str, ' ', persistent);
197 }
198 smart_str_appendl_ex(&str, ";\n", 2, persistent);
199 return smart_str_extract(&str);
200 }
201
202 void psi_parser_postprocess(struct psi_parser *P)
203 {
204 unsigned flags;
205 zend_string *name;
206 struct psi_validate_scope scope = {0};
207
208 psi_validate_scope_ctor(&scope);
209 scope.cpp = P->preproc;
210
211 flags = P->flags;
212 P->flags |= PSI_SILENT;
213
214 ZEND_HASH_FOREACH_STR_KEY_PTR(&P->preproc->defs, name, scope.macro)
215 {
216 bool parsed;
217 size_t processed = 0;
218 struct psi_plist *scanned, *preproc;
219 struct psi_parser_input *I;
220 zend_string *cnst;
221
222 if (scope.macro->sig) {
223 continue;
224 } else if (!scope.macro->exp) {
225 struct psi_token *tok;
226 if (psi_plist_count(scope.macro->tokens) != 1) {
227 continue;
228 } else if (!psi_plist_get(scope.macro->tokens, 0, &tok)) {
229 continue;
230 } else if (tok->type != PSI_T_QUOTED_STRING) {
231 continue;
232 }
233 } else if (!psi_num_exp_validate(PSI_DATA(P), scope.macro->exp, &scope)) {
234 continue;
235 }
236
237 cnst = macro_to_constant(P, name, &scope);
238 if (!cnst) {
239 continue;
240 }
241 //fprintf(stderr, "PARSE: %s", ZSTR_VAL(cnst));
242 I = psi_parser_open_string(P, ZSTR_VAL(cnst), ZSTR_LEN(cnst));
243 zend_string_release(cnst);
244
245 if (!(scanned = psi_parser_scan(P, I))) {
246 psi_parser_input_free(&I);
247 continue;
248 }
249 psi_parser_input_free(&I);
250
251 if (!(preproc = psi_parser_preprocess(P, &scanned))) {
252 psi_plist_free(scanned);
253 continue;
254 }
255
256 parsed = psi_parser_process(P, preproc, &processed);
257 PSI_DEBUG_PRINT(PSI_DATA(P), "PSI: processed=%zu success=%d\n",
258 processed, (int) parsed);
259 psi_plist_free(preproc);
260 }
261 ZEND_HASH_FOREACH_END();
262
263 P->flags = flags;
264
265 psi_validate_scope_dtor(&scope);
266 }
267
268 bool psi_parser_parse(struct psi_parser *P, struct psi_parser_input *I)
269 {
270 struct psi_plist *scanned, *preproc;
271 size_t processed = 0;
272
273 if (!(scanned = psi_parser_scan(P, I))) {
274 return false;
275 }
276
277 if (!(preproc = psi_parser_preprocess(P, &scanned))) {
278 psi_plist_free(scanned);
279 return false;
280 }
281
282 if (!psi_parser_process(P, preproc, &processed)) {
283 psi_plist_free(preproc);
284 return false;
285 }
286
287 psi_parser_postprocess(P);
288
289 psi_plist_free(preproc);
290 return true;
291 }
292
293 void psi_parser_dtor(struct psi_parser *P)
294 {
295 psi_cpp_free(&P->preproc);
296 psi_data_dtor(PSI_DATA(P));
297
298 memset(P, 0, sizeof(*P));
299 }
300
301 void psi_parser_free(struct psi_parser **P)
302 {
303 if (*P) {
304 psi_parser_dtor(*P);
305 free(*P);
306 *P = NULL;
307 }
308 }
309