From 22ca720deabdb92ebedf4c9c82d758671c9d5f3d Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Thu, 19 Nov 2015 18:03:58 +0100 Subject: [PATCH] glob --- config.m4 | 6 ++ psi.d/glob.psi | 18 ++++++ src/context.c | 49 ++++++++++------ src/module.c | 125 +++++++++++++++++++--------------------- src/parser.h | 4 ++ tests/glob/glob001.phpt | 22 +++++++ tests/glob/glob002.phpt | 21 +++++++ 7 files changed, 161 insertions(+), 84 deletions(-) create mode 100644 psi.d/glob.psi create mode 100644 tests/glob/glob001.phpt create mode 100644 tests/glob/glob002.phpt diff --git a/config.m4 b/config.m4 index 0b11787..731c46b 100644 --- a/config.m4 +++ b/config.m4 @@ -402,12 +402,18 @@ if test "$PHP_PSI" != "no"; then gl_pathv) psi_member_type="char**" ;; ], glob.h) PSI_CONST(GLOB_APPEND, int, glob.h) + PSI_CONST(GLOB_BRACE, int, glob.h) PSI_CONST(GLOB_DOOFFS, int, glob.h) PSI_CONST(GLOB_ERR, int, glob.h) PSI_CONST(GLOB_MARK, int, glob.h) PSI_CONST(GLOB_NOCHECK, int, glob.h) PSI_CONST(GLOB_NOESCAPE, int, glob.h) + PSI_CONST(GLOB_NOMAGIC, int, glob.h) PSI_CONST(GLOB_NOSORT, int, glob.h) + PSI_CONST(GLOB_ONLYDIR, int, glob.h) + PSI_CONST(GLOB_PERIOD, int, glob.h) + PSI_CONST(GLOB_TILDE, int, glob.h) + PSI_CONST(GLOB_TILDE_CHECK, int, glob.h) PSI_CONST(GLOB_ABORTED, int, glob.h) PSI_CONST(GLOB_NOMATCH, int, glob.h) PSI_CONST(GLOB_NOSPACE, int, glob.h) diff --git a/psi.d/glob.psi b/psi.d/glob.psi new file mode 100644 index 0000000..3f8ee1e --- /dev/null +++ b/psi.d/glob.psi @@ -0,0 +1,18 @@ +extern void globfree(glob_t *buf); + +extern int glob(char *pat, int flags, void *err, glob_t *buf); +function psi\glob(string $pattern, int $flags, array &$glob = NULL) : int { + let pat = strval($pattern); + let flags = intval($flags); + let err = NULL; + let buf = arrval($glob); + return to_int(glob); + set $glob = to_array(*buf, + to_int(gl_matchc), + to_int(gl_pathc), + to_int(gl_offs), + to_int(gl_flags), + to_array(**gl_pathv, gl_pathc, gl_offs, to_string(*gl_pathv)) + ); + //free globfree(buf); +} diff --git a/src/context.c b/src/context.c index d7eabb5..2df3dd8 100644 --- a/src/context.c +++ b/src/context.c @@ -276,23 +276,27 @@ static inline int validate_decl(PSI_Data *data, void *dl, decl *decl) { } return 1; } +static inline decl_arg *locate_decl_var_arg(decl_var *var, decl_args *args) { + size_t i; -static inline decl_arg *locate_struct_member(decl_struct *s, decl_var *var) { - if (s->args) { - size_t i; - - for (i = 0; i < s->args->count; ++i) { - decl_arg *darg = s->args->args[i]; + for (i = 0; i < args->count; ++i) { + decl_arg *arg = args->args[i]; - if (!strcmp(var->name, darg->var->name)) { - return var->arg = darg; - } + if (!strcmp(var->name, arg->var->name)) { + return var->arg = arg; } } return NULL; } -static inline int validate_set_value(PSI_Data *data, set_value *set, decl_arg *ref) { +static inline decl_arg *locate_struct_member(decl_struct *s, decl_var *var) { + if (s->args) { + return locate_decl_var_arg(var, s->args); + } + + return NULL; +} +static inline int validate_set_value(PSI_Data *data, set_value *set, decl_arg *ref, decl_args *ref_list) { size_t i; decl_type *ref_type = real_decl_type(ref->type); decl_var *set_var = set->vars->vars[0]; @@ -316,10 +320,11 @@ static inline int validate_set_value(PSI_Data *data, set_value *set, decl_arg *r EMPTY_SWITCH_DEFAULT_CASE(); } - if (strcmp(set_var->name, ref->var->name)) { - return 0; + for (i = 1; i < set->vars->count; ++i) { + if (!locate_decl_var_arg(set->vars->vars[i], ref_list)) { + 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 && !ref->var->arg->var->pointer_level))) { @@ -328,24 +333,32 @@ static inline int validate_set_value(PSI_Data *data, set_value *set, decl_arg *r } if (ref_type->type == PSI_T_STRUCT) { + /* to_array(struct, to_...) */ 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)) { + if (!validate_set_value(data, set->inner[i], sub_ref, ref_type->strct->args)) { return 0; } + set->inner[i]->outer.set = set; } } } else if (set->count == 1) { + /* to_array(ptr, to_string(*ptr)) */ decl_var *sub_var = set->inner[0]->vars->vars[0]; - decl_arg *sub_ref = sub_var->arg; + decl_arg *sub_ref = locate_decl_var_arg(sub_var, ref_list); if (sub_ref) { - if (!validate_set_value(data, set->inner[0], sub_ref)) { + if (strcmp(sub_var->name, set_var->name)) { + data->error(E_WARNING, "Inner `set` statement casts on pointers must reference the same variable"); + return 0; + } + if (!validate_set_value(data, set->inner[0], sub_ref, ref_list)) { return 0; } + set->inner[0]->outer.set = set; } } else if (set->count > 1) { data->error(E_WARNING, "Inner `set` statement casts on pointers may only occur once"); @@ -393,7 +406,7 @@ static inline int validate_impl_ret_stmt(PSI_Data *data, impl *impl) { return 0; } - if (!validate_set_value(data, ret->set, ret->decl)) { + if (!validate_set_value(data, ret->set, ret->decl, impl->decl->args)) { return 0; } @@ -491,7 +504,7 @@ static inline int validate_impl_set_stmts(PSI_Data *data, impl *impl) { if (!strcmp(set_var->name, set_arg->var->name)) { check = 1; - if (!validate_set_value(data, set->val, set_arg)) { + if (!validate_set_value(data, set->val, set_arg, impl->decl->args)) { return 0; } set_var->arg = set_arg; diff --git a/src/module.c b/src/module.c index 8637bab..fcf23bd 100644 --- a/src/module.c +++ b/src/module.c @@ -296,12 +296,10 @@ void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val) } -static impl_val *iterate(impl_val *val, token_t t, unsigned i, impl_val *tmp) +static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp) { - size_t size = psi_t_size(t); - memset(tmp, 0, sizeof(*tmp)); - memcpy(tmp, val->ptr + size * i, size); + memcpy(tmp, ((void*) val->ptr) + size * i, size); return tmp; } @@ -355,10 +353,19 @@ void *psi_array_to_struct(decl_struct *s, HashTable *arr) return mem; } +static inline impl_val *struct_member_ref(decl_arg *set_arg, impl_val *struct_ptr, impl_val **to_free) { + void *ptr = (char *) struct_ptr->ptr + set_arg->layout->pos; + impl_val *val = enref_impl_val(ptr, set_arg->var); + + if (val != ptr) { + *to_free = val; + } + + return val; +} void psi_to_array(zval *return_value, set_value *set, impl_val *r_val) { - zval ele; - unsigned i; + size_t i; 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); @@ -366,78 +373,39 @@ void psi_to_array(zval *return_value, set_value *set, impl_val *r_val) array_init(return_value); if (t == PSI_T_STRUCT) { - decl_struct *s = real_decl_type(var->arg->type)->strct; - - ZEND_ASSERT(s); + // decl_struct *s = real_decl_type(var->arg->type)->strct; if (set->count) { /* explicit member casts */ for (i = 0; i < set->count; ++i) { - zval ztmp; - impl_val *tmp_ptr; set_value *sub_set = set->inner[i]; decl_var *sub_var = sub_set->vars->vars[0]; - decl_arg *sub_arg = sub_var->arg; - if (sub_arg) { - void *ptr = malloc(sub_arg->layout->len); + sub_set->outer.val = r_val; + + if (sub_var->arg) { + impl_val *tmp = NULL, *val; + zval ztmp; - 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, sub_set, tmp_ptr); + val = deref_impl_val(struct_member_ref(sub_var->arg, ret_val, &tmp), sub_var); + sub_set->func->handler(&ztmp, sub_set, val); add_assoc_zval(return_value, sub_var->name, &ztmp); - free(tmp_ptr); - if (tmp_ptr != ptr) { - free(ptr); + + if (tmp) { + free(tmp); } } } } return; -// for (i = 0; i < s->args->count; ++i) { -// decl_arg *darg = s->args->args[i]; -// impl_val tmp, tmp_ptr; -// zval ztmp; -// char *ptr = (char *) ret_val->ptr + darg->layout->pos; -// -// tmp_ptr.ptr = &tmp; -// memset(&tmp, 0, sizeof(tmp)); -// memcpy(&tmp, ptr, darg->layout->len); -// switch (real_decl_type(darg->type)->type) { -// case PSI_T_FLOAT: -// case PSI_T_DOUBLE: -// psi_to_double(&ztmp, real_decl_type(darg->type)->type, &tmp, darg->var); -// break; -// case PSI_T_INT8: -// case PSI_T_UINT8: -// if (darg->var->pointer_level) { -// psi_to_string(&ztmp, real_decl_type(darg->type)->type, &tmp_ptr, darg->var); -// break; -// } -// /* no break */ -// case PSI_T_INT16: -// case PSI_T_UINT16: -// case PSI_T_INT32: -// case PSI_T_UINT32: -// case PSI_T_INT64: -// case PSI_T_UINT64: -// psi_to_int(&ztmp, real_decl_type(darg->type)->type, &tmp, darg->var); -// break; -// case PSI_T_STRUCT: -// psi_to_array(&ztmp, real_decl_type(darg->type)->type, &tmp_ptr, darg->var); -// break; -// default: -// printf("t=%d\n", real_decl_type(darg->type)->type); -// abort(); -// } -// add_assoc_zval(return_value, darg->var->name, &ztmp); -// } } + 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); + size_t size = psi_t_size(var->arg->var->pointer_level > 1 ? PSI_T_POINTER : t); + impl_val *ptr = iterate(ret_val, size, i, &tmp); + zval ele; switch (t) { case PSI_T_FLOAT: @@ -454,16 +422,41 @@ void psi_to_array(zval *return_value, set_value *set, impl_val *r_val) add_next_index_zval(return_value, &ele); } return; - } else { - /* pointer to something */ - impl_val *ptr; + } else if (set->vars->count > 1) { + /* to_array(arr_var, cnt_var[, cnt_var...], to_int(*arr_var)) + * check for length in second var + */ + size_t count = 0; + zval ele; - for (i = 0; (ptr = iterate(ret_val, t, i, &tmp)); ++i) { - if (!ptr->ptr) { - break; + if (set->outer.set) { + /* struct */ + for (i = 1; i < set->vars->count; ++i) { + impl_val *tmp = NULL, *cnt_val; + decl_var *cnt_var = set->vars->vars[i]; + + cnt_val = struct_member_ref(cnt_var->arg, set->outer.val, &tmp); + count += deref_impl_val(cnt_val, cnt_var)->lval; + + if (tmp) { + free(tmp); + } } + } else { + ZEND_ASSERT(0); } + + for (i = 0; i < count; ++i) { + size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t); + impl_val *ptr = iterate(ret_val, size, i, &tmp); + + set->inner[0]->func->handler(&ele, set->inner[0], ptr); + add_next_index_zval(return_value, &ele); + } + } else { + ZEND_ASSERT(0); } + } static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl) diff --git a/src/parser.h b/src/parser.h index 683192b..9309ab1 100644 --- a/src/parser.h +++ b/src/parser.h @@ -613,6 +613,10 @@ static inline void free_set_func(set_func *func) { typedef struct set_value { set_func *func; decl_vars *vars; + struct { + struct set_value *set; + impl_val *val; + } outer; struct set_value **inner; size_t count; } set_value; diff --git a/tests/glob/glob001.phpt b/tests/glob/glob001.phpt new file mode 100644 index 0000000..d85d8d5 --- /dev/null +++ b/tests/glob/glob001.phpt @@ -0,0 +1,22 @@ +--TEST-- +glob +--INI-- +psi.directory={PWD}/../../psi.d:{PWD} +--SKIPIF-- + +--FILE-- +===TEST=== + +===DONE=== +--EXPECTF-- +===TEST=== +int(0) +bool(true) +===DONE=== \ No newline at end of file diff --git a/tests/glob/glob002.phpt b/tests/glob/glob002.phpt new file mode 100644 index 0000000..530165a --- /dev/null +++ b/tests/glob/glob002.phpt @@ -0,0 +1,21 @@ +--TEST-- +glob +--INI-- +psi.directory={PWD}/../../psi.d:{PWD} +--SKIPIF-- + +--FILE-- +===TEST=== + 3]; +var_dump(psi\glob("*.php{,t}", psi\GLOB_BRACE|psi\GLOB_DOOFFS, $glob)); +var_dump($glob); +?> +===DONE=== +--EXPECTF-- +===TEST=== +int(0) +===DONE=== \ No newline at end of file -- 2.30.2