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