389cbc5752e123fc33cd1fab4eb8a4f7c264da80
[m6w6/ext-psi] / src / module.c
1
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5
6 #include <jit/jit.h>
7 #include <dirent.h>
8 #include <fnmatch.h>
9
10 #include "php.h"
11 #include "php_ini.h"
12 #include "ext/standard/info.h"
13 #include "php_scandir.h"
14
15 #include "php_psi.h"
16
17 #include "parser.h"
18 #include "validator.h"
19 #include "compiler.h"
20
21 ZEND_DECLARE_MODULE_GLOBALS(psi);
22
23 PHP_INI_BEGIN()
24 STD_PHP_INI_ENTRY("psi.directory", "psis", PHP_INI_ALL, OnUpdateString, directory, zend_psi_globals, psi_globals)
25 PHP_INI_END();
26
27 static int psi_select_dirent(const struct dirent *entry)
28 {
29 return 0 == fnmatch("*.psi", entry->d_name, FNM_CASEFOLD);
30 }
31
32 PHP_MINIT_FUNCTION(psi)
33 {
34 jit_context_t ctx;
35 int i, n;
36 struct dirent **entries = NULL;
37
38 REGISTER_INI_ENTRIES();
39
40 jit_init();
41
42 if (!(ctx = jit_context_create())) {
43 zend_error(E_WARNING, "Could not initialize libjit!");
44 return FAILURE;
45 }
46
47 PSI_G(context) = ctx;
48
49 n = php_scandir(PSI_G(directory), &entries, psi_select_dirent, alphasort);
50 if (n < 0) {
51 php_error(E_WARNING, "Failed to scan PSI directory '%s'", PSI_G(directory));
52 } else for (i = 0; i < n; ++i) {
53 char psi[MAXPATHLEN];
54 PSI_Parser P;
55 PSI_Validator V;
56
57 if (MAXPATHLEN <= slprintf(psi, MAXPATHLEN, "%s/%s", PSI_G(directory), entries[i]->d_name)) {
58 php_error(E_WARNING, "Path to PSI file too long: %s/%s",
59 PSI_G(directory), entries[i]->d_name);
60 }
61 if (!PSI_ParserInit(&P, psi, 0)) {
62 php_error(E_WARNING, "Failed to init PSI parser (%s): %s",
63 psi, strerror(errno));
64 continue;
65 }
66
67 while (-1 != PSI_ParserScan(&P)) {
68 PSI_ParserParse(&P, PSI_TokenAlloc(&P));
69 };
70 PSI_ParserParse(&P, NULL);
71
72 if (!PSI_ValidatorInit(&V, &P)) {
73 php_error(E_WARNING, "Failed to init PSI validator");
74 break;
75 }
76 PSI_ParserDtor(&P);
77
78 if (PSI_ValidatorValidate(&V)) {
79 PSI_Compiler C;
80
81 jit_context_build_start(ctx);
82 if (PSI_CompilerInit(&C, &V, ctx)) {
83 zend_function_entry *closures = PSI_CompilerCompile(&C);
84
85 if (closures) {
86 zend_register_functions(NULL, closures, NULL, MODULE_PERSISTENT);
87 }
88 PSI_CompilerDtor(&C);
89 }
90 jit_context_build_end(ctx);
91 }
92 PSI_ValidatorDtor(&V);
93 }
94 if (entries) {
95 for (i = 0; i < n; ++i) {
96 free(entries[i]);
97 }
98 free(entries);
99 }
100 return SUCCESS;
101 }
102 PHP_MSHUTDOWN_FUNCTION(psi)
103 {
104 jit_context_t ctx = PSI_G(context);
105 jit_context_destroy(ctx);
106
107 UNREGISTER_INI_ENTRIES();
108
109 return SUCCESS;
110 }
111
112 /* Remove if there's nothing to do at request start */
113 /* {{{ PHP_RINIT_FUNCTION
114 */
115 PHP_RINIT_FUNCTION(psi)
116 {
117 #if defined(COMPILE_DL_PSI) && defined(ZTS)
118 ZEND_TSRMLS_CACHE_UPDATE();
119 #endif
120 return SUCCESS;
121 }
122 /* }}} */
123
124 /* Remove if there's nothing to do at request end */
125 /* {{{ PHP_RSHUTDOWN_FUNCTION
126 */
127 PHP_RSHUTDOWN_FUNCTION(psi)
128 {
129 return SUCCESS;
130 }
131 /* }}} */
132
133 PHP_MINFO_FUNCTION(psi)
134 {
135 php_info_print_table_start();
136 php_info_print_table_header(2, "psi support", "enabled");
137 php_info_print_table_end();
138
139 DISPLAY_INI_ENTRIES();
140 }
141 const zend_function_entry psi_functions[] = {
142 PHP_FE_END
143 };
144
145 zend_module_entry psi_module_entry = {
146 STANDARD_MODULE_HEADER,
147 "psi",
148 psi_functions,
149 PHP_MINIT(psi),
150 PHP_MSHUTDOWN(psi),
151 PHP_RINIT(psi), /* Replace with NULL if there's nothing to do at request start */
152 PHP_RSHUTDOWN(psi), /* Replace with NULL if there's nothing to do at request end */
153 PHP_MINFO(psi),
154 PHP_PSI_VERSION,
155 STANDARD_MODULE_PROPERTIES
156 };
157
158 #ifdef COMPILE_DL_PSI
159 #ifdef ZTS
160 ZEND_TSRMLS_CACHE_DEFINE();
161 #endif
162 ZEND_GET_MODULE(psi)
163 #endif
164
165 /*
166 * Local variables:
167 * tab-width: 4
168 * c-basic-offset: 4
169 * End:
170 * vim600: noet sw=4 ts=4 fdm=marker
171 * vim<600: noet sw=4 ts=4
172 */