fi
], [], PSI_INCLUDES_DEFAULT($4))
])
- if test "$1" != "$psi_struct_name"
+ if test "$1" = "$psi_struct_name"
then
PSI_TYPES="{PSI_T_STRUCT, \"$psi_struct_name\", \"$psi_struct_name\"}, $PSI_TYPES"
fi
zend_internal_arg_info *psi_internal_arginfo(impl *impl);
size_t psi_num_min_args(impl *impl);
-void psi_to_bool(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var);
-void psi_to_int(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var);
-void psi_to_double(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var);
-void psi_to_string(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var);
-void psi_to_array(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var);
+void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val);
+void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val);
+void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val);
+void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val);
+void psi_to_array(zval *return_value, set_value *set, impl_val *ret_val);
void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl);
#include "context.h"
#include "parser.h"
+#include "libjit.h"
+#include "libffi.h"
+
#define psi_predef_count(of) ((sizeof(psi_predef ##of## s)/sizeof(psi_predef ##of))-1)
typedef struct psi_predef_type {
token_t type_tag;
}
static inline decl_arg *locate_struct_member(decl_struct *s, decl_var *var) {
- size_t i;
+ if (s->args) {
+ size_t i;
- ZEND_ASSERT(s);
- for (i = 0; i < s->args->count; ++i) {
- decl_arg *darg = s->args->args[i];
+ for (i = 0; i < s->args->count; ++i) {
+ decl_arg *darg = s->args->args[i];
- if (!strcmp(var->name, darg->var->name)) {
- return var->arg = darg;
+ if (!strcmp(var->name, darg->var->name)) {
+ return var->arg = darg;
+ }
}
}
if (strcmp(set_var->name, ref->var->name)) {
return 0;
}
+ ZEND_ASSERT(!set_var->arg || set_var->arg == ref);
+ set_var->arg = ref;
- if (set->count && (set->func->type != PSI_T_TO_ARRAY || ref_type->type != PSI_T_STRUCT)) {
- data->error(E_WARNING, "Inner `set` statement casts only work with to_array() casts on structs");
+ if (set->count && (set->func->type != PSI_T_TO_ARRAY || (ref_type->type != PSI_T_STRUCT && !ref->var->arg->var->pointer_level))) {
+ data->error(E_WARNING, "Inner `set` statement casts only work with to_array() casts on structs or pointers");
return 0;
}
- for (i = 0; i < set->count; ++i) {
- decl_var *sub_var = set->inner[i]->vars->vars[0];
- decl_arg *sub_ref = locate_struct_member(ref_type->strct, sub_var);
+
+ if (ref_type->type == PSI_T_STRUCT) {
+ for (i = 0; i < set->count; ++i) {
+ decl_var *sub_var = set->inner[i]->vars->vars[0];
+ decl_arg *sub_ref = locate_struct_member(ref_type->strct, sub_var);
+
+ if (sub_ref) {
+ if (!validate_set_value(data, set->inner[i], sub_ref)) {
+ return 0;
+ }
+ }
+ }
+ } else if (set->count == 1) {
+ decl_var *sub_var = set->inner[0]->vars->vars[0];
+ decl_arg *sub_ref = sub_var->arg;
if (sub_ref) {
- if (!validate_set_value(data, set->inner[i], sub_ref)) {
+ if (!validate_set_value(data, set->inner[0], sub_ref)) {
return 0;
}
}
+ } else if (set->count > 1) {
+ data->error(E_WARNING, "Inner `set` statement casts on pointers may only occur once");
+ return 0;
}
return 1;
}
static inline decl *locate_impl_decl(decls *decls, return_stmt *ret) {
- size_t i;
+ if (decls) {
+ size_t i;
- for (i = 0; i < decls->count; ++i) {
- if (!strcmp(decls->list[i]->func->var->name, ret->set->vars->vars[0]->name)) {
- ret->decl = decls->list[i]->func;
- return decls->list[i];
+ for (i = 0; i < decls->count; ++i) {
+ if (!strcmp(decls->list[i]->func->var->name, ret->set->vars->vars[0]->name)) {
+ ret->decl = decls->list[i]->func;
+ return decls->list[i];
+ }
}
}
+
return NULL;
}
static inline int validate_impl_ret_stmt(PSI_Data *data, impl *impl) {
return 1;
}
static inline decl *locate_free_decl(decls *decls, free_call *f) {
- size_t i;
+ if (decls) {
+ size_t i;
- for (i = 0; i < decls->count; ++i) {
- if (!strcmp(decls->list[i]->func->var->name, f->func)) {
- f->decl = decls->list[i];
- return decls->list[i];
+ for (i = 0; i < decls->count; ++i) {
+ if (!strcmp(decls->list[i]->func->var->name, f->func)) {
+ f->decl = decls->list[i];
+ return decls->list[i];
+ }
}
}
+
return NULL;
}
static inline int validate_impl_free_stmts(PSI_Data *data, impl *impl) {
void PSI_ContextBuild(PSI_Context *C, const char *paths)
{
- int i, n;
+ int i, n, flags = getenv("PSI_DEBUG") ? PSI_PARSER_DEBUG : 0;
char *sep = NULL, *cpy = strdup(paths), *ptr = cpy;
struct dirent **entries = NULL;
C->error(PSI_WARNING, "Path to PSI file too long: %s/%s",
ptr, entries[i]->d_name);
}
- if (!PSI_ParserInit(&P, psi, C->error, 0)) {
+ if (!PSI_ParserInit(&P, psi, C->error, flags)) {
C->error(PSI_WARNING, "Failed to init PSI parser (%s): %s",
psi, strerror(errno));
continue;
C->ops->call(C, ret_val, decl);
}
+static inline void dump_decl_type(int fd, decl_type *t) {
+ const char *pre;
+
+ switch (t->type) {
+ case PSI_T_STRUCT:
+ pre = "struct ";
+ break;
+ default:
+ pre = "";
+ }
+ dprintf(fd, "%s%s", pre, t->name);
+}
+static inline void dump_decl_var(int fd, decl_var *v) {
+ dprintf(fd, "%.*s%s", v->pointer_level-!!v->array_size, "**********", v->name);
+ if (v->array_size) {
+ dprintf(fd, "[%u]", v->array_size);
+ }
+}
+static inline void dump_decl_arg(int fd, decl_arg *a) {
+ dump_decl_type(fd, a->type);
+ dprintf(fd, " ");
+ dump_decl_var(fd, a->var);
+}
+void PSI_ContextDump(PSI_Context *C, int fd)
+{
+ size_t i, j;
+
+#ifdef HAVE_LIBJIT
+ if (C->ops == PSI_Libjit()) {
+ dprintf(fd, "#PSI(libjit)\n");
+ }
+#endif
+#ifdef HAVE_LIBFFI
+ if (C->ops == PSI_Libffi()) {
+ dprintf(fd, "#PSI(libffi)\n");
+ }
+#endif
+
+ if (C->defs) for (i = 0; i < C->defs->count; ++i) {
+ decl_typedef *tdef = C->defs->list[i];
+
+ dprintf(fd, "typedef ");
+ dump_decl_type(fd, tdef->type);
+ dprintf(fd, " %s;\n", tdef->alias);
+ }
+ if (C->structs) for (i = 0; i < C->structs->count; ++i) {
+ decl_struct *strct = C->structs->list[i];
+ decl_arg *sarg = NULL;
+
+ dprintf(fd, "struct %s::(%zu) {\n", strct->name, strct->size);
+ for (j = 0; j < strct->args->count; ++j) {
+ sarg = strct->args->args[j];
+ dprintf(fd, "\t");
+ dump_decl_arg(fd, sarg);
+ dprintf(fd, "::(%zu, %zu);\n", sarg->layout->pos, sarg->layout->len);
+ }
+ dprintf(fd, "}\n");
+ }
+
+ dprintf(fd, "\n");
+}
+
void PSI_ContextDtor(PSI_Context *C)
{
size_t i;
free_decl_libs(&C->psi.libs);
- for (i = 0; i < C->count; ++i) {
- PSI_DataDtor(&C->data[i]);
+ if (C->data) {
+ for (i = 0; i < C->count; ++i) {
+ PSI_DataDtor(&C->data[i]);
+ }
+ free(C->data);
}
- free(C->data);
- for (zfe = C->closures; zfe->fname; ++zfe) {
- free((void *) zfe->arg_info);
+ if (C->closures) {
+ for (zfe = C->closures; zfe->fname; ++zfe) {
+ free((void *) zfe->arg_info);
+ }
+ free(C->closures);
}
- free(C->closures);
if (C->consts) {
if (C->consts->list) {
int PSI_ContextValidate(PSI_Context *C, PSI_Parser *P);
zend_function_entry *PSI_ContextCompile(PSI_Context *C);
void PSI_ContextCall(PSI_Context *C, impl_val *ret_val, decl *decl);
+void PSI_ContextDump(PSI_Context *C, int fd);
void PSI_ContextDtor(PSI_Context *C);
void PSI_ContextFree(PSI_Context **C);
C->context = PSI_LibffiContextInit(NULL);
}
-static void psi_ffi_dtor(PSI_Context *C) {
- size_t i;
+static void psi_ffi_dtor(PSI_Context *C)
+{
+ if (C->decls) {
+ size_t i;
- for (i = 0; i < C->decls->count; ++i) {
- decl *decl = C->decls->list[i];
+ for (i = 0; i < C->decls->count; ++i) {
+ decl *decl = C->decls->list[i];
- if (decl->call.info) {
- PSI_LibffiCallFree(decl->call.info);
+ if (decl->call.info) {
+ PSI_LibffiCallFree(decl->call.info);
+ }
}
}
free(C->context);
static void psi_jit_dtor(PSI_Context *C)
{
- size_t i;
+ if (C->decls) {
+ size_t i;
- for (i = 0; i < C->decls->count; ++i) {
- decl *decl = C->decls->list[i];
+ for (i = 0; i < C->decls->count; ++i) {
+ decl *decl = C->decls->list[i];
- PSI_LibjitCallFree(decl->call.info);
+ PSI_LibjitCallFree(decl->call.info);
+ }
}
PSI_LibjitContextFree((void *) &C->context);
}
return n;
}
-void psi_to_bool(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var)
+void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val)
{
+ decl_var *var = set->vars->vars[0];
+ token_t t = real_decl_type(var->arg->type)->type;
impl_val *v = deref_impl_val(ret_val, var);
switch (t) {
convert_to_boolean(return_value);
}
-void psi_to_int(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var)
+void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val)
{
+ decl_var *var = set->vars->vars[0];
+ token_t t = real_decl_type(var->arg->type)->type;
impl_val *v = deref_impl_val(ret_val, var);
switch (t) {
convert_to_long(return_value);
}
-void psi_to_double(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var)
+void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val)
{
+ decl_var *var = set->vars->vars[0];
+ token_t t = real_decl_type(var->arg->type)->type;
impl_val *v = deref_impl_val(ret_val, var);
switch (t) {
}
}
-void psi_to_string(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var)
+void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val)
{
+ decl_var *var = set->vars->vars[0];
+ token_t t = real_decl_type(var->arg->type)->type;
+
switch (t) {
case PSI_T_INT8:
case PSI_T_UINT8:
return mem;
}
-void psi_to_array(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var)
+void psi_to_array(zval *return_value, set_value *set, impl_val *r_val)
{
zval ele;
unsigned i;
- impl_val tmp;
+ decl_var *var = set->vars->vars[0];
+ token_t t = real_decl_type(var->arg->type)->type;
+ impl_val tmp, *ret_val = deref_impl_val(r_val, var);
array_init(return_value);
if (t == PSI_T_STRUCT) {
decl_struct *s = real_decl_type(var->arg->type)->strct;
- ret_val = deref_impl_val(ret_val, var);
ZEND_ASSERT(s);
decl_arg *sub_arg = sub_var->arg;
if (sub_arg) {
- token_t t = real_decl_type(sub_arg->type)->type;
void *ptr = malloc(sub_arg->layout->len);
memcpy(ptr, (char *) ret_val->ptr + sub_arg->layout->pos,
sub_arg->layout->len);
tmp_ptr = enref_impl_val(ptr, sub_arg->var);
- sub_set->func->handler(&ztmp, t, tmp_ptr, sub_set, sub_var);
+ sub_set->func->handler(&ztmp, sub_set, tmp_ptr);
add_assoc_zval(return_value, sub_var->name, &ztmp);
free(tmp_ptr);
if (tmp_ptr != ptr) {
}
}
return;
-
// for (i = 0; i < s->args->count; ++i) {
// decl_arg *darg = s->args->args[i];
// impl_val tmp, tmp_ptr;
// }
// add_assoc_zval(return_value, darg->var->name, &ztmp);
// }
- return;
}
- ret_val = deref_impl_val(ret_val, var);
- for (i = 0; i < var->arg->var->array_size; ++i) {
- impl_val *ptr = iterate(ret_val, t, i, &tmp);
+ if (var->arg->var->array_size) {
+ /* to_array(foo[NUMBER]) */
+ for (i = 0; i < var->arg->var->array_size; ++i) {
+ impl_val *ptr = iterate(ret_val, t, i, &tmp);
+
+ switch (t) {
+ case PSI_T_FLOAT:
+ ZVAL_DOUBLE(&ele, (double) ptr->fval);
+ break;
+ case PSI_T_DOUBLE:
+ ZVAL_DOUBLE(&ele, ptr->dval);
+ break;
+ default:
+ ZVAL_LONG(&ele, ptr->lval);
+ break;
+ }
- switch (t) {
- case PSI_T_FLOAT:
- ZVAL_DOUBLE(&ele, (double) ptr->fval);
- break;
- case PSI_T_DOUBLE:
- ZVAL_DOUBLE(&ele, ptr->dval);
- break;
- default:
- ZVAL_LONG(&ele, ptr->lval);
- break;
+ add_next_index_zval(return_value, &ele);
}
+ return;
+ } else {
+ /* pointer to something */
+ impl_val *ptr;
- add_next_index_zval(return_value, &ele);
+ for (i = 0; (ptr = iterate(ret_val, t, i, &tmp)); ++i) {
+ if (!ptr->ptr) {
+ break;
+ }
+ }
}
}
static inline void psi_do_set(zval *return_value, set_value *set)
{
- impl_val *val = (impl_val *) &set->vars->vars[0]->arg->let->ptr;
- token_t t = real_decl_type(set->vars->vars[0]->arg->type)->type;
-
ZVAL_DEREF(return_value);
zval_dtor(return_value);
- set->func->handler(return_value, t, val, set, set->vars->vars[0]);
+ set->func->handler(return_value, set, set->vars->vars[0]->arg->let->ptr);
}
static inline void psi_do_return(zval *return_value, return_stmt *ret, impl_val *ret_val)
{
- token_t t = real_decl_type(ret->decl->type)->type;
-
- ret->set->func->handler(return_value, t, ret_val, ret->set, ret->decl->var);
+ ret->set->func->handler(return_value, ret->set, ret_val);
}
static inline void psi_do_free(free_stmt *fre)
PSI_ContextInit(&PSI_G(context), ops, psi_error);
PSI_ContextBuild(&PSI_G(context), PSI_G(directory));
+ if (getenv("PSI_DUMP")) {
+ PSI_ContextDump(&PSI_G(context), STDOUT_FILENO);
+ }
+
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(psi)
static inline impl_val *deref_impl_val(impl_val *ret_val, decl_var *var) {
unsigned i;
- if (var->arg->var != var) for (i = 0; i < var->pointer_level; ++i) {
+ if (var->arg->var != var) for (i = 1; i < var->pointer_level; ++i) {
ret_val = *(void **) ret_val;
}
return ret_val;
typedef struct set_func {
token_t type;
char *name;
- void (*handler)(zval *, token_t, impl_val *, struct set_value *set, decl_var *);
+ void (*handler)(zval *, struct set_value *set, impl_val *ret_val);
} set_func;
static inline set_func *init_set_func(token_t type, const char *name) {
return t; \
} while(1)
-/* DIGIT = [0-9]
- DIGITS = DIGIT+
- DECIMALS = (+|-)? DIGIT* "."
- digits ::= digits DIGIT.
- decimals ::= digits DOT digits.
- decimals ::= DOT digits.
- decimals ::= digits DOT.
- number ::= digits.
- number ::= PLUS digits.
- number ::= MINUS digits.
- number ::= decimals.
- number ::= MINUS decimals.
- number ::= PLUS decimals.
-
-*/
token_t PSI_ParserScan(PSI_Parser *P)
{
for (;;) {
QUOTED_STRING = "\"" ([^\"])+ "\"";
NUMBER = [+-]? [0-9]* "."? [0-9]+ ([eE] [+-]? [0-9]+)?;
- "#" .* "\n" { ++P->line; RETURN(PSI_T_COMMENT);}
+ ("#"|"//") .* "\n" { ++P->line; continue;}
"(" {RETURN(PSI_T_LPAREN);}
")" {RETURN(PSI_T_RPAREN);}
";" {RETURN(PSI_T_EOS);}
#define PSI_T_LET 4
#define PSI_T_RETURN 5
#define PSI_T_LIB 6
-#define PSI_T_COMMENT 7
+#define PSI_T_INT 7
#define PSI_T_QUOTED_STRING 8
#define PSI_T_EOS 9
#define PSI_T_STRUCT 10
#define PSI_T_LBRACE 11
#define PSI_T_RBRACE 12
-#define PSI_T_BOOL 13
-#define PSI_T_INT 14
-#define PSI_T_FLOAT 15
-#define PSI_T_STRING 16
-#define PSI_T_CONST 17
-#define PSI_T_NSNAME 18
-#define PSI_T_EQUALS 19
-#define PSI_T_TYPEDEF 20
-#define PSI_T_LPAREN 21
-#define PSI_T_RPAREN 22
-#define PSI_T_VOID 23
-#define PSI_T_LBRACKET 24
-#define PSI_T_NUMBER 25
+#define PSI_T_COLON 13
+#define PSI_T_LPAREN 14
+#define PSI_T_NUMBER 15
+#define PSI_T_RPAREN 16
+#define PSI_T_BOOL 17
+#define PSI_T_FLOAT 18
+#define PSI_T_STRING 19
+#define PSI_T_CONST 20
+#define PSI_T_NSNAME 21
+#define PSI_T_EQUALS 22
+#define PSI_T_TYPEDEF 23
+#define PSI_T_VOID 24
+#define PSI_T_LBRACKET 25
#define PSI_T_RBRACKET 26
#define PSI_T_COMMA 27
#define PSI_T_DOUBLE 28
#define PSI_T_INT64 35
#define PSI_T_UINT64 36
#define PSI_T_FUNCTION 37
-#define PSI_T_COLON 38
-#define PSI_T_REFERENCE 39
-#define PSI_T_NULL 40
-#define PSI_T_TRUE 41
-#define PSI_T_FALSE 42
-#define PSI_T_DOLLAR 43
-#define PSI_T_CALLOC 44
-#define PSI_T_ARRVAL 45
-#define PSI_T_STRLEN 46
-#define PSI_T_STRVAL 47
-#define PSI_T_FLOATVAL 48
-#define PSI_T_INTVAL 49
-#define PSI_T_BOOLVAL 50
-#define PSI_T_TO_ARRAY 51
-#define PSI_T_TO_STRING 52
-#define PSI_T_TO_INT 53
-#define PSI_T_TO_FLOAT 54
-#define PSI_T_TO_BOOL 55
-#define PSI_T_MIXED 56
-#define PSI_T_ARRAY 57
-#define PSI_T_POINTER 58
+#define PSI_T_REFERENCE 38
+#define PSI_T_NULL 39
+#define PSI_T_TRUE 40
+#define PSI_T_FALSE 41
+#define PSI_T_DOLLAR 42
+#define PSI_T_CALLOC 43
+#define PSI_T_ARRVAL 44
+#define PSI_T_STRLEN 45
+#define PSI_T_STRVAL 46
+#define PSI_T_FLOATVAL 47
+#define PSI_T_INTVAL 48
+#define PSI_T_BOOLVAL 49
+#define PSI_T_TO_ARRAY 50
+#define PSI_T_TO_STRING 51
+#define PSI_T_TO_INT 52
+#define PSI_T_TO_FLOAT 53
+#define PSI_T_TO_BOOL 54
+#define PSI_T_MIXED 55
+#define PSI_T_ARRAY 56
+#define PSI_T_POINTER 57
}
%nonassoc NAME.
-%fallback NAME FREE SET LET RETURN LIB.
+%fallback NAME FREE SET LET RETURN LIB INT.
file ::= blocks.
blocks ::= block.
blocks ::= blocks block.
-block ::= COMMENT.
-
block ::= LIB(T) QUOTED_STRING(libname) EOS. {
if (P->psi.file.ln) {
PSI_ParserSyntaxError(P, P->psi.file.ln, T->line, "Extra 'lib %s' statement has no effect", libname->text);
%type decl_struct {decl_struct*}
%destructor decl_struct {free_decl_struct($$);}
-decl_struct(strct) ::= STRUCT NAME(N) LBRACE struct_args(args) RBRACE. {
+decl_struct(strct) ::= STRUCT NAME(N) struct_size(size_) LBRACE struct_args(args) RBRACE. {
strct = init_decl_struct(N->text, args);
+ strct->size = size_;
free(N);
}
+%type struct_size {size_t}
+struct_size(size) ::= . {
+ size = 0;
+}
+struct_size(size) ::= COLON COLON LPAREN NUMBER(SIZ) RPAREN. {
+ size = atol(SIZ->text);
+ free(SIZ);
+}
+
%token_class const_type_token BOOL INT FLOAT STRING.
%type const_type {const_type*}
%destructor const_type {free_const_type($$);}
}
%type struct_args {decl_args*}
%destructor struct_args {free_decl_args($$);}
-struct_args(args) ::= decl_arg(arg) EOS. {
+struct_args(args) ::= struct_arg(arg). {
args = init_decl_args(arg);
}
-struct_args(args) ::= struct_args(args_) decl_arg(arg) EOS. {
+struct_args(args) ::= struct_args(args_) struct_arg(arg). {
args = add_decl_arg(args_, arg);
}
+%type struct_arg {decl_arg*}
+%destructor struct_arg {free_decl_arg($$);}
+struct_arg(arg) ::= decl_arg(arg_) struct_layout(layout_) EOS. {
+ arg_->layout = layout_;
+ arg = arg_;
+}
+
+%type struct_layout {decl_struct_layout*}
+%destructor struct_layout {free_decl_struct_layout($$);}
+struct_layout(layout) ::= . {
+ layout = NULL;
+}
+struct_layout(layout) ::= COLON COLON LPAREN NUMBER(POS) COMMA NUMBER(SIZ) RPAREN. {
+ layout = init_decl_struct_layout(atol(POS->text), atol(SIZ->text));
+ free(POS);
+ free(SIZ);
+}
%token_class decl_type_token FLOAT DOUBLE INT8 UINT8 INT16 UINT16 INT32 UINT32 INT64 UINT64 NAME.
%type decl_type {decl_type*}
--- /dev/null
+--TEST--
+asctime/gmtime
+--SKIPIF--
+<?php
+extension_loaded("psi") or die("skip - need ext/psi");
+?>
+--ENV--
+TZ=UTC
+--INI--
+psi.directory = {PWD}/../../psi.d:{PWD}
+--FILE--
+===TEST===
+<?php
+var_dump(psi\asctime(NULL));
+var_dump(psi\asctime_r(NULL));
+var_dump(psi\asctime(psi\gmtime(1234567890)));
+var_dump(psi\asctime_r(psi\gmtime_r(1234567890)));
+?>
+===DONE===
+--EXPECT--
+===TEST===
+string(25) "Sun Jan 0 00:00:00 1900
+"
+string(25) "Sun Jan 0 00:00:00 1900
+"
+string(25) "Fri Feb 13 23:31:30 2009
+"
+string(25) "Fri Feb 13 23:31:30 2009
+"
+===DONE===
--- /dev/null
+--TEST--
+gettimeofday
+--INI--
+psi.directory = {PWD}/../../psi.d:{PWD}
+--SKIPIF--
+<?php
+extension_loaded("psi") or die("skip - need ext/psi");
+?>
+--FILE--
+===TEST===
+<?php
+
+var_dump($ar = gettimeofday());
+
+var_dump(psi\gettimeofday());
+var_dump(psi\gettimeofday($tv), $tv);
+var_dump(psi\gettimeofday($tv, $tz), $tv, $tz);
+
+var_dump(abs($ar["sec"] - $tv["tv_sec"]) <= 1);
+
+?>
+===DONE===
+--EXPECTF--
+===TEST===
+array(4) {
+ ["sec"]=>
+ int(1%d)
+ ["usec"]=>
+ int(%d)
+ ["minuteswest"]=>
+ int(%d)
+ ["dsttime"]=>
+ int(%d)
+}
+int(0)
+int(0)
+array(2) {
+ ["tv_sec"]=>
+ int(1%d)
+ ["tv_usec"]=>
+ int(%d)
+}
+int(0)
+array(2) {
+ ["tv_sec"]=>
+ int(1%d)
+ ["tv_usec"]=>
+ int(%d)
+}
+array(2) {
+ ["tz_minuteswest"]=>
+ int(%d)
+ ["tz_dsttime"]=>
+ int(%d)
+}
+bool(true)
+===DONE===
+
\ No newline at end of file
--- /dev/null
+--TEST--
+nanosleep
+--SKIPIF--
+<?php
+extension_loaded("psi") or die("skip - need ext/psi");
+?>
+--ENV--
+TZ=UTC
+--INI--
+psi.directory = {PWD}/../../psi.d:{PWD}
+--FILE--
+===TEST===
+<?php
+var_dump(psi\gettimeofday($tv1), $tv1);
+var_dump(psi\nanosleep(["tv_nsec" => 10000000], $rm), $rm);
+var_dump(psi\gettimeofday($tv2), $tv2);
+var_dump($tv2["tv_usec"]-$tv1["tv_usec"]);
+?>
+===DONE===
+--EXPECTF--
+===TEST===
+int(0)
+array(2) {
+ ["tv_sec"]=>
+ int(1%d)
+ ["tv_usec"]=>
+ int(%d)
+}
+int(0)
+array(2) {
+ ["tv_sec"]=>
+ int(0)
+ ["tv_nsec"]=>
+ int(0)
+}
+int(0)
+array(2) {
+ ["tv_sec"]=>
+ int(%d)
+ ["tv_usec"]=>
+ int(%d)
+}
+int(%r\d\d\d\d\d%r)
+===DONE===
+++ /dev/null
---TEST--
-gettimeofday
---INI--
-psi.directory = {PWD}/../../psi.d:{PWD}
---SKIPIF--
-<?php
-extension_loaded("psi") or die("skip - need ext/psi");
-?>
---FILE--
-===TEST===
-<?php
-
-var_dump($ar = gettimeofday());
-
-var_dump(psi\gettimeofday());
-var_dump(psi\gettimeofday($tv), $tv);
-var_dump(psi\gettimeofday($tv, $tz), $tv, $tz);
-
-var_dump(abs($ar["sec"] - $tv["tv_sec"]) <= 1);
-
-?>
-===DONE===
---EXPECTF--
-===TEST===
-array(4) {
- ["sec"]=>
- int(1%d)
- ["usec"]=>
- int(%d)
- ["minuteswest"]=>
- int(%d)
- ["dsttime"]=>
- int(%d)
-}
-int(0)
-int(0)
-array(2) {
- ["tv_sec"]=>
- int(1%d)
- ["tv_usec"]=>
- int(%d)
-}
-int(0)
-array(2) {
- ["tv_sec"]=>
- int(1%d)
- ["tv_usec"]=>
- int(%d)
-}
-array(2) {
- ["tz_minuteswest"]=>
- int(%d)
- ["tz_dsttime"]=>
- int(%d)
-}
-bool(true)
-===DONE===
-
\ No newline at end of file
+++ /dev/null
---TEST--
-asctime/gmtime
---SKIPIF--
-<?php
-extension_loaded("psi") or die("skip - need ext/psi");
-?>
---ENV--
-TZ=UTC
---INI--
-psi.directory = {PWD}/../../psi.d:{PWD}
---FILE--
-===TEST===
-<?php
-var_dump(psi\asctime(NULL));
-var_dump(psi\asctime_r(NULL));
-var_dump(psi\asctime(psi\gmtime(1234567890)));
-var_dump(psi\asctime_r(psi\gmtime_r(1234567890)));
-?>
-===DONE===
---EXPECT--
-===TEST===
-string(25) "Sun Jan 0 00:00:00 1900
-"
-string(25) "Sun Jan 0 00:00:00 1900
-"
-string(25) "Fri Feb 13 23:31:30 2009
-"
-string(25) "Fri Feb 13 23:31:30 2009
-"
-===DONE===
+++ /dev/null
---TEST--
-nanosleep
---SKIPIF--
-<?php
-extension_loaded("psi") or die("skip - need ext/psi");
-?>
---ENV--
-TZ=UTC
---INI--
-psi.directory = {PWD}/../../psi.d:{PWD}
---FILE--
-===TEST===
-<?php
-var_dump(psi\gettimeofday($tv1), $tv1);
-var_dump(psi\nanosleep(["tv_nsec" => 10000000], $rm), $rm);
-var_dump(psi\gettimeofday($tv2), $tv2);
-var_dump($tv2["tv_usec"]-$tv1["tv_usec"]);
-?>
-===DONE===
---EXPECTF--
-===TEST===
-int(0)
-array(2) {
- ["tv_sec"]=>
- int(1%d)
- ["tv_usec"]=>
- int(%d)
-}
-int(0)
-array(2) {
- ["tv_sec"]=>
- int(0)
- ["tv_nsec"]=>
- int(0)
-}
-int(0)
-array(2) {
- ["tv_sec"]=>
- int(%d)
- ["tv_usec"]=>
- int(%d)
-}
-int(%r\d\d\d\d\d%r)
-===DONE===
+++ /dev/null
---TEST--
-times
---INI--
-psi.directory={PWD}/../../psi.d:{PWD}
---SKIPIF--
-<?php
-extension_loaded("psi") or die("skip - need ext/psi");
-?>
---FILE--
-===TEST===
-<?php
-var_dump(psi\times($times), $times);
-?>
-===DONE===
---EXPECTF--
-===TEST===
-int(%d)
-array(4) {
- ["tms_utime"]=>
- int(%d)
- ["tms_stime"]=>
- int(%d)
- ["tms_cutime"]=>
- int(%d)
- ["tms_cstime"]=>
- int(%d)
-}
-===DONE===
--- /dev/null
+--TEST--
+times
+--INI--
+psi.directory={PWD}/../../psi.d:{PWD}
+--SKIPIF--
+<?php
+extension_loaded("psi") or die("skip - need ext/psi");
+?>
+--FILE--
+===TEST===
+<?php
+var_dump(psi\times($times), $times);
+?>
+===DONE===
+--EXPECTF--
+===TEST===
+int(%d)
+array(4) {
+ ["tms_utime"]=>
+ int(%d)
+ ["tms_stime"]=>
+ int(%d)
+ ["tms_cutime"]=>
+ int(%d)
+ ["tms_cstime"]=>
+ int(%d)
+}
+===DONE===