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 #include "php.h"
7 #include "php_scandir.h"
8 #include "context.h"
9 #include "validator.h"
10
11 PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErrorFunc error)
12 {
13 if (!C) {
14 C = malloc(sizeof(*C));
15 }
16 memset(C, 0, sizeof(*C));
17
18 C->error = error;
19 C->ops = ops;
20 ops->init(C);
21
22 return C;
23 }
24
25 static int psi_select_dirent(const struct dirent *entry)
26 {
27 #ifndef FNM_CASEFOLD
28 #define FNM_CASEFOLD 0
29 #endif
30 return 0 == fnmatch("*.psi", entry->d_name, FNM_CASEFOLD);
31 }
32
33
34 void PSI_ContextBuild(PSI_Context *C, const char *path)
35 {
36 int i, n;
37 struct dirent **entries = NULL;
38
39 n = php_scandir(path, &entries, psi_select_dirent, alphasort);
40
41 if (n < 0) {
42 C->error(PSI_WARNING, "Failed to scan PSI directory '%s'", path);
43 } else for (i = 0; i < n; ++i) {
44 char psi[MAXPATHLEN];
45 PSI_Parser P;
46 PSI_Validator V;
47
48 if (MAXPATHLEN <= slprintf(psi, MAXPATHLEN, "%s/%s", path, entries[i]->d_name)) {
49 C->error(PSI_WARNING, "Path to PSI file too long: %s/%s",
50 path, entries[i]->d_name);
51 }
52 if (!PSI_ParserInit(&P, psi, C->error, 0)) {
53 C->error(PSI_WARNING, "Failed to init PSI parser (%s): %s",
54 psi, strerror(errno));
55 continue;
56 }
57
58 while (-1 != PSI_ParserScan(&P)) {
59 PSI_ParserParse(&P, PSI_TokenAlloc(&P));
60 };
61 PSI_ParserParse(&P, NULL);
62
63 if (!PSI_ValidatorInit(&V, &P)) {
64 C->error(PSI_WARNING, "Failed to init PSI validator");
65 break;
66 }
67 PSI_ParserDtor(&P);
68
69 if (PSI_ValidatorValidate(&V)) {
70 zend_function_entry *closures = PSI_ContextCompile(C, (PSI_Data *) &V);
71
72 if (closures && SUCCESS != zend_register_functions(NULL, closures, NULL, MODULE_PERSISTENT)) {
73 C->error(PSI_WARNING, "Failed to register functions!");
74 }
75
76 }
77 PSI_ValidatorDtor(&V);
78 }
79 if (entries) {
80 for (i = 0; i < n; ++i) {
81 free(entries[i]);
82 }
83 free(entries);
84 }
85
86 }
87
88 zend_function_entry *PSI_ContextCompile(PSI_Context *C, PSI_Data *D)
89 {
90 size_t count = C->count++;
91 zend_function_entry *zfe;
92
93 C->data = realloc(C->data, C->count * sizeof(*C->data));
94 PSI_DataExchange(&C->data[count], D);
95
96 zfe = C->ops->compile(C, &C->data[count]);
97
98 C->closures = realloc(C->closures, C->count * sizeof(*C->closures));
99 C->closures[count] = zfe;
100
101 return zfe;
102 }
103
104 void PSI_ContextDtor(PSI_Context *C)
105 {
106 size_t i;
107
108 C->ops->dtor(C);
109
110 for (i = 0; i < C->count; ++i) {
111 PSI_DataDtor(&C->data[i]);
112 }
113 free(C->data);
114
115 memset(C, 0, sizeof(*C));
116 }
117
118 void PSI_ContextFree(PSI_Context **C)
119 {
120 if (*C) {
121 PSI_ContextDtor(*C);
122 free(*C);
123 *C = NULL;
124 }
125 }
126