flush+
[m6w6/ext-psi] / src / module.c
1
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5
6 #include "php.h"
7 #include "php_ini.h"
8 #include "ext/standard/info.h"
9
10 #include "php_psi.h"
11 #include "parser.h"
12
13 #include "libjit.h"
14
15 ZEND_DECLARE_MODULE_GLOBALS(psi);
16
17 PHP_INI_BEGIN()
18 STD_PHP_INI_ENTRY("psi.directory", "psis", PHP_INI_ALL, OnUpdateString, directory, zend_psi_globals, psi_globals)
19 PHP_INI_END();
20
21 void psi_error(int type, const char *msg, ...)
22 {
23 char buf[0x1000];
24 va_list argv;
25
26 va_start(argv, msg);
27 vslprintf(buf, 0x1000, msg, argv);
28 va_end(argv);
29
30 php_error(type, buf);
31 }
32
33 int psi_internal_type(impl_type *type)
34 {
35 switch (type->type) {
36 case PSI_T_BOOL:
37 return _IS_BOOL;
38 case PSI_T_INT:
39 case PSI_T_LONG:
40 return IS_LONG;
41 case PSI_T_FLOAT:
42 case PSI_T_DOUBLE:
43 return IS_DOUBLE;
44 case PSI_T_STRING:
45 return IS_STRING;
46 case PSI_T_ARRAY:
47 return IS_ARRAY;
48 default:
49 return 0;
50 }
51 }
52
53 zend_internal_arg_info *psi_internal_arginfo(impl *impl)
54 {
55 size_t i;
56 zend_internal_arg_info *aip;
57 zend_internal_function_info *fi;
58
59 aip = calloc(impl->func->args->count + 1, sizeof(*aip));
60
61 fi = (zend_internal_function_info *) &aip[0];
62 fi->required_num_args = psi_num_min_args(impl);
63 fi->return_reference = impl->func->return_reference;
64 fi->type_hint = psi_internal_type(impl->func->return_type);
65
66 for (i = 0; i < impl->func->args->count; ++i) {
67 impl_arg *iarg = impl->func->args->args[i];
68 zend_internal_arg_info *ai = &aip[i+1];
69
70 ai->name = iarg->var->name;
71 ai->type_hint = psi_internal_type(iarg->type);
72 if (iarg->var->reference) {
73 ai->pass_by_reference = 1;
74 }
75 if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) {
76 ai->allow_null = 1;
77 }
78 }
79
80 return aip;
81 }
82
83 size_t psi_num_min_args(impl *impl)
84 {
85 size_t i, n = impl->func->args->count;
86
87 for (i = 0; i < impl->func->args->count; ++i) {
88 if (impl->func->args->args[i]->def) {
89 --n;
90 }
91 }
92 return n;
93 }
94
95 void psi_to_int(impl_val *ret_val, decl_arg *func, zval *return_value)
96 {
97 switch (real_decl_type(func->type)->type) {
98 case PSI_T_FLOAT:
99 case PSI_T_DOUBLE:
100 RETVAL_DOUBLE(deref_impl_val(0, ret_val, func)->dval);
101 convert_to_long(return_value);
102 break;
103 default:
104 RETVAL_LONG(deref_impl_val(0, ret_val, func)->lval);
105 }
106 }
107
108 void psi_to_string(impl_val *ret_val, decl_arg *func, zval *return_value)
109 {
110 switch (real_decl_type(func->type)->type) {
111 case PSI_T_CHAR:
112 case PSI_T_SINT8:
113 case PSI_T_UINT8:
114 if (!func->var->pointer_level) {
115 char chr = ret_val->lval;
116 RETVAL_STRINGL(&chr, 1);
117 } else {
118 ret_val = deref_impl_val(1, ret_val, func);
119 if (ret_val->ptr) {
120 RETVAL_STRING(ret_val->ptr);
121 } else {
122 RETVAL_EMPTY_STRING();
123 }
124 }
125 break;
126 case PSI_T_FLOAT:
127 case PSI_T_DOUBLE:
128 RETVAL_DOUBLE(deref_impl_val(0, ret_val, func)->dval);
129 convert_to_string(return_value);
130 break;
131 default:
132 RETVAL_LONG(deref_impl_val(0, ret_val, func)->lval);
133 convert_to_string(return_value);
134 break;
135 }
136 }
137
138 ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl)
139 {
140 impl_arg *iarg;
141
142 if (!impl->func->args->count) {
143 return zend_parse_parameters_none();
144 }
145
146 ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl), impl->func->args->count)
147 nextarg:
148 iarg = impl->func->args->args[_i];
149 if (iarg->def) {
150 Z_PARAM_OPTIONAL;
151 }
152 if (PSI_T_BOOL == iarg->type->type) {
153 if (iarg->def) {
154 iarg->val.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0;
155 }
156 Z_PARAM_BOOL(iarg->val.bval);
157 } else if (PSI_T_INT == iarg->type->type) {
158 if (iarg->def) {
159 iarg->val.lval = zend_atol(iarg->def->text, strlen(iarg->def->text));
160 }
161 Z_PARAM_LONG(iarg->val.lval);
162 } else if (PSI_T_FLOAT == iarg->type->type) {
163 if (iarg->def) {
164 iarg->val.dval = zend_strtod(iarg->def->text, NULL);
165 }
166 Z_PARAM_DOUBLE(iarg->val.dval);
167 } else if (PSI_T_STRING == iarg->type->type) {
168 struct {char *val; size_t len;} str;
169 if (iarg->def) {
170 /* FIXME */
171 str.len = strlen(iarg->def->text) - 2;
172 str.val = &iarg->def->text[1];
173 }
174 Z_PARAM_STR_EX(iarg->val.str, 1, 0);
175 if (iarg->val.str) {
176 zend_string_addref(iarg->val.str);
177 } else if (iarg->def) {
178 iarg->val.str = zend_string_init(str.val, str.len, 0);
179 }
180 } else {
181 error_code = ZPP_ERROR_FAILURE;
182 break;
183 }
184 iarg->_zv = _arg;
185 if (_i < _max_num_args) {
186 goto nextarg;
187 }
188 ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
189
190 return SUCCESS;
191 }
192
193 impl_val *psi_do_let(decl_arg *darg)
194 {
195 impl_val *arg_val = &darg->let->out;
196 impl_arg *iarg = darg->let->arg;
197
198 if (!iarg) {
199 /* let foo = NULL */
200 memset(arg_val, 0, sizeof(*arg_val));
201 return arg_val;
202 }
203 switch (darg->let->val->func->type) {
204 case PSI_T_BOOLVAL:
205 if (iarg->type->type == PSI_T_BOOL) {
206 arg_val->cval = iarg->val.cval;
207 } else {
208 arg_val->cval = zend_is_true(iarg->_zv);
209 }
210 break;
211 case PSI_T_INTVAL:
212 if (iarg->type->type == PSI_T_INT) {
213 arg_val->lval = iarg->val.lval;
214 } else {
215 arg_val->lval = zval_get_long(iarg->_zv);
216 }
217 break;
218 case PSI_T_STRVAL:
219 if (iarg->type->type == PSI_T_STRING) {
220 arg_val->ptr = estrdup(iarg->val.str->val);
221 darg->let->mem = arg_val->ptr;
222 zend_string_release(iarg->val.str);
223 } else {
224 zend_string *zs = zval_get_string(iarg->_zv);
225 arg_val->ptr = estrdup(zs->val);
226 darg->let->mem = arg_val->ptr;
227 zend_string_release(zs);
228 }
229 break;
230 case PSI_T_STRLEN:
231 if (iarg->type->type == PSI_T_STRING) {
232 arg_val->lval = iarg->val.str->len;
233 zend_string_release(iarg->val.str);
234 } else {
235 zend_string *zs = zval_get_string(iarg->_zv);
236 arg_val->lval = zs->len;
237 zend_string_release(zs);
238 }
239 break;
240 EMPTY_SWITCH_DEFAULT_CASE();
241 }
242
243 return arg_val;
244 }
245
246 void psi_do_set(zval *return_value, set_func *func, decl_vars *vars)
247 {
248 impl_val *val = (impl_val *) &vars->vars[0]->arg->let->ptr;
249
250 ZVAL_DEREF(return_value);
251 zval_dtor(return_value);
252
253 switch (func->type) {
254 case PSI_T_TO_STRING:
255 psi_to_string(val, vars->vars[0]->arg, return_value);
256 break;
257 EMPTY_SWITCH_DEFAULT_CASE();
258 }
259 }
260
261 void psi_do_return(impl *impl, impl_val *ret_val, zval *return_value)
262 {
263 switch (impl->stmts->ret.list[0]->func->type) {
264 case PSI_T_TO_STRING:
265 psi_to_string(ret_val, impl->decl->func, return_value);
266 break;
267 case PSI_T_TO_INT:
268 psi_to_int(ret_val, impl->decl->func, return_value);
269 break;
270 EMPTY_SWITCH_DEFAULT_CASE();
271 }
272 }
273
274 void psi_do_free(free_stmt *fre)
275 {
276 size_t i;
277
278 for (i = 0; i < fre->vars->count; ++i) {
279 decl_var *dvar = fre->vars->vars[i];
280
281 if (dvar->arg && dvar->arg->let->out.ptr) {
282 free(dvar->arg->let->out.ptr);
283 dvar->arg->let->out.ptr = NULL;
284 }
285 }
286 }
287
288 void psi_do_clean(impl *impl)
289 {
290 size_t i;
291
292 for (i = 0; i < impl->decl->args->count; ++i) {
293 decl_arg *darg = impl->decl->args->args[i];
294
295 if (darg->let && darg->let->mem) {
296 efree(darg->let->mem);
297 darg->let->mem = NULL;
298 }
299 }
300 }
301
302 PHP_MINIT_FUNCTION(psi)
303 {
304 REGISTER_INI_ENTRIES();
305
306 PSI_ContextInit(&PSI_G(context), PSI_Libjit(), psi_error);
307 PSI_ContextBuild(&PSI_G(context), PSI_G(directory));
308
309 return SUCCESS;
310 }
311 PHP_MSHUTDOWN_FUNCTION(psi)
312 {
313 PSI_ContextDtor(&PSI_G(context));
314
315 UNREGISTER_INI_ENTRIES();
316
317 return SUCCESS;
318 }
319
320 /* Remove if there's nothing to do at request start */
321 /* {{{ PHP_RINIT_FUNCTION
322 */
323 PHP_RINIT_FUNCTION(psi)
324 {
325 #if defined(COMPILE_DL_PSI) && defined(ZTS)
326 ZEND_TSRMLS_CACHE_UPDATE();
327 #endif
328 return SUCCESS;
329 }
330 /* }}} */
331
332 /* Remove if there's nothing to do at request end */
333 /* {{{ PHP_RSHUTDOWN_FUNCTION
334 */
335 PHP_RSHUTDOWN_FUNCTION(psi)
336 {
337 return SUCCESS;
338 }
339 /* }}} */
340
341 PHP_MINFO_FUNCTION(psi)
342 {
343 php_info_print_table_start();
344 php_info_print_table_header(2, "psi support", "enabled");
345 php_info_print_table_end();
346
347 DISPLAY_INI_ENTRIES();
348 }
349 const zend_function_entry psi_functions[] = {
350 PHP_FE_END
351 };
352
353 zend_module_entry psi_module_entry = {
354 STANDARD_MODULE_HEADER,
355 "psi",
356 psi_functions,
357 PHP_MINIT(psi),
358 PHP_MSHUTDOWN(psi),
359 PHP_RINIT(psi), /* Replace with NULL if there's nothing to do at request start */
360 PHP_RSHUTDOWN(psi), /* Replace with NULL if there's nothing to do at request end */
361 PHP_MINFO(psi),
362 PHP_PSI_VERSION,
363 STANDARD_MODULE_PROPERTIES
364 };
365
366 #ifdef COMPILE_DL_PSI
367 #ifdef ZTS
368 ZEND_TSRMLS_CACHE_DEFINE();
369 #endif
370 ZEND_GET_MODULE(psi)
371 #endif
372
373 /*
374 * Local variables:
375 * tab-width: 4
376 * c-basic-offset: 4
377 * End:
378 * vim600: noet sw=4 ts=4 fdm=marker
379 * vim<600: noet sw=4 ts=4
380 */