flush
[m6w6/ext-psi] / src / context.c
1 #include <sys/param.h>
2 #include <dirent.h>
3 #include <fnmatch.h>
4 #include <errno.h>
5
6 #ifdef HAVE_CONFIG_H
7 # include "config.h"
8 #endif
9
10 #include "php.h"
11 #include "php_scandir.h"
12 #include "context.h"
13 #include "parser.h"
14 #include "validator.h"
15
16 #define psi_predef_count(of) ((sizeof(psi_predef ##of## s)/sizeof(psi_predef ##of))-1)
17 typedef struct psi_predef_type {
18 token_t type_tag;
19 const char *type_name;
20 const char *alias;
21 } psi_predef_type;
22 static const psi_predef_type psi_predef_types[] = {
23 PHP_PSI_TYPES{0}
24 };
25 #define psi_predef_type_count() psi_predef_count(_type)
26
27 typedef struct psi_predef_const {
28 token_t type_tag;
29 const char *type_name;
30 const char *name;
31 const char *val_text;
32 token_t val_type_tag;
33 } psi_predef_const;
34 static const psi_predef_const psi_predef_consts[] = {
35 PHP_PSI_CONSTS{0}
36 };
37 #define psi_predef_const_count() psi_predef_count(_const)
38
39 typedef struct psi_predef_struct_member {
40 token_t type_tag;
41 const char *type_name;
42 const char *name;
43 size_t off;
44 size_t len;
45 size_t pointer_level;
46 size_t array_size;
47 } psi_predef_struct_member;
48 #define PSI_PREDEF_STRUCT_MEMBERS 32
49 typedef struct psi_predef_struct {
50 const char *name;
51 psi_predef_struct_member members[PSI_PREDEF_STRUCT_MEMBERS];
52 } psi_predef_struct;
53 static const psi_predef_struct psi_predef_structs[] = {
54 PHP_PSI_STRUCTS{0}
55 };
56 #define psi_predef_struct_count() psi_predef_count(_struct)
57
58 PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErrorFunc error)
59 {
60 size_t i, j;
61 PSI_Data data;
62
63 if (!C) {
64 C = malloc(sizeof(*C));
65 }
66 memset(C, 0, sizeof(*C));
67
68 C->error = error;
69 C->ops = ops;
70 ops->init(C);
71
72 memset(&data, 0, sizeof(data));
73 for (i = 0; i < psi_predef_type_count(); ++i) {
74 const psi_predef_type *pre = &psi_predef_types[i];
75 decl_type *type = init_decl_type(pre->type_tag, pre->type_name);
76 decl_typedef *def = init_decl_typedef(pre->alias, type);
77
78 data.defs = add_decl_typedef(data.defs, def);
79 }
80 for (i = 0; i < psi_predef_const_count(); ++i) {
81 const psi_predef_const *pre = &psi_predef_consts[i];
82 impl_def_val *val = init_impl_def_val(pre->val_type_tag, pre->val_text);
83 const_type *type = init_const_type(pre->type_tag, pre->type_name);
84 constant *constant = init_constant(type, pre->name, val);
85
86 data.consts = add_constant(data.consts, constant);
87 }
88 for (i = 0; i < psi_predef_struct_count(); ++i) {
89 const psi_predef_struct *pre = &psi_predef_structs[i];
90 decl_args *dargs = init_decl_args(NULL);
91
92 for (j = 0; j < PSI_PREDEF_STRUCT_MEMBERS; ++j) {
93 const psi_predef_struct_member *member = &pre->members[j];
94 decl_type *type;
95 decl_var *dvar;
96
97 if (!member->name) {
98 break;
99 }
100
101 type = init_decl_type(member->type_tag, member->type_name);
102 dvar = init_decl_var(member->name, member->pointer_level, member->array_size);
103 dargs = add_decl_arg(dargs, init_decl_arg(type, dvar));
104 }
105
106 data.structs = add_decl_struct(data.structs,
107 init_decl_struct(pre->name, dargs));
108 }
109 return C;
110 }
111
112 static int psi_select_dirent(const struct dirent *entry)
113 {
114 #ifndef FNM_CASEFOLD
115 #define FNM_CASEFOLD 0
116 #endif
117 return 0 == fnmatch("*.psi", entry->d_name, FNM_CASEFOLD);
118 }
119
120
121 void PSI_ContextBuild(PSI_Context *C, const char *path)
122 {
123 int i, n;
124 struct dirent **entries = NULL;
125
126 n = php_scandir(path, &entries, psi_select_dirent, alphasort);
127
128 if (n < 0) {
129 return;
130 } else for (i = 0; i < n; ++i) {
131 char psi[MAXPATHLEN];
132 PSI_Parser P;
133 PSI_Validator V;
134
135 if (MAXPATHLEN <= slprintf(psi, MAXPATHLEN, "%s/%s", path, entries[i]->d_name)) {
136 C->error(PSI_WARNING, "Path to PSI file too long: %s/%s",
137 path, entries[i]->d_name);
138 }
139 if (!PSI_ParserInit(&P, psi, C->error, 0)) {
140 C->error(PSI_WARNING, "Failed to init PSI parser (%s): %s",
141 psi, strerror(errno));
142 continue;
143 }
144
145 while (-1 != PSI_ParserScan(&P)) {
146 PSI_ParserParse(&P, PSI_TokenAlloc(&P));
147 };
148 PSI_ParserParse(&P, NULL);
149
150 if (!PSI_ValidatorInit(&V, &P)) {
151 C->error(PSI_WARNING, "Failed to init PSI validator");
152 break;
153 }
154 PSI_ParserDtor(&P);
155
156 if (PSI_ValidatorValidate(&V)) {
157 zend_function_entry *closures;
158
159 closures = PSI_ContextCompile(C, (PSI_Data *) &V);
160 if (closures && SUCCESS != zend_register_functions(NULL, closures, NULL, MODULE_PERSISTENT)) {
161 C->error(PSI_WARNING, "Failed to register functions!");
162 }
163 }
164 PSI_ValidatorDtor(&V);
165 }
166 if (entries) {
167 for (i = 0; i < n; ++i) {
168 free(entries[i]);
169 }
170 free(entries);
171 }
172
173 }
174
175 zend_function_entry *PSI_ContextCompile(PSI_Context *C, PSI_Data *D)
176 {
177 size_t i, count = C->count++;
178 zend_function_entry *zfe;
179
180 if (D->consts) {
181 zend_constant zc;
182
183 zc.flags = CONST_PERSISTENT|CONST_CS;
184 zc.module_number = EG(current_module)->module_number;
185
186 for (i = 0; i < D->consts->count; ++i) {
187 constant *c = D->consts->list[i];
188
189 zc.name = zend_string_init(c->name + (c->name[0] == '\\'), strlen(c->name) - (c->name[0] == '\\'), 1);
190 ZVAL_NEW_STR(&zc.value, zend_string_init(c->val->text, strlen(c->val->text), 1));
191
192 switch (c->type->type) {
193 case PSI_T_BOOL:
194 convert_to_boolean(&zc.value);
195 break;
196 case PSI_T_INT:
197 convert_to_long(&zc.value);
198 break;
199 case PSI_T_FLOAT:
200 convert_to_double(&zc.value);
201 break;
202 }
203 zend_register_constant(&zc);
204 }
205 }
206
207 C->data = realloc(C->data, C->count * sizeof(*C->data));
208 PSI_DataExchange(&C->data[count], D);
209
210 zfe = C->ops->compile(C, &C->data[count]);
211
212 C->closures = realloc(C->closures, C->count * sizeof(*C->closures));
213 C->closures[count] = zfe;
214
215 return zfe;
216 }
217
218 void PSI_ContextDtor(PSI_Context *C)
219 {
220 size_t i;
221
222 C->ops->dtor(C);
223
224 for (i = 0; i < C->count; ++i) {
225 PSI_DataDtor(&C->data[i]);
226 if (C->closures[i]){
227 free(C->closures[i]);
228 }
229 }
230 free(C->data);
231 free(C->closures);
232
233 memset(C, 0, sizeof(*C));
234 }
235
236 void PSI_ContextFree(PSI_Context **C)
237 {
238 if (*C) {
239 PSI_ContextDtor(*C);
240 free(*C);
241 *C = NULL;
242 }
243 }