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