summaryrefslogtreecommitdiffhomepage
path: root/mini_xdebug.c
diff options
context:
space:
mode:
Diffstat (limited to 'mini_xdebug.c')
-rw-r--r--mini_xdebug.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/mini_xdebug.c b/mini_xdebug.c
new file mode 100644
index 0000000..b9263ba
--- /dev/null
+++ b/mini_xdebug.c
@@ -0,0 +1,132 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "php.h"
+#include "zend_extensions.h"
+
+#define MINI_XDEBUG_CMD_END -1
+#define MINI_XDEBUG_CMD_INVALID 0
+#define MINI_XDEBUG_CMD_NEXT 1
+
+static int g_is_first_statement;
+static int g_do_next_cmd;
+static int g_next_call_depth;
+
+static void mini_xdebug_activate(void) {
+ CG(compiler_options) |= ZEND_COMPILE_EXTENDED_STMT;
+ g_is_first_statement = 1;
+ g_do_next_cmd = 0;
+ g_next_call_depth = 0;
+}
+
+static int get_call_depth(void) {
+ int depth = 0;
+ zend_execute_data* ex = EG(current_execute_data);
+ while (ex) {
+ depth++;
+ ex = ex->prev_execute_data;
+ }
+ return depth;
+}
+
+static void show_context(const char* filename, int lineno) {
+ FILE* fp = fopen(filename, "r");
+ if (!fp) {
+ return;
+ }
+
+ char buf[1024];
+ int n = 0;
+ while (fgets(buf, sizeof(buf), fp)) {
+ n++;
+ if (lineno - 1 <= n && n <= lineno + 1) {
+ fprintf(stdout, "%s %3d | %s", n == lineno ? ">" : " ", n, buf);
+ }
+ if (n > lineno + 1) {
+ break;
+ }
+ }
+ fclose(fp);
+}
+
+static void show_prompt(void) {
+ fprintf(stdout, "(mini-xdebug) ");
+ fflush(stdout);
+}
+
+static int query_command(char* buf) {
+ if (!fgets(buf, sizeof(buf), stdin)) {
+ return MINI_XDEBUG_CMD_END;
+ }
+ buf[strcspn(buf, "\n")] = '\0';
+
+ return (!strcmp(buf, "next") || !strcmp(buf, "n"))
+ ? MINI_XDEBUG_CMD_NEXT
+ : MINI_XDEBUG_CMD_INVALID;
+}
+
+static void mini_xdebug_statement_handler(zend_execute_data* frame) {
+ if (!g_is_first_statement && !g_do_next_cmd) {
+ return;
+ }
+
+ uint32_t lineno = EG(current_execute_data)->opline->lineno;
+ const char* filename = ZSTR_VAL(frame->func->op_array.filename);
+ int depth = get_call_depth();
+
+ if (g_is_first_statement) {
+ g_is_first_statement = 0;
+ } else if (g_do_next_cmd) {
+ if (depth > g_next_call_depth) {
+ return;
+ }
+ g_do_next_cmd = 0;
+ }
+
+ fprintf(stdout, "\n%s:%d\n", filename, lineno);
+ show_context(filename, lineno);
+
+ char command_buf[256];
+ for (;;) {
+ show_prompt();
+ int cmd = query_command(command_buf);
+ if (cmd == MINI_XDEBUG_CMD_NEXT) {
+ g_do_next_cmd = 1;
+ g_next_call_depth = depth;
+ break;
+ } else if (cmd == MINI_XDEBUG_CMD_END) {
+ break;
+ } else {
+ fprintf(stdout, "Available commands: next (n)\n");
+ }
+ }
+}
+
+#ifndef ZEND_EXT_API
+#define ZEND_EXT_API ZEND_DLEXPORT
+#endif
+
+ZEND_EXT_API zend_extension_version_info extension_version_info = {
+ ZEND_EXTENSION_API_NO,
+ (char*)ZEND_EXTENSION_BUILD_ID,
+};
+
+ZEND_DLEXPORT zend_extension zend_extension_entry = {
+ "mini-xdebug", /* name */
+ "0.1.0", /* version */
+ "nsfisis", /* author */
+ "", /* URL */
+ "", /* copyright */
+ NULL, /* startup */
+ NULL, /* shutdown */
+ mini_xdebug_activate, /* activate */
+ NULL, /* deactivate */
+ NULL, /* message_handler */
+ NULL, /* op_array_handler */
+ mini_xdebug_statement_handler, /* statement_handler */
+ NULL, /* fcall_begin_handler */
+ NULL, /* fcall_end_handler */
+ NULL, /* op_array_ctor */
+ NULL, /* op_array_dtor */
+ STANDARD_ZEND_EXTENSION_PROPERTIES,
+};