+++ /dev/null
-#ifndef _PSI_COMPILER_H
-#define _PSI_COMPILER_H
-
-#include "types.h"
-#include "validator.h"
-
-typedef struct PSI_Compiler {
- decl_typedefs *defs;
- decls *decls;
- impls *impls;
- char *lib;
- char *fn;
-} PSI_Compiler;
-
-PSI_Compiler *PSI_CompilerInit(PSI_Compiler *C, PSI_Validator *V);
-void PSI_CompilerDtor(PSI_Compiler *C);
-void PSI_CompilerFree(PSI_Compiler **C);
-
-#endif
+++ /dev/null
-#ifndef _PSI_LEXER_H
-#define _PSI_LEXER_H
-
-#include "types.h"
-
-#define BSIZE 256
-
-
-PSI_Lexer *PSI_LexerInit(PSI_Lexer *L, const char *filename);
-size_t PSI_LexerFill(PSI_Lexer *L, size_t n);
-token_t PSI_LexerScan(PSI_Lexer *L);
-void PSI_LexerDtor(PSI_Lexer *L);
-void PSI_LexerFree(PSI_Lexer **L);
-
-PSI_Token *PSI_TokenAlloc(PSI_Lexer *L, token_t t);
-
-#endif
+++ /dev/null
-#ifndef _PSI_VALIDATOR_H
-#define _PSI_VALIDATOR_H
-
-#include "types.h"
-#include "lexer.h"
-
-typedef struct PSI_Validator {
- decl_typedefs *defs;
- decls *decls;
- impls *impls;
- char *lib;
- char *fn;
- void *dlopened;
-} PSI_Validator;
-
-PSI_Validator *PSI_ValidatorInit(PSI_Validator *V, PSI_Lexer *L);
-int PSI_ValidatorValidate(PSI_Validator *V);
-void PSI_ValidatorDtor(PSI_Validator *V);
-void PSI_ValidatorFree(PSI_Validator **V);
-
-#endif
#include "php.h"
#include "php_scandir.h"
#include "context.h"
+#include "parser.h"
#include "validator.h"
PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErrorFunc error)
n = php_scandir(path, &entries, psi_select_dirent, alphasort);
if (n < 0) {
+ return;
C->error(PSI_WARNING, "Failed to scan PSI directory '%s'", path);
} else for (i = 0; i < n; ++i) {
char psi[MAXPATHLEN];
PSI_ParserDtor(&P);
if (PSI_ValidatorValidate(&V)) {
- zend_function_entry *closures = PSI_ContextCompile(C, (PSI_Data *) &V);
+ zend_function_entry *closures;
+
+ if (V.consts) {
+ zend_constant zc;
+
+ zc.flags = CONST_PERSISTENT|CONST_CS;
+ zc.module_number = EG(current_module)->module_number;
+
+ for (i = 0; i < V.consts->count; ++i) {
+ constant *c = V.consts->list[i];
+
+ zc.name = zend_string_init(c->name + (c->name[0] == '\\'), strlen(c->name) - (c->name[0] == '\\'), 1);
+ ZVAL_NEW_STR(&zc.value, zend_string_init(c->val->text, strlen(c->val->text), 1));
+
+ switch (c->type->type) {
+ case PSI_T_BOOL:
+ convert_to_boolean(&zc.value);
+ break;
+ case PSI_T_INT:
+ convert_to_long(&zc.value);
+ break;
+ case PSI_T_FLOAT:
+ convert_to_double(&zc.value);
+ break;
+ }
+ zend_register_constant(&zc);
+ }
+ }
+ closures = PSI_ContextCompile(C, (PSI_Data *) &V);
if (closures && SUCCESS != zend_register_functions(NULL, closures, NULL, MODULE_PERSISTENT)) {
C->error(PSI_WARNING, "Failed to register functions!");
}
-
}
PSI_ValidatorDtor(&V);
}
for (i = 0; i < C->count; ++i) {
PSI_DataDtor(&C->data[i]);
+ if (C->closures[i]){
+ free(C->closures[i]->arg_info);
+ free(C->closures[i]);
+ }
}
free(C->data);
+ free(C->closures);
memset(C, 0, sizeof(*C));
}
PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErrorFunc error);
void PSI_ContextBuild(PSI_Context *C, const char *path);
zend_function_entry *PSI_ContextCompile(PSI_Context *C, PSI_Data *D);
+zend_constant a;
void PSI_ContextDtor(PSI_Context *C);
void PSI_ContextFree(PSI_Context **C);
static inline impl_val *deref(unsigned level, impl_val *ret_val, decl_arg *darg) {
unsigned i;
- for (i = level; i < darg->var->pointer_level; ++i) {
+ for (i = level; i < darg->var->pointer_level; ++i && ret_val->ptr) {
ret_val = *(void **)ret_val;
}
char chr = ret_val->lval;
RETVAL_STRINGL(&chr, 1);
} else {
- RETVAL_STRING(deref(1, ret_val, func)->ptr);
+ ret_val = deref(1, ret_val, func);
+ if (ret_val->ptr) {
+ RETVAL_STRING(ret_val->ptr);
+ } else {
+ RETVAL_EMPTY_STRING();
+ }
}
break;
case PSI_T_FLOAT:
static void handle_set(zval *return_value, set_func *func, decl_vars *vars) {
impl_val *val = &vars->vars[0]->arg->let->ptr;
+ ZVAL_DEREF(return_value);
zval_dtor(return_value);
switch (func->type) {
free(impls);
}
+typedef struct const_type {
+ token_t type;
+ char *name;
+} const_type;
+
+static inline const_type *init_const_type(token_t type, const char *name) {
+ const_type *ct = malloc(sizeof(*ct));
+ ct->type = type;
+ ct->name = strdup(name);
+ return ct;
+}
+
+static inline void free_const_type(const_type *type) {
+ free(type->name);
+ free(type);
+}
+
+typedef struct constant {
+ const_type *type;
+ char *name;
+ impl_def_val *val;
+} constant;
+
+static inline constant *init_constant(const_type *type, char *name, impl_def_val *val) {
+ constant *c = malloc(sizeof(*c));
+ c->type = type;
+ c->name = strdup(name);
+ c->val = val;
+ return c;
+}
+
+static inline void free_constant(constant *constant) {
+ free_const_type(constant->type);
+ free(constant->name);
+ free_impl_def_val(constant->val);
+ free(constant);
+}
+
+typedef struct constants {
+ size_t count;
+ constant **list;
+} constants;
+
+static inline constants *add_constant(constants *constants, constant *constant) {
+ if (!constants) {
+ constants = calloc(1, sizeof(*constants));
+ }
+ constants->list = realloc(constants->list, ++constants->count * sizeof(*constants->list));
+ constants->list[constants->count-1] = constant;
+ return constants;
+}
+
+static inline void free_constants(constants *c) {
+ size_t i;
+
+ for (i = 0; i < c->count; ++i) {
+ free_constant(c->list[i]);
+ }
+ free(c->list);
+ free(c);
+}
+
#define PSI_ERROR 16
#define PSI_WARNING 32
typedef void (*psi_error_cb)(int type, const char *msg, ...);
-typedef struct PSI_Data {
#define PSI_DATA_MEMBERS \
+ constants *consts; \
decl_typedefs *defs; \
decls *decls; \
impls *impls; \
char *lib; \
char *fn; \
psi_error_cb error
+typedef struct PSI_Data {
PSI_DATA_MEMBERS;
} PSI_Data;
}
static inline void PSI_DataDtor(PSI_Data *data) {
+ if (data->consts) {
+ free_constants(data->consts);
+ }
if (data->defs) {
free_decl_typedefs(data->defs);
}
ARRAY = 'array';
FUNCTION = 'function';
TYPEDEF = 'typedef';
+ CONST = 'const';
LIB = 'lib';
LET = 'let';
SET = 'set';
ARRAY {RETURN(PSI_T_ARRAY);}
FUNCTION {RETURN(PSI_T_FUNCTION);}
TYPEDEF {RETURN(PSI_T_TYPEDEF);}
+ CONST {RETURN(PSI_T_CONST);}
LIB {RETURN(PSI_T_LIB);}
LET {RETURN(PSI_T_LET);}
SET {RETURN(PSI_T_SET);}
#define PSI_T_LIB 2
#define PSI_T_QUOTED_STRING 3
#define PSI_T_EOS 4
-#define PSI_T_TYPEDEF 5
-#define PSI_T_NAME 6
-#define PSI_T_LPAREN 7
-#define PSI_T_RPAREN 8
-#define PSI_T_COMMA 9
-#define PSI_T_VOID 10
-#define PSI_T_CHAR 11
-#define PSI_T_SHORT 12
-#define PSI_T_INT 13
-#define PSI_T_LONG 14
-#define PSI_T_FLOAT 15
-#define PSI_T_DOUBLE 16
-#define PSI_T_SINT8 17
-#define PSI_T_UINT8 18
-#define PSI_T_SINT16 19
-#define PSI_T_UINT16 20
-#define PSI_T_SINT32 21
-#define PSI_T_UINT32 22
-#define PSI_T_SINT64 23
-#define PSI_T_UINT64 24
-#define PSI_T_LBRACE 25
-#define PSI_T_RBRACE 26
-#define PSI_T_FUNCTION 27
-#define PSI_T_NSNAME 28
-#define PSI_T_COLON 29
-#define PSI_T_REFERENCE 30
-#define PSI_T_NULL 31
-#define PSI_T_NUMBER 32
-#define PSI_T_TRUE 33
-#define PSI_T_FALSE 34
-#define PSI_T_DOLLAR 35
-#define PSI_T_EQUALS 36
-#define PSI_T_LET 37
-#define PSI_T_STRLEN 38
-#define PSI_T_STRVAL 39
-#define PSI_T_INTVAL 40
-#define PSI_T_FLOATVAL 41
-#define PSI_T_BOOLVAL 42
-#define PSI_T_SET 43
-#define PSI_T_TO_STRING 44
-#define PSI_T_TO_INT 45
-#define PSI_T_TO_FLOAT 46
-#define PSI_T_TO_BOOL 47
-#define PSI_T_RETURN 48
-#define PSI_T_FREE 49
-#define PSI_T_MIXED 50
-#define PSI_T_BOOL 51
-#define PSI_T_STRING 52
-#define PSI_T_ARRAY 53
-#define PSI_T_POINTER 54
+#define PSI_T_BOOL 5
+#define PSI_T_INT 6
+#define PSI_T_FLOAT 7
+#define PSI_T_STRING 8
+#define PSI_T_CONST 9
+#define PSI_T_NSNAME 10
+#define PSI_T_EQUALS 11
+#define PSI_T_TYPEDEF 12
+#define PSI_T_NAME 13
+#define PSI_T_LPAREN 14
+#define PSI_T_RPAREN 15
+#define PSI_T_COMMA 16
+#define PSI_T_VOID 17
+#define PSI_T_CHAR 18
+#define PSI_T_SHORT 19
+#define PSI_T_LONG 20
+#define PSI_T_DOUBLE 21
+#define PSI_T_SINT8 22
+#define PSI_T_UINT8 23
+#define PSI_T_SINT16 24
+#define PSI_T_UINT16 25
+#define PSI_T_SINT32 26
+#define PSI_T_UINT32 27
+#define PSI_T_SINT64 28
+#define PSI_T_UINT64 29
+#define PSI_T_LBRACE 30
+#define PSI_T_RBRACE 31
+#define PSI_T_FUNCTION 32
+#define PSI_T_COLON 33
+#define PSI_T_REFERENCE 34
+#define PSI_T_NULL 35
+#define PSI_T_NUMBER 36
+#define PSI_T_TRUE 37
+#define PSI_T_FALSE 38
+#define PSI_T_DOLLAR 39
+#define PSI_T_LET 40
+#define PSI_T_STRLEN 41
+#define PSI_T_STRVAL 42
+#define PSI_T_INTVAL 43
+#define PSI_T_FLOATVAL 44
+#define PSI_T_BOOLVAL 45
+#define PSI_T_SET 46
+#define PSI_T_TO_STRING 47
+#define PSI_T_TO_INT 48
+#define PSI_T_TO_FLOAT 49
+#define PSI_T_TO_BOOL 50
+#define PSI_T_RETURN 51
+#define PSI_T_FREE 52
+#define PSI_T_MIXED 53
+#define PSI_T_ARRAY 54
+#define PSI_T_POINTER 55
block ::= decl_typedef(def). {
P->defs = add_decl_typedef(P->defs, def);
}
+block ::= constant(constant). {
+ P->consts = add_constant(P->consts, constant);
+}
+
+%type const_type {const_type*}
+const_type(type_) ::= BOOL(T). {
+ type_ = init_const_type(T->type, T->text);
+ free(T);
+}
+const_type(type_) ::= INT(T). {
+ type_ = init_const_type(T->type, T->text);
+ free(T);
+}
+const_type(type_) ::= FLOAT(T). {
+ type_ = init_const_type(T->type, T->text);
+ free(T);
+}
+const_type(type_) ::= STRING(T). {
+ type_ = init_const_type(T->type, T->text);
+ free(T);
+}
+%type constant {constant*}
+constant(constant) ::= CONST const_type(type) NSNAME(T) EQUALS impl_def_val(val) EOS. {
+ constant = init_constant(type, T->text, val);
+ free(T);
+}
%type decl_typedef {decl_typedef*}
decl_typedef(def) ::= TYPEDEF NAME(ALIAS) decl_type(type) EOS. {
}
%type impl {impl*}
+%destructor impl {free_impl($$);}
impl(impl) ::= impl_func(func) LBRACE impl_stmts(stmts) RBRACE. {
impl = init_impl(func, stmts);
}
}
%type impl_stmts {impl_stmts*}
+%destructor impl_stmts {free_impl_stmts($$);}
impl_stmts(stmts) ::= impl_stmt(stmt). {
stmts = init_impl_stmts(stmt);
}
}
%type impl_stmt {impl_stmt*}
+%destructor impl_stmt {free_impl_stmt($$);}
impl_stmt(stmt) ::= let_stmt(let). {
stmt = init_impl_stmt(PSI_T_LET, let);
}
--- /dev/null
+# libidn
+lib "idn";
+
+# IDNA errors
+const int \IDNA_SUCCESS = 0;
+const int \IDNA_STRINGPREP_ERROR = 1;
+const int \IDNA_PUNYCODE_ERROR = 2;
+const int \IDNA_CONTAINS_NON_LDH = 3;
+const int \IDNA_CONTAINS_LDH = 3;
+const int \IDNA_CONTAINS_MINUS = 4;
+const int \IDNA_INVALID_LENGTH = 5;
+const int \IDNA_NO_ACE_PREFIX = 6;
+const int \IDNA_ROUNDTRIP_VERIFY_ERROR = 7;
+const int \IDNA_CONTAINS_ACE_PREFIX = 8;
+const int \IDNA_ICONV_ERROR = 9;
+const int \IDNA_MALLOC_ERROR = 201;
+const int \IDNA_DLOPEN_ERROR = 202;
+# IDNA flags
+const int \IDNA_ALLOW_UNASSIGNED = 1;
+const int \IDNA_USE_STD3_ASCII_RULES = 2;
+
+
+default int idna_to_ascii_8z(sint8 *host, sint8 **buffer, int flags);
+function idn\utf8_to_ascii(string $host, string &$result, int $flags = 0) : int {
+ let buffer = &NULL;
+ let host = strval($host);
+ let flags = intval($flags);
+ set $result = to_string(*buffer);
+ return to_int(idna_to_ascii_8z);
+ free *buffer;
+}
+default sint8 *idna_strerror(int rc);
+function idn\strerror(int $rc) : string {
+ return to_string(idna_strerror);
+ let rc = intval($rc);
+}
--- /dev/null
+--TEST--
+libidn
+--INI--
+psi.directory={PWD}
+--SKIPIF--
+<?php
+extension_loaded("psi") or die("skip - need ext/psi");
+?>
+--FILE--
+===TEST===
+<?php
+
+$rc = idn\utf8_to_ascii("flöte.de", $result);
+printf("%s\n", $result);
+printf("%s\n", idn\strerror($rc));
+?>
+===DONE===
+--EXPECT--
+===TEST===
+xn--flte-6qa.de
+Success
+===DONE===
\ No newline at end of file
--- /dev/null
+--TEST--
+libidn
+--INI--
+psi.directory={PWD}
+--SKIPIF--
+<?php
+extension_loaded("psi") or die("skip - need ext/psi");
+?>
+--FILE--
+===TEST===
+<?php
+
+$rc = idn\utf8_to_ascii("…asdf….de", $result, IDNA_USE_STD3_ASCII_RULES);
+printf("%s\n", $result);
+printf("%s\n", idn\strerror($rc));
+
+?>
+===DONE===
+--EXPECT--
+===TEST===
+
+Non-digit/letter/hyphen in input
+===DONE===
\ No newline at end of file