diff --git a/include/common.h b/include/common.h index c29a035..fbdec73 100644 --- a/include/common.h +++ b/include/common.h @@ -16,6 +16,8 @@ #pragma once +#include "php/main/php.h" + #define BEGIN_EXTERN_C() extern "C" { #define END_EXTERN_C() } @@ -26,6 +28,47 @@ else {k = ZSTR_VAL(_foreach_key), klen=ZSTR_LEN(_foreach_key); ktype = 1;} { #define YASD_HASHTABLE_FOREACH_END() } ZEND_HASH_FOREACH_END(); +#ifndef ZEND_THIS +#define ZEND_THIS (&EX(This)) +#endif + +/* PHP 8 compatibility macro {{{*/ +#if PHP_VERSION_ID < 80000 +#define yasd_zend7_object zval +#define YASD_Z7_OBJ_P(object) Z_OBJ_P(object) +#define YASD_Z8_OBJ_P(zobj) zobj +#else +#define yasd_zend7_object zend_object +#define YASD_Z7_OBJ_P(object) object +#define YASD_Z8_OBJ_P(zobj) Z_OBJ_P(zobj) +#endif +/*}}}*/ + +static void yasd_zend_update_property_null_ex(zend_class_entry *scope, zval *object, zend_string *s) { + zval tmp; + + ZVAL_NULL(&tmp); + zend_update_property_ex(scope, YASD_Z8_OBJ_P(object), s, &tmp); +} + +static zval* yasd_zend_read_property(zend_class_entry *ce, zval *obj, const char *s, int len, int silent) { + zval rv, *property = zend_read_property(ce, YASD_Z8_OBJ_P(obj), s, len, silent, &rv); + if (UNEXPECTED(property == &EG(uninitialized_zval))) { + zend_update_property_null(ce, YASD_Z8_OBJ_P(obj), s, len); + return zend_read_property(ce, YASD_Z8_OBJ_P(obj), s, len, silent, &rv); + } + return property; +} + +static zval* yasd_zend_read_property_ex(zend_class_entry *ce, zval *obj, zend_string *s, int silent) { + zval rv, *property = zend_read_property_ex(ce, YASD_Z8_OBJ_P(obj), s, silent, &rv); + if (UNEXPECTED(property == &EG(uninitialized_zval))) { + yasd_zend_update_property_null_ex(ce, obj, s); + return zend_read_property_ex(ce, YASD_Z8_OBJ_P(obj), s, silent, &rv); + } + return property; +} + namespace yasd { enum Color { YASD_ECHO_RED, diff --git a/include/util.h b/include/util.h index dbc54d0..1e4d75a 100644 --- a/include/util.h +++ b/include/util.h @@ -28,9 +28,9 @@ namespace yasd class Util { public: - static std::vector explode(std::string const & s, char delim); + static std::vector explode(const std::string &str, const std::string &delimiter); static HashTable *get_defined_vars(); - static void print_var(const char *var_name, size_t var_name_length); + static void print_var(std::string var_name); static void printf_info(int color, const char *format, ...); static void show_breakpoint_hit_info(); static const char *get_executed_filename(); diff --git a/src/cmder.cc b/src/cmder.cc index 0e6dd86..73bf32e 100644 --- a/src/cmder.cc +++ b/src/cmder.cc @@ -60,7 +60,7 @@ int Cmder::parse_breakpoint_cmd() { int lineno; std::string filename; - auto exploded_cmd = yasd::Util::explode(last_cmd, ' '); + auto exploded_cmd = yasd::Util::explode(last_cmd, " "); // breakpoint in current file with lineno if (exploded_cmd.size() == 2) { @@ -96,7 +96,7 @@ int Cmder::parse_delete_breakpoint_cmd() { int lineno; std::string filename; - auto exploded_cmd = yasd::Util::explode(last_cmd, ' '); + auto exploded_cmd = yasd::Util::explode(last_cmd, " "); if (exploded_cmd.size() == 2) { filename = yasd::Util::get_executed_filename(); @@ -198,7 +198,9 @@ int Cmder::parse_quit_cmd() { } int Cmder::parse_print_cmd() { - yasd::Util::print_var(last_cmd.c_str() + 2, last_cmd.length() - 2); + auto exploded_cmd = yasd::Util::explode(last_cmd, " "); + + yasd::Util::print_var(exploded_cmd[1]); global->do_next = true; return RECV_CMD_AGAIN; @@ -243,7 +245,7 @@ void Cmder::show_welcome_info() { int Cmder::execute_cmd() { // yasd::Context *context = global->get_current_context(); - auto exploded_cmd = yasd::Util::explode(last_cmd, ' '); + auto exploded_cmd = yasd::Util::explode(last_cmd, " "); if (!global->is_running) { if (is_disable_cmd(exploded_cmd[0])) { diff --git a/src/util.cc b/src/util.cc index 25b3ea1..55d1445 100644 --- a/src/util.cc +++ b/src/util.cc @@ -24,15 +24,36 @@ END_EXTERN_C() namespace yasd { -std::vector Util::explode(std::string const &s, char delim) { - std::vector result; - std::istringstream iss(s); +std::vector Util::explode(const std::string &target, const std::string &delimiter) { + std::vector arr; - for (std::string token; std::getline(iss, token, delim);) { - result.push_back(std::move(token)); + int str_len = target.length(); + int del_len = delimiter.length(); + + if (del_len == 0) { + return arr; } - return result; + int i = 0; + int k = 0; + + while (i < str_len) { + int j = 0; + while (i + j < str_len && j < del_len && target[i + j] == delimiter[j]) { + j++; + } + + if (j == del_len) { + arr.push_back(target.substr(k, i - k)); + i += del_len; + k = i; + } else { + i++; + } + } + + arr.push_back(target.substr(k, i - k)); + return arr; } HashTable *Util::get_defined_vars() { @@ -47,13 +68,29 @@ HashTable *Util::get_defined_vars() { return symbol_table; } -void Util::print_var(const char *var_name, size_t var_name_length) { +void Util::print_var(std::string var_name) { zval *var; HashTable *defined_vars; + zend_execute_data *execute_data = EG(current_execute_data); + + // print $this + if (var_name == "this") { + php_var_dump(ZEND_THIS, 1); + return; + } + + // print property + auto exploded_var_name = yasd::Util::explode(var_name, "->"); + if (exploded_var_name.size() == 2) { + zval *property = yasd_zend_read_property( + Z_OBJCE_P(ZEND_THIS), ZEND_THIS, exploded_var_name[1].c_str(), exploded_var_name[1].length(), 0); + php_var_dump(property, 1); + return; + } defined_vars = get_defined_vars(); - var = zend_hash_str_find(defined_vars, var_name, var_name_length); + var = zend_hash_str_find(defined_vars, var_name.c_str(), var_name.length()); if (!var) { std::cout << "not found variable $" << var_name << std::endl; } else {