api refactoring
[m6w6/ext-psi] / src / module.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include "php.h"
6 #include "php_ini.h"
7 #include "ext/standard/info.h"
8 #include "zend_constants.h"
9 #include "zend_operators.h"
10
11 #include "php_psi.h"
12 #include "token.h"
13 #include "parser.h"
14
15 #if HAVE_LIBJIT
16 # include "libjit.h"
17 # ifndef HAVE_LIBFFI
18 # define PSI_ENGINE "jit"
19 # endif
20 #endif
21 #if HAVE_LIBFFI
22 # include "libffi.h"
23 # define PSI_ENGINE "ffi"
24 #endif
25
26 ZEND_DECLARE_MODULE_GLOBALS(psi);
27
28 PHP_INI_BEGIN()
29 STD_PHP_INI_ENTRY("psi.engine", PSI_ENGINE, PHP_INI_SYSTEM, OnUpdateString, engine, zend_psi_globals, psi_globals)
30 STD_PHP_INI_ENTRY("psi.directory", "psi.d", PHP_INI_SYSTEM, OnUpdateString, directory, zend_psi_globals, psi_globals)
31 PHP_INI_END();
32
33 static zend_object_handlers psi_object_handlers;
34 static zend_class_entry *psi_class_entry;
35
36 zend_class_entry *psi_object_get_class_entry()
37 {
38 return psi_class_entry;
39 }
40
41 void psi_error_wrapper(void *context, struct psi_token *t, int type, const char *msg, ...)
42 {
43 va_list argv;
44 const char *fn = NULL;
45 unsigned ln = 0;
46
47 if (context) {
48 if (PSI_DATA(context)->flags & PSI_PARSER_SILENT) {
49 return;
50 }
51 }
52
53 if (t) {
54 fn = t->file;
55 ln = t->line;
56 } else if (zend_is_executing()) {
57 fn = zend_get_executed_filename();
58 ln = zend_get_executed_lineno();
59 } else if (zend_is_compiling()) {
60 fn = zend_get_compiled_filename()->val;
61 ln = zend_get_compiled_lineno();
62 }
63
64 va_start(argv, msg);
65 psi_verror(type, fn, ln, msg, argv);
66 va_end(argv);
67 }
68
69 void psi_error(int type, const char *fn, unsigned ln, const char *msg, ...)
70 {
71 va_list argv;
72
73 va_start(argv, msg);
74 psi_verror(type, fn, ln, msg, argv);
75 va_end(argv);
76 }
77
78 void psi_verror(int type, const char *fn, unsigned ln, const char *msg, va_list argv)
79 {
80 zend_error_cb(type, fn, ln, msg, argv);
81 }
82
83 static void psi_object_free(zend_object *o)
84 {
85 psi_object *obj = PSI_OBJ(NULL, o);
86
87 if (obj->data) {
88 /* FIXME: how about registering a destructor?
89 // free(obj->data); */
90 obj->data = NULL;
91 }
92 zend_object_std_dtor(o);
93 }
94
95 static zend_object *psi_object_init(zend_class_entry *ce)
96 {
97 psi_object *o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
98
99 zend_object_std_init(&o->std, ce);
100 object_properties_init(&o->std, ce);
101 o->std.handlers = &psi_object_handlers;
102 return &o->std;
103 }
104
105 ZEND_BEGIN_ARG_INFO_EX(ai_psi_dump, 0, 0, 0)
106 ZEND_ARG_INFO(0, stream)
107 ZEND_END_ARG_INFO();
108 static PHP_FUNCTION(psi_dump) {
109 php_stream *s;
110 zval *r = NULL;
111 int fd = STDOUT_FILENO;
112
113 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "|r!", &r)) {
114 return;
115 }
116 if (r) {
117 php_stream_from_zval(s, r);
118
119 if (SUCCESS != php_stream_cast(s, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL, (void **)&fd, 1)) {
120 RETURN_FALSE;
121 }
122 }
123 psi_context_dump(&PSI_G(context), fd);
124 }
125
126 ZEND_BEGIN_ARG_INFO_EX(ai_psi_validate, 0, 0, 1)
127 ZEND_ARG_INFO(0, file)
128 ZEND_END_ARG_INFO();
129 static PHP_FUNCTION(psi_validate) {
130 zend_string *file;
131 struct psi_parser P;
132
133 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "P", &file)) {
134 return;
135 }
136
137 if (!psi_parser_init(&P, file->val, psi_error_wrapper, 0)) {
138 RETURN_FALSE;
139 }
140
141 while (0 < psi_parser_scan(&P)) {
142 psi_parser_parse(&P, psi_token_alloc(&P));
143 if (P.num == PSI_T_EOF) {
144 break;
145 }
146 }
147 psi_parser_parse(&P, NULL);
148
149 if (0 == psi_context_validate_data(NULL, PSI_DATA(&P)) && !P.errors) {
150 RETVAL_TRUE;
151 } else {
152 RETVAL_FALSE;
153 }
154 psi_parser_dtor(&P);
155 }
156
157 static PHP_MINIT_FUNCTION(psi)
158 {
159 struct psi_context_ops *ops = NULL;
160 zend_class_entry ce = {0};
161 unsigned flags = psi_check_env("PSI_DEBUG") ? PSI_PARSER_DEBUG : (
162 psi_check_env("PSI_SILENT") ? PSI_PARSER_SILENT : 0);
163
164 REGISTER_INI_ENTRIES();
165
166 INIT_NS_CLASS_ENTRY(ce, "psi", "object", NULL);
167 psi_class_entry = zend_register_internal_class_ex(&ce, NULL);
168 psi_class_entry->create_object = psi_object_init;
169
170 memcpy(&psi_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
171 psi_object_handlers.offset = XtOffsetOf(psi_object, std);
172 psi_object_handlers.free_obj = psi_object_free;
173 psi_object_handlers.clone_obj = NULL;
174
175 #ifdef HAVE_LIBJIT
176 if (!strcasecmp(PSI_G(engine), "jit")) {
177 ops = psi_libjit_ops();
178 } else
179 #endif
180 #ifdef HAVE_LIBFFI
181 ops = psi_libffi_ops();
182 #endif
183
184 if (!ops) {
185 php_error(E_WARNING, "No PSI engine found");
186 return FAILURE;
187 }
188
189 psi_context_init(&PSI_G(context), ops, psi_error_wrapper, flags);
190 psi_context_build(&PSI_G(context), PSI_G(directory));
191
192 if (psi_check_env("PSI_DUMP")) {
193 psi_context_dump(&PSI_G(context), STDOUT_FILENO);
194 }
195
196 return SUCCESS;
197 }
198
199 static PHP_MSHUTDOWN_FUNCTION(psi)
200 {
201 psi_context_dtor(&PSI_G(context));
202
203 UNREGISTER_INI_ENTRIES();
204
205 return SUCCESS;
206 }
207
208 #if defined(COMPILE_DL_PSI) && defined(ZTS)
209 static PHP_RINIT_FUNCTION(psi)
210 {
211 ZEND_TSRMLS_CACHE_UPDATE();
212 return SUCCESS;
213 }
214 #endif
215
216 static PHP_MINFO_FUNCTION(psi)
217 {
218 php_info_print_table_start();
219 php_info_print_table_header(2, "psi support", "enabled");
220 php_info_print_table_end();
221
222 DISPLAY_INI_ENTRIES();
223 }
224
225 static const zend_function_entry psi_functions[] = {
226 PHP_FE(psi_dump, ai_psi_dump)
227 PHP_FE(psi_validate, ai_psi_validate)
228 PHP_FE_END
229 };
230
231 zend_module_entry psi_module_entry = {
232 STANDARD_MODULE_HEADER,
233 "psi",
234 psi_functions,
235 PHP_MINIT(psi),
236 PHP_MSHUTDOWN(psi),
237 #if defined(COMPILE_DL_PSI) && defined(ZTS)
238 PHP_RINIT(psi), /* Replace with NULL if there's nothing to do at request start */
239 #else
240 NULL,
241 #endif
242 NULL,
243 PHP_MINFO(psi),
244 PHP_PSI_VERSION,
245 STANDARD_MODULE_PROPERTIES
246 };
247
248 #ifdef COMPILE_DL_PSI
249 #ifdef ZTS
250 ZEND_TSRMLS_CACHE_DEFINE();
251 #endif
252 ZEND_GET_MODULE(psi)
253 #endif
254
255 /*
256 * Local variables:
257 * tab-width: 4
258 * c-basic-offset: 4
259 * End:
260 * vim600: noet sw=4 ts=4 fdm=marker
261 * vim<600: noet sw=4 ts=4
262 */