7 #include "php_scandir.h"
10 #include "validator.h"
12 #define psi_predef_count(s) (sizeof(psi_predef_ ##s## s)/sizeof(psi_predef ##s))
13 typedef struct psi_predef_type
{
15 const char *type_name
;
18 #define psi_predef_type_count() psi_predef_count(type)
19 static const psi_predef_types
[] = {
23 typedef struct psi_predef_const
{
25 const char *type_name
;
30 #define psi_predef_const_count() psi_predef_count(const)
31 static const psi_predef_consts
[] = {
35 PSI_Context
*PSI_ContextInit(PSI_Context
*C
, PSI_ContextOps
*ops
, PSI_ContextErrorFunc error
)
41 C
= malloc(sizeof(*C
));
43 memset(C
, 0, sizeof(*C
));
49 memset(&data
, 0, sizeof(data
));
50 for (i
= 0; i
< psi_predef_type_count(); ++i
) {
51 psi_predef_type
*pre
= &psi_predef_types
[i
];
52 decl_type
*type
= init_decl_type(pre
->type_tag
, pre
->type_name
);
53 decl_typedef
*def
= init_decl_typedef(pre
->alias
, type
);
55 data
.defs
= add_decl_typedef(data
.defs
, def
);
57 for (i
= 0; i
< psi_predef_const_count(); ++i
) {
58 psi_predef_const
*pre
= psi_predef_const
[i
];
59 impl_def_val
*val
= init_impl_def_val(pre
->val_type_tag
, pre
->val_text
);
60 const_type
*type
= init_const_type(pre
->type_tag
, pre
->type_name
);
61 constant
*constant
= init_constant(type
, pre
->name
, val
);
63 data
.consts
= add_constant(data
.consts
, constant
);
68 static int psi_select_dirent(const struct dirent
*entry
)
71 #define FNM_CASEFOLD 0
73 return 0 == fnmatch("*.psi", entry
->d_name
, FNM_CASEFOLD
);
77 void PSI_ContextBuild(PSI_Context
*C
, const char *path
)
80 struct dirent
**entries
= NULL
;
82 n
= php_scandir(path
, &entries
, psi_select_dirent
, alphasort
);
86 } else for (i
= 0; i
< n
; ++i
) {
91 if (MAXPATHLEN
<= slprintf(psi
, MAXPATHLEN
, "%s/%s", path
, entries
[i
]->d_name
)) {
92 C
->error(PSI_WARNING
, "Path to PSI file too long: %s/%s",
93 path
, entries
[i
]->d_name
);
95 if (!PSI_ParserInit(&P
, psi
, C
->error
, 0)) {
96 C
->error(PSI_WARNING
, "Failed to init PSI parser (%s): %s",
97 psi
, strerror(errno
));
101 while (-1 != PSI_ParserScan(&P
)) {
102 PSI_ParserParse(&P
, PSI_TokenAlloc(&P
));
104 PSI_ParserParse(&P
, NULL
);
106 if (!PSI_ValidatorInit(&V
, &P
)) {
107 C
->error(PSI_WARNING
, "Failed to init PSI validator");
112 if (PSI_ValidatorValidate(&V
)) {
113 zend_function_entry
*closures
;
115 closures
= PSI_ContextCompile(C
, (PSI_Data
*) &V
);
116 if (closures
&& SUCCESS
!= zend_register_functions(NULL
, closures
, NULL
, MODULE_PERSISTENT
)) {
117 C
->error(PSI_WARNING
, "Failed to register functions!");
120 PSI_ValidatorDtor(&V
);
123 for (i
= 0; i
< n
; ++i
) {
131 zend_function_entry
*PSI_ContextCompile(PSI_Context
*C
, PSI_Data
*D
)
133 size_t i
, count
= C
->count
++;
134 zend_function_entry
*zfe
;
139 zc
.flags
= CONST_PERSISTENT
|CONST_CS
;
140 zc
.module_number
= EG(current_module
)->module_number
;
142 for (i
= 0; i
< D
->consts
->count
; ++i
) {
143 constant
*c
= D
->consts
->list
[i
];
145 zc
.name
= zend_string_init(c
->name
+ (c
->name
[0] == '\\'), strlen(c
->name
) - (c
->name
[0] == '\\'), 1);
146 ZVAL_NEW_STR(&zc
.value
, zend_string_init(c
->val
->text
, strlen(c
->val
->text
), 1));
148 switch (c
->type
->type
) {
150 convert_to_boolean(&zc
.value
);
153 convert_to_long(&zc
.value
);
156 convert_to_double(&zc
.value
);
159 zend_register_constant(&zc
);
163 C
->data
= realloc(C
->data
, C
->count
* sizeof(*C
->data
));
164 PSI_DataExchange(&C
->data
[count
], D
);
166 zfe
= C
->ops
->compile(C
, &C
->data
[count
]);
168 C
->closures
= realloc(C
->closures
, C
->count
* sizeof(*C
->closures
));
169 C
->closures
[count
] = zfe
;
174 void PSI_ContextDtor(PSI_Context
*C
)
180 for (i
= 0; i
< C
->count
; ++i
) {
181 PSI_DataDtor(&C
->data
[i
]);
183 free(C
->closures
[i
]);
189 memset(C
, 0, sizeof(*C
));
192 void PSI_ContextFree(PSI_Context
**C
)