/* * SPL - The SPL Programming Language * Copyright (C) 2004, 2005, 2006 Clifford Wolf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * mod_webdebug.c: WebSPL Debugger (CLIB part) */ #include #include "spl.h" #include "compat.h" static struct spl_code bytecode = #include "spl_modules/mod_webdebug.splh" ; extern void SPL_ABI(spl_mod_webdebug_init)(struct spl_vm *vm, struct spl_module *mod, int restore); extern void SPL_ABI(spl_mod_webdebug_done)(struct spl_vm *vm, struct spl_module *mod); static char nbspbuf[] = "            " "            " "            " "            " "            " "            " "            " "            " "            " "            " "            " "            "; /* this is really hackish! but the whole treedump/debug construct is and this * doubles the speed for redrawing the debug window. * * FIXME: This is not thread-save!!! */ static struct spl_node *info_node = 0; static struct spl_task *info_task = 0; /* modified xml_encode() from mod_encode_xml.c */ static char *txt2html(const char *source) { int source_i, target_i; for (source_i = target_i = 0; source[source_i]; source_i++) switch (source[source_i]) { case '&': /* & */ target_i += 5; break; case '<': /* < */ target_i += 4; break; case '>': /* > */ target_i += 4; break; case '"': /* " */ target_i += 6; break; case '\'': /* ' */ target_i += 6; break; case '\n': /*
*/ target_i += 5; break; case ' ': /*   */ target_i += 6; break; case '\t': /* 4x   */ target_i += 4*6; break; default: target_i++; } char *target = malloc(target_i+1); for (source_i = target_i = 0; source[source_i]; source_i++) switch (source[source_i]) { case '&': /* & */ target[target_i++] = '&'; target[target_i++] = 'a'; target[target_i++] = 'm'; target[target_i++] = 'p'; target[target_i++] = ';'; break; case '<': /* < */ target[target_i++] = '&'; target[target_i++] = 'l'; target[target_i++] = 't'; target[target_i++] = ';'; break; case '>': /* > */ target[target_i++] = '&'; target[target_i++] = 'g'; target[target_i++] = 't'; target[target_i++] = ';'; break; case '"': /* " */ target[target_i++] = '&'; target[target_i++] = 'q'; target[target_i++] = 'u'; target[target_i++] = 'o'; target[target_i++] = 't'; target[target_i++] = ';'; break; case '\'': /* ' */ target[target_i++] = '&'; target[target_i++] = 'a'; target[target_i++] = 'p'; target[target_i++] = 'o'; target[target_i++] = 's'; target[target_i++] = ';'; break; case '\n': /*
*/ target[target_i++] = '<'; target[target_i++] = 'b'; target[target_i++] = 'r'; target[target_i++] = '/'; target[target_i++] = '>'; break; case ' ': /*   */ target[target_i++] = '&'; target[target_i++] = 'n'; target[target_i++] = 'b'; target[target_i++] = 's'; target[target_i++] = 'p'; target[target_i++] = ';'; break; case '\t': /* 4x   */ target[target_i++] = '&'; target[target_i++] = 'n'; target[target_i++] = 'b'; target[target_i++] = 's'; target[target_i++] = 'p'; target[target_i++] = ';'; target[target_i++] = '&'; target[target_i++] = 'n'; target[target_i++] = 'b'; target[target_i++] = 's'; target[target_i++] = 'p'; target[target_i++] = ';'; target[target_i++] = '&'; target[target_i++] = 'n'; target[target_i++] = 'b'; target[target_i++] = 's'; target[target_i++] = 'p'; target[target_i++] = ';'; target[target_i++] = '&'; target[target_i++] = 'n'; target[target_i++] = 'b'; target[target_i++] = 's'; target[target_i++] = 'p'; target[target_i++] = ';'; break; default: target[target_i++] = source[source_i]; } target[target_i] = 0; return target; } static struct spl_node *handler_webdebug_gettree(struct spl_task *t, void UNUSED(*d)) { struct spl_node *tree_open = spl_clib_get_node(t); char *baseurl = spl_clib_get_string(t); char *info = strdup(spl_clib_get_string(t)); int show_tasks = spl_clib_get_int(t); int show_mods = spl_clib_get_int(t); char *treedump_raw = spl_treedump_string(t->vm, SPL_TREEDUMP_FLAG_ADDR | (show_tasks ? SPL_TREEDUMP_FLAG_TASKS : 0) | (show_mods ? SPL_TREEDUMP_FLAG_MODS : 0), info); int firstline = 1; char *input = treedump_raw; struct spl_string *output = 0; if (info_node) spl_put(t->vm, info_node); info_node = 0; info_task = 0; while (*input) { char *name = input; int name_len = strcspn(input, " [<\n"); input += name_len; input += strspn(input, " [<"); char *pos = input; char pos_type = 0; if (input[-1] == '[') pos_type = 'N'; if (input[-1] == '<') pos_type = 'T'; int pos_len = strcspn(input, ">] \n"); input += pos_len; input += strspn(input, ">] \n"); if (!name_len) break; int display = memchr(name, '.', name_len) ? 0 : 1; if (!display) { char *lastdot = my_memrchr(name, '.', name_len); char parent[(lastdot-name) + 1]; memcpy(parent, name, sizeof(parent)-1); parent[sizeof(parent)-1] = 0; if (!strcmp(parent, info)) display = 1; } char name_cpy[name_len+1]; memcpy(name_cpy, name, name_len); name_cpy[name_len] = '.'; if (!strncmp(name_cpy, info, name_len+1)) display = 1; int isinfonode = 0; name_cpy[name_len] = 0; int matched_info = 1; for (int i=0; name_cpy[i] || info[i]; i++) if (name_cpy[i] != info[i]) { if (!info[i]) { while (name_cpy[i] == '*') i++; if (!name_cpy[i]) break; } matched_info=0; break; } if (matched_info) { free(info); info = strdup(name_cpy); display = isinfonode = 1; } char *name_enc = spl_hash_encode(name_cpy); int isopen = spl_lookup(t, tree_open, name_enc, 0) ? 1 : 0; free(name_enc); int dots = 0; char *inner_basename = name_cpy; char *tmp; while ( (tmp=strchr(inner_basename, '.')) ) { inner_basename = tmp+1; dots++; } if (!display && !isopen) continue; int name_url_len = 1; for (char *p=name_cpy; *p; p++) if (*p == '#') name_url_len += 3; else name_url_len++; char name_url[name_url_len]; for (char *p=name_cpy, *q=name_url; *p; p++) if (*p == '#') { strcpy(q, "%23"); q+=3; } else { *(q++) = *p; *q = 0; } output = spl_string_printf(0, output, 0, "%s(%c) %.*s" "%s%s%s ", firstline ? "" : " 
\n", baseurl, name_url, isopen ? '+' : '-', dots*12, nbspbuf, baseurl, name_url, isinfonode ? "" : "", *inner_basename ? inner_basename : "*CTX*", isinfonode ? "" : ""); firstline=0; struct spl_node *node = 0; struct spl_task *task = 0; char pos_cpy[pos_len+1]; memcpy(pos_cpy, pos, pos_len); pos_cpy[pos_len] = 0; if (pos_type == 'N') sscanf(pos_cpy, "%p", &node); if (pos_type == 'T') sscanf(pos_cpy, "%p", &task); if (task && !info_task && !strcmp(name_cpy, info)) info_task = task; if (!node) continue; if (!info_node && !strcmp(name_cpy, info)) info_node = spl_get(node); if (!display && !isopen) continue; if (node->value) output = spl_string_printf(0, output, 0, "V"); if (node->subs_counter) output = spl_string_printf(0, output, 0, "S"); if (node->ctx) output = spl_string_printf(0, output, 0, "C"); if (node->hnode_name) output = spl_string_printf(0, output, 0, "H"); if (node->flags & (SPL_NODE_FLAG_FUNCTION|SPL_NODE_FLAG_METHOD)) output = spl_string_printf(0, output, 0, "F"); if (node->flags & (SPL_NODE_FLAG_RETINFO)) output = spl_string_printf(0, output, 0, "R"); if (node->flags & (SPL_NODE_FLAG_CLASS)) output = spl_string_printf(0, output, 0, "O"); if (node->ctx_type == SPL_CTX_FUNCTION) output = spl_string_printf(0, output, 0, "f"); if (node->ctx_type == SPL_CTX_OBJECT) output = spl_string_printf(0, output, 0, "o"); if (node->ctx_type == SPL_CTX_LOCAL) output = spl_string_printf(0, output, 0, "l"); if (node->ctx_type == SPL_CTX_ROOT) output = spl_string_printf(0, output, 0, "r"); } free(info); free(treedump_raw); return SPL_NEW_SPL_STRING(spl_string_printf(0, output, 0, " \n")); } static struct spl_node *handler_webdebug_getinfo(struct spl_task *t, void UNUSED(*d)) { char *info = spl_clib_get_string(t); char *baseurl = spl_clib_get_string(t); struct spl_string *output = 0; if (info_task) { output = spl_string_printf(0, output, 0, "

%s

\n", info); output = spl_string_printf(0, output, 0, "\n"); output = spl_string_printf(0, output, 0, "Backtrace:
\n
");
		output = spl_string_new(0, output, 0,
				spl_backtrace_string(info_task), 0);

		output = spl_string_printf(0, output, 0, "
\n"); return SPL_NEW_SPL_STRING(output); } if (!info_node) return 0; output = spl_string_printf(0, output, 0, "

%s

\n", info); output = spl_string_printf(0, output, 0, "\n"); if (strcmp(info, info_node->path)) output = spl_string_printf(0, output, 0, "Real Path:
%s

\n", baseurl, info_node->path, info_node->path); if (info_node->flags) { output = spl_string_printf(0, output, 0, "Flags:
\n"); #define SHOW_FLAG(x) if (info_node->flags & x) output = spl_string_printf(0, output, 0, "%s
\n", #x); SHOW_FLAG(SPL_NODE_FLAG_FUNCTION) SHOW_FLAG(SPL_NODE_FLAG_METHOD) SHOW_FLAG(SPL_NODE_FLAG_RETINFO) SHOW_FLAG(SPL_NODE_FLAG_STATIC) SHOW_FLAG(SPL_NODE_FLAG_CLASS) SHOW_FLAG(SPL_NODE_FLAG_CLNULL) SHOW_FLAG(SPL_NODE_FLAG_CLEXCEPT) SHOW_FLAG(SPL_NODE_FLAG_EXCEPTION) SHOW_FLAG(SPL_NODE_FLAG_TRY) SHOW_FLAG(SPL_NODE_FLAG_CATCH) SHOW_FLAG(SPL_NODE_FLAG_RERES) SHOW_FLAG(SPL_NODE_FLAG_ARGC) SHOW_FLAG(SPL_NODE_FLAG_IS_INT) SHOW_FLAG(SPL_NODE_FLAG_IS_FLOAT) SHOW_FLAG(SPL_NODE_FLAG_GC) #undef SHOW_FLAG output = spl_string_printf(0, output, 0, "

\n"); } if (info_node->ctx_type) { output = spl_string_printf(0, output, 0, "Context Type:
\n"); if (info_node->ctx_type == SPL_CTX_FUNCTION) output = spl_string_printf(0, output, 0, "SPL_CTX_FUNCTION
\n"); if (info_node->ctx_type == SPL_CTX_OBJECT) output = spl_string_printf(0, output, 0, "SPL_CTX_OBJECT
\n"); if (info_node->ctx_type == SPL_CTX_LOCAL) output = spl_string_printf(0, output, 0, "SPL_CTX_LOCAL
\n"); if (info_node->ctx_type == SPL_CTX_ROOT) output = spl_string_printf(0, output, 0, "SPL_CTX_ROOT
\n"); output = spl_string_printf(0, output, 0, "

\n"); } if (info_node->hnode_name) output = spl_string_printf(0, output, 0, "HNODE Handler Name:
%s

\n", info_node->hnode_name); if (info_node->ctx) output = spl_string_printf(0, output, 0, "Context / Pointer:
%s

\n", baseurl, info_node->ctx->path, info_node->ctx->path); if (info_node->cls) output = spl_string_printf(0, output, 0, "Parent Object / Class:
%s

\n", baseurl, info_node->cls->path, info_node->cls->path); if (info_node->value) { char *val = txt2html(spl_get_string(info_node)); output = spl_string_printf(0, output, 0, "Value:
%s

\n", val); free(val); } spl_put(t->vm, info_node); info_node = 0; output = spl_string_printf(0, output, 0, "\n"); return SPL_NEW_SPL_STRING(output); } static struct spl_node *handler_webdebug_exec(struct spl_task *t, void UNUSED(*d)) { char *code = spl_clib_get_string(t); spl_eval(t->vm, spl_get(info_node), 0, code); return 0; } void SPL_ABI(spl_mod_webdebug_init)(struct spl_vm *vm, struct spl_module *mod, int restore) { spl_clib_reg(vm, "__webdebug_gettree", handler_webdebug_gettree, 0); spl_clib_reg(vm, "__webdebug_getinfo", handler_webdebug_getinfo, 0); spl_clib_reg(vm, "__webdebug_exec", handler_webdebug_exec, 0); if ( !restore ) spl_eval_bytecode(vm, 0, strdup(mod->name), &bytecode); } void SPL_ABI(spl_mod_webdebug_done)(struct spl_vm *vm, struct spl_module UNUSED(*mod)) { if (info_node) spl_put(vm, info_node); info_node = 0; return; }