flush
authorMichael Wallner <mike@php.net>
Tue, 20 Oct 2015 17:08:55 +0000 (19:08 +0200)
committerMichael Wallner <mike@php.net>
Tue, 20 Oct 2015 17:08:55 +0000 (19:08 +0200)
13 files changed:
idl/old/compiler.h [deleted file]
idl/old/lexer.h [deleted file]
idl/old/validator.h [deleted file]
src/context.c
src/context.h
src/libjit.c
src/parser.h
src/parser.re
src/parser_proc.h
src/parser_proc.y
tests/idn/idn.psi [new file with mode: 0644]
tests/idn/idn001.phpt [new file with mode: 0644]
tests/idn/idn002.phpt [new file with mode: 0644]

diff --git a/idl/old/compiler.h b/idl/old/compiler.h
deleted file mode 100644 (file)
index 1dce838..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#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
diff --git a/idl/old/lexer.h b/idl/old/lexer.h
deleted file mode 100644 (file)
index 1e955a7..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#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
diff --git a/idl/old/validator.h b/idl/old/validator.h
deleted file mode 100644 (file)
index 0b8a279..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#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
index 825682d46624f3be6eddeaf0f06a094f04967771..7670462cd255e8769f0d01caa7ffa3ae803d8729 100644 (file)
@@ -6,6 +6,7 @@
 #include "php.h"
 #include "php_scandir.h"
 #include "context.h"
 #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)
 #include "validator.h"
 
 PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErrorFunc error)
@@ -39,6 +40,7 @@ void PSI_ContextBuild(PSI_Context *C, const char *path)
        n = php_scandir(path, &entries, psi_select_dirent, alphasort);
 
        if (n < 0) {
        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];
                C->error(PSI_WARNING, "Failed to scan PSI directory '%s'", path);
        } else for (i = 0; i < n; ++i) {
                char psi[MAXPATHLEN];
@@ -67,12 +69,39 @@ void PSI_ContextBuild(PSI_Context *C, const char *path)
                PSI_ParserDtor(&P);
 
                if (PSI_ValidatorValidate(&V)) {
                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!");
                        }
                        if (closures && SUCCESS != zend_register_functions(NULL, closures, NULL, MODULE_PERSISTENT)) {
                                C->error(PSI_WARNING, "Failed to register functions!");
                        }
-
                }
                PSI_ValidatorDtor(&V);
        }
                }
                PSI_ValidatorDtor(&V);
        }
@@ -109,8 +138,13 @@ void PSI_ContextDtor(PSI_Context *C)
 
        for (i = 0; i < C->count; ++i) {
                PSI_DataDtor(&C->data[i]);
 
        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->data);
+       free(C->closures);
 
        memset(C, 0, sizeof(*C));
 }
 
        memset(C, 0, sizeof(*C));
 }
index 24bdb9c5a8083d450c3dc5445ae812acfee84f6b..6e86e448caa8f3bc304496411d5a195300125fef 100644 (file)
@@ -28,6 +28,7 @@ struct PSI_Context {
 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);
 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);
 
 void PSI_ContextDtor(PSI_Context *C);
 void PSI_ContextFree(PSI_Context **C);
 
index 5dc011f47eb082e029189f577417cf80a684070a..5cc8525931c4f63999b3fe7640d80b4a14562cda 100644 (file)
@@ -109,7 +109,7 @@ static inline PSI_ClosureData *PSI_ClosureDataAlloc(void *context, impl *impl) {
 static inline impl_val *deref(unsigned level, impl_val *ret_val, decl_arg *darg) {
        unsigned i;
 
 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;
        }
 
                ret_val = *(void **)ret_val;
        }
 
@@ -135,7 +135,12 @@ static void to_string(impl_val *ret_val, decl_arg *func, zval *return_value) {
                        char chr = ret_val->lval;
                        RETVAL_STRINGL(&chr, 1);
                } else {
                        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:
                }
                break;
        case PSI_T_FLOAT:
@@ -270,6 +275,7 @@ static void handle_rval(impl *impl, impl_val *ret_val, zval *return_value) {
 static void handle_set(zval *return_value, set_func *func, decl_vars *vars) {
        impl_val *val = &vars->vars[0]->arg->let->ptr;
 
 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) {
        zval_dtor(return_value);
 
        switch (func->type) {
index 0ed55ca97391d8f7daa0ccd066a630a46740d96a..d7393d443cb831b0cde5a08d7d8e1db3a287d921 100644 (file)
@@ -689,18 +689,81 @@ static void free_impls(impls *impls) {
        free(impls);
 }
 
        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, ...);
 
 #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 \
 #define PSI_DATA_MEMBERS \
+       constants *consts; \
        decl_typedefs *defs; \
        decls *decls; \
        impls *impls; \
        char *lib; \
        char *fn; \
        psi_error_cb error
        decl_typedefs *defs; \
        decls *decls; \
        impls *impls; \
        char *lib; \
        char *fn; \
        psi_error_cb error
+typedef struct PSI_Data {
        PSI_DATA_MEMBERS;
 } PSI_Data;
 
        PSI_DATA_MEMBERS;
 } PSI_Data;
 
@@ -710,6 +773,9 @@ static inline void PSI_DataExchange(PSI_Data *dest, PSI_Data *src) {
 }
 
 static inline void PSI_DataDtor(PSI_Data *data) {
 }
 
 static inline void PSI_DataDtor(PSI_Data *data) {
+       if (data->consts) {
+               free_constants(data->consts);
+       }
        if (data->defs) {
                free_decl_typedefs(data->defs);
        }
        if (data->defs) {
                free_decl_typedefs(data->defs);
        }
index d0daecb92e2a7163a7f35c8b076df8756dfe7457..0d13d79697cb334d108ee9f2423da6896a42eadb 100644 (file)
@@ -201,6 +201,7 @@ token_t PSI_ParserScan(PSI_Parser *P)
                ARRAY = 'array';
                FUNCTION = 'function';
                TYPEDEF = 'typedef';
                ARRAY = 'array';
                FUNCTION = 'function';
                TYPEDEF = 'typedef';
+               CONST = 'const';
                LIB = 'lib';
                LET = 'let';
                SET = 'set';
                LIB = 'lib';
                LET = 'let';
                SET = 'set';
@@ -255,6 +256,7 @@ token_t PSI_ParserScan(PSI_Parser *P)
                ARRAY {RETURN(PSI_T_ARRAY);}
                FUNCTION {RETURN(PSI_T_FUNCTION);}
                TYPEDEF {RETURN(PSI_T_TYPEDEF);}
                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);}
                LIB {RETURN(PSI_T_LIB);}
                LET {RETURN(PSI_T_LET);}
                SET {RETURN(PSI_T_SET);}
index e5d418a4ca7989a67a5a00bec0cd605de9a50ce3..b025185ad23ce04235e07867141a24a20f0dc5b6 100644 (file)
@@ -2,53 +2,54 @@
 #define PSI_T_LIB                              2
 #define PSI_T_QUOTED_STRING                    3
 #define PSI_T_EOS                              4
 #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
index 3dc06e28bff2a0e7a631465283d8081e664377c7..f7bec637acac659b4a9dcc7f32e04d1dc0b5956e 100644 (file)
@@ -42,6 +42,32 @@ block ::= impl(impl). {
 block ::= decl_typedef(def). {
        P->defs = add_decl_typedef(P->defs, def);
 }
 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 decl_typedef {decl_typedef*}
 decl_typedef(def) ::= TYPEDEF NAME(ALIAS) decl_type(type) EOS. {
@@ -158,6 +184,7 @@ decl_type(type_) ::= NAME(T). {
 }
 
 %type impl {impl*}
 }
 
 %type impl {impl*}
+%destructor impl {free_impl($$);}
 impl(impl) ::= impl_func(func) LBRACE impl_stmts(stmts) RBRACE. {
        impl = init_impl(func, stmts);
 }
 impl(impl) ::= impl_func(func) LBRACE impl_stmts(stmts) RBRACE. {
        impl = init_impl(func, stmts);
 }
@@ -223,6 +250,7 @@ impl_arg_list(args) ::= impl_arg_list(args_) COMMA impl_arg(arg). {
 }
 
 %type impl_stmts {impl_stmts*}
 }
 
 %type impl_stmts {impl_stmts*}
+%destructor impl_stmts {free_impl_stmts($$);}
 impl_stmts(stmts) ::= impl_stmt(stmt). {
        stmts = init_impl_stmts(stmt);
 }
 impl_stmts(stmts) ::= impl_stmt(stmt). {
        stmts = init_impl_stmts(stmt);
 }
@@ -231,6 +259,7 @@ impl_stmts(stmts) ::= impl_stmts(stmts_) impl_stmt(stmt). {
 }
 
 %type impl_stmt {impl_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);
 }
 impl_stmt(stmt) ::= let_stmt(let). {
        stmt = init_impl_stmt(PSI_T_LET, let);
 }
diff --git a/tests/idn/idn.psi b/tests/idn/idn.psi
new file mode 100644 (file)
index 0000000..1583680
--- /dev/null
@@ -0,0 +1,36 @@
+# 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);
+}
diff --git a/tests/idn/idn001.phpt b/tests/idn/idn001.phpt
new file mode 100644 (file)
index 0000000..c5d19c6
--- /dev/null
@@ -0,0 +1,22 @@
+--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
diff --git a/tests/idn/idn002.phpt b/tests/idn/idn002.phpt
new file mode 100644 (file)
index 0000000..9f092b1
--- /dev/null
@@ -0,0 +1,23 @@
+--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