Initial DAP implementation

So far only basic debugging functionality is implemented (breakpoints,
stepping, stack traces/variables).

This is not tested against an established DAP client. My intention is to
create a custom GUI frontend and extend the protocol to support
xsystem4-specific features, such as inspecting the scene. (This work is
underway.)

Instruction references are hex-encoded address strings. Clients do not
need to obtain them from DAP requests. This is outside the spec, but it
is needed for a binary-only debugger.

Functions that write directly to stdout (e.g. printf) should generally
not be used any more.  Instead, use either sys_message (which respects
sys_silent) or log_message (which will send the message to the debugger
if DAP is enabled). stderr can be used as normal.
This commit is contained in:
Nunuhara Cabbage
2023-04-29 10:32:50 -07:00
parent 4ad893c147
commit d4e06db8e2
19 changed files with 1217 additions and 255 deletions
+17
View File
@@ -18,6 +18,7 @@
#define SYSTEM4_DEBUGGER_H
#ifdef DEBUGGER_ENABLED
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include "system4/instructions.h"
@@ -46,6 +47,7 @@ struct dbg_cmd {
void (*run)(unsigned nr_args, char **args);
};
extern bool dbg_dap;
extern bool dbg_enabled;
extern bool dbg_start_in_debugger;
extern unsigned dbg_current_frame;
@@ -54,6 +56,8 @@ void dbg_init(void);
void dbg_fini(void);
void dbg_repl(void);
void dbg_log(const char *log, const char *fmt, va_list ap);
void dbg_continue(void);
void dbg_quit(void);
void dbg_start(void(*fun)(void*), void *data);
@@ -61,6 +65,7 @@ void dbg_cmd_init(void);
void dbg_cmd_repl(void);
void dbg_cmd_add_module(const char *name, unsigned nr_commands, struct dbg_cmd *commands);
void dbg_handle_breakpoint(void);
bool dbg_clear_breakpoint(uint32_t addr, void(*free_data)(void*));
bool dbg_set_function_breakpoint(const char *_name, void(*cb)(struct breakpoint*), void *data);
bool dbg_set_address_breakpoint(uint32_t address, void(*cb)(struct breakpoint*), void *data);
bool dbg_set_step_over_breakpoint(void);
@@ -73,10 +78,22 @@ void dbg_print_vm_state(void);
union vm_value dbg_eval_string(const char *str, struct ain_type *type_out);
struct string *dbg_value_to_string(struct ain_type *type, union vm_value value, int recursive);
void dbg_dap_init(void);
void dbg_dap_quit(void);
void dbg_dap_repl(void);
void dbg_dap_handle_messages(void);
void dbg_dap_log(const char *log, const char *fmt, va_list ap);
#ifdef HAVE_SCHEME
void dbg_scm_init(void);
void dbg_scm_fini(void);
void dbg_scm_repl(void);
#endif /* HAVE_SCHEME */
#else /* DEBUGGER ENABLED */
#define dbg_init()
#define dbg_repl()
#define dbg_dap 0
#define dbg_dap_handle_messages()
#define dbg_dap_log(log, fmt, ap)
#endif /* DEBUGGER_ENABLED */
#endif /* SYSTEM4_DEBUGGER_H */
+45
View File
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* 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
*
*/
#ifndef __MSGQUEUE_H__
#define __MSGQUEUE_H__
#include <stdbool.h>
#include <SDL_mutex.h>
struct msgq_elem;
struct msgq {
SDL_mutex *mutex;
SDL_cond *cond_nonempty;
struct msgq_elem *head;
struct msgq_elem *last;
};
static inline bool msgq_isempty(struct msgq *q) {
return !q->head;
}
struct msgq *msgq_new(void);
void msgq_free(struct msgq *q);
void msgq_enqueue(struct msgq *q, void *msg);
void *msgq_dequeue(struct msgq *q);
void *msgq_dequeue_timeout(struct msgq *q, uint32_t timeout_ms);
#endif // __MSGQUEUE_H__
+3 -1
View File
@@ -56,7 +56,9 @@ const char *display_utf0(const char *utf);
const char *display_utf1(const char *utf);
const char *display_utf2(const char *utf);
void indent_printf(int indent, const char *fmt, ...);
void indent_message(int indent, const char *fmt, ...);
void log_message(const char *log, const char *fmt, ...);
char *unix_path(const char *path);
char *gamedir_path(const char *path);
+38 -38
View File
@@ -60,11 +60,11 @@ static const char *fog_type_name(enum RE_fog_type type)
static void print_motion(const char *name, struct motion *m, int indent)
{
if (m->instance->type == RE_ITYPE_BILLBOARD) {
indent_printf(indent, "%s = {state=%s, frame=%f, range=(%d,%d), loop_range=(%d,%d)},\n",
indent_message(indent, "%s = {state=%s, frame=%f, range=(%d,%d), loop_range=(%d,%d)},\n",
name, motion_state_name(m->state), m->current_frame,
(int)m->frame_begin, (int)m->frame_end, (int)m->loop_frame_begin, (int)m->loop_frame_end);
} else if (m->mot) {
indent_printf(indent, "%s = {name=\"%s\", state=%s, frame=%f},\n",
indent_message(indent, "%s = {name=\"%s\", state=%s, frame=%f},\n",
name, m->mot->name, motion_state_name(m->state), m->current_frame);
}
}
@@ -73,85 +73,85 @@ static void print_instance(struct RE_instance *inst, int index, int indent)
{
if (!inst)
return;
indent_printf(indent, "instance[%d] = {\n", index);
indent_message(indent, "instance[%d] = {\n", index);
indent++;
indent_printf(indent, "type = %s,\n", instance_type_name(inst->type));
indent_message(indent, "type = %s,\n", instance_type_name(inst->type));
if (inst->type == RE_ITYPE_DIRECTIONAL_LIGHT || inst->type == RE_ITYPE_SPECULAR_LIGHT) {
indent_printf(indent, "vec = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(inst->vec));
indent_printf(indent, "diffuse = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(inst->diffuse));
indent_printf(indent, "globe_diffuse = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(inst->globe_diffuse));
indent_message(indent, "vec = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(inst->vec));
indent_message(indent, "diffuse = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(inst->diffuse));
indent_message(indent, "globe_diffuse = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(inst->globe_diffuse));
} else {
indent_printf(indent, "draw = %d,\n", inst->draw);
indent_printf(indent, "pos = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(inst->pos));
indent_printf(indent, "scale = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(inst->scale));
indent_printf(indent, "ambient = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(inst->ambient));
indent_message(indent, "draw = %d,\n", inst->draw);
indent_message(indent, "pos = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(inst->pos));
indent_message(indent, "scale = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(inst->scale));
indent_message(indent, "ambient = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(inst->ambient));
}
if (inst->model) {
indent_printf(indent, "path = \"%s\",\n", inst->model->path);
indent_printf(indent, "aabb = {min = {x=%f, y=%f, z=%f}, max = {x=%f, y=%f, z=%f}},\n",
indent_message(indent, "path = \"%s\",\n", inst->model->path);
indent_message(indent, "aabb = {min = {x=%f, y=%f, z=%f}, max = {x=%f, y=%f, z=%f}},\n",
SPREAD_VEC3(inst->model->aabb[0]), SPREAD_VEC3(inst->model->aabb[1]));
}
if (inst->motion) {
indent_printf(indent, "fps = %f,\n", inst->fps);
indent_message(indent, "fps = %f,\n", inst->fps);
print_motion("motion", inst->motion, indent);
}
if (inst->next_motion)
print_motion("next_motion", inst->next_motion, indent);
if (inst->motion_blend)
indent_printf(indent, "motion_blend_rate = %f,\n", inst->motion_blend_rate);
indent_message(indent, "motion_blend_rate = %f,\n", inst->motion_blend_rate);
if (inst->effect)
indent_printf(indent, "path = \"%s\",\n", inst->effect->pae->path);
indent_message(indent, "path = \"%s\",\n", inst->effect->pae->path);
indent--;
indent_printf(indent, "},\n");
indent_message(indent, "},\n");
}
static void print_back_cg(struct RE_back_cg *bcg, int index, int indent)
{
if (!bcg->name && !bcg->no)
return;
indent_printf(indent, "backCG[%d] = {\n", index);
indent_message(indent, "backCG[%d] = {\n", index);
indent++;
if (bcg->no)
indent_printf(indent, "no = %d,\n", bcg->no);
indent_message(indent, "no = %d,\n", bcg->no);
if (bcg->name)
indent_printf(indent, "name = \"%s\",\n", bcg->name ? bcg->name->text : "");
indent_printf(indent, "pos = {x=%f, y=%f},\n", bcg->x, bcg->y);
indent_printf(indent, "blend_rate = %f,\n", bcg->blend_rate);
indent_printf(indent, "mag = %f,\n", bcg->mag);
indent_printf(indent, "show = %d,\n", bcg->show);
indent_message(indent, "name = \"%s\",\n", bcg->name ? bcg->name->text : "");
indent_message(indent, "pos = {x=%f, y=%f},\n", bcg->x, bcg->y);
indent_message(indent, "blend_rate = %f,\n", bcg->blend_rate);
indent_message(indent, "mag = %f,\n", bcg->mag);
indent_message(indent, "show = %d,\n", bcg->show);
indent--;
indent_printf(indent, "},\n");
indent_message(indent, "},\n");
}
void RE_debug_print(struct sact_sprite *sp, int indent)
{
struct RE_plugin *p = (struct RE_plugin *)sp->plugin;
indent_printf(indent, "name = \"%s\",\n", p->plugin.name);
indent_printf(indent, "camera = {x=%f, y=%f, z=%f, pitch=%f, roll=%f, yaw=%f},\n",
indent_message(indent, "name = \"%s\",\n", p->plugin.name);
indent_message(indent, "camera = {x=%f, y=%f, z=%f, pitch=%f, roll=%f, yaw=%f},\n",
SPREAD_VEC3(p->camera.pos), p->camera.pitch, p->camera.roll, p->camera.yaw);
indent_printf(indent, "shadow_map_light_dir = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(p->shadow_map_light_dir));
indent_printf(indent, "shadow_bias = %f,\n", p->shadow_bias);
indent_message(indent, "shadow_map_light_dir = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(p->shadow_map_light_dir));
indent_message(indent, "shadow_bias = %f,\n", p->shadow_bias);
indent_printf(indent, "fog_type = %s,\n", fog_type_name(p->fog_type));
indent_message(indent, "fog_type = %s,\n", fog_type_name(p->fog_type));
switch (p->fog_type) {
case RE_FOG_NONE:
break;
case RE_FOG_LINEAR:
indent_printf(indent, "fog_near = %f, fog_far = %f,\n", p->fog_near, p->fog_far);
indent_printf(indent, "fog_color = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(p->fog_color));
indent_message(indent, "fog_near = %f, fog_far = %f,\n", p->fog_near, p->fog_far);
indent_message(indent, "fog_color = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(p->fog_color));
break;
case RE_FOG_LIGHT_SCATTERING:
indent_printf(indent, "ls_beta_r = %f, ls_beta_m = %f,\n", p->ls_beta_r, p->ls_beta_m);
indent_printf(indent, "ls_g = %f,\n", p->ls_g);
indent_printf(indent, "ls_distance = %f,\n", p->ls_distance);
indent_printf(indent, "ls_light_dir = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(p->ls_light_dir));
indent_printf(indent, "ls_light_color = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(p->ls_light_color));
indent_printf(indent, "ls_sun_color = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(p->ls_sun_color));
indent_message(indent, "ls_beta_r = %f, ls_beta_m = %f,\n", p->ls_beta_r, p->ls_beta_m);
indent_message(indent, "ls_g = %f,\n", p->ls_g);
indent_message(indent, "ls_distance = %f,\n", p->ls_distance);
indent_message(indent, "ls_light_dir = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(p->ls_light_dir));
indent_message(indent, "ls_light_color = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(p->ls_light_color));
indent_message(indent, "ls_sun_color = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(p->ls_sun_color));
break;
}
+28 -8
View File
@@ -36,6 +36,7 @@
#include "little_endian.h"
#include "xsystem4.h"
bool dbg_dap = false;
bool dbg_enabled = true;
bool dbg_start_in_debugger = false;
unsigned dbg_current_frame = 0;
@@ -74,7 +75,10 @@ void dbg_start(void(*fun)(void*), void *data)
static void _dbg_repl(void *_)
{
dbg_cmd_repl();
if (dbg_dap)
dbg_dap_repl();
else
dbg_cmd_repl();
}
void dbg_repl(void)
@@ -86,10 +90,15 @@ void dbg_repl(void)
void dbg_init(void)
{
dbg_cmd_init();
if (dbg_dap)
dbg_dap_init();
else
dbg_cmd_init();
#ifdef HAVE_SCHEME
dbg_scm_init();
#endif
if (!dbg_dap && dbg_start_in_debugger)
dbg_repl();
}
void dbg_fini(void)
@@ -135,6 +144,17 @@ static struct breakpoint *get_breakpoint(uint32_t addr)
return ht_get_int(bp_table, addr, NULL);
}
bool dbg_clear_breakpoint(uint32_t addr, void(*free_data)(void*))
{
struct breakpoint *bp = get_breakpoint(addr);
if (!bp)
return false;
if (free_data)
free_data(bp->data);
delete_breakpoint(addr, bp);
return true;
}
bool dbg_set_function_breakpoint(const char *_name, void(*cb)(struct breakpoint*), void *data)
{
char *name = utf2sjis(_name, 0);
@@ -157,7 +177,7 @@ bool dbg_set_function_breakpoint(const char *_name, void(*cb)(struct breakpoint*
LittleEndian_putW(ain->code, f->address, BREAKPOINT | bp->restore_op);
add_breakpoint(f->address, bp);
printf("Set breakpoint at function '%s' (0x%08x)\n", display_utf0(_name), f->address);
log_message("debug", "Set breakpoint at function '%s' (0x%08x)\n", display_utf0(_name), f->address);
return true;
}
@@ -185,7 +205,7 @@ bool dbg_set_address_breakpoint(uint32_t address, void(*cb)(struct breakpoint*),
LittleEndian_putW(ain->code, address, BREAKPOINT | bp->restore_op);
add_breakpoint(address, bp);
printf("Set breakpoint at 0x%08x\n", address);
log_message("debug", "Set breakpoint at 0x%08x\n", address);
return true;
}
@@ -196,7 +216,7 @@ static void dbg_step_breakpoint_cb(struct breakpoint *bp)
if ((intptr_t)bp->data != call_stack_ptr)
return;
delete_breakpoint(instr_ptr, bp);
dbg_cmd_repl();
_dbg_repl(NULL);
}
static void dbg_set_step_breakpoint(int32_t address, int call_index)
@@ -384,8 +404,8 @@ static void _dbg_handle_breakpoint(void *data)
if (bp->cb) {
bp->cb(bp);
} else {
printf("%s\n", bp->message);
dbg_cmd_repl();
log_message("debug", "%s\n", bp->message);
_dbg_repl(NULL);
}
}
@@ -408,7 +428,7 @@ void dbg_print_frame(unsigned no)
unsigned cs_no = call_stack_ptr - (1 + no);
struct ain_function *f = &ain->functions[call_stack[cs_no].fno];
uint32_t addr = no ? call_stack[cs_no+1].call_address : instr_ptr;
printf("%c #%d 0x%08x in %s\n", no == dbg_current_frame ? '*' : ' ',
sys_message("%c #%d 0x%08x in %s\n", no == dbg_current_frame ? '*' : ' ',
no, addr, display_sjis0(f->name));
}
+756
View File
@@ -0,0 +1,756 @@
/* Copyright (C) 2023 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* Based largely on DAP implementation from xsystem35-sdl2
* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* 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, see <http://gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <SDL_thread.h>
#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#endif
#define VM_PRIVATE
#include "system4.h"
#include "system4/string.h"
#include "system4/utfsjis.h"
#include "xsystem4.h"
#include "cJSON.h"
#include "debugger.h"
#include "msgqueue.h"
#include "vm.h"
#include "vm/heap.h"
#include "vm/page.h"
#define THREAD_ID 1
static enum {
DAP_UNINITIALIZED,
DAP_INITIALIZED,
DAP_RUNNING,
DAP_STOPPED
} dap_state = DAP_UNINITIALIZED;
static struct msgq *queue;
static void json_add_sjis_to_object(cJSON *obj, const char *name, const char *sjis)
{
char *utf = sjis2utf(sjis, 0);
cJSON_AddStringToObject(obj, name, utf);
free(utf);
}
static void send_json(cJSON *json)
{
static int seq = 1;
cJSON_AddNumberToObject(json, "seq", seq++);
char *str = cJSON_PrintUnformatted(json);
printf("Content-Length: %zu\r\n\r\n%s", strlen(str), str);
fflush(stdout);
free(str);
cJSON_Delete(json);
}
static void send_response(cJSON *response, bool success)
{
cJSON_AddBoolToObject(response, "success", success);
send_json(response);
}
static void emit_event(const char *name, struct cJSON *body)
{
cJSON *event = cJSON_CreateObject();
cJSON_AddStringToObject(event, "type", "event");
cJSON_AddStringToObject(event, "event", name);
if (body) {
cJSON_AddItemToObjectCS(event, "body", body);
}
send_json(event);
}
static void emit_initialized_event(void)
{
emit_event("initialized", NULL);
}
static void emit_terminated_event(void)
{
emit_event("terminated", NULL);
}
static void emit_stopped_event(void)
{
cJSON *body = cJSON_CreateObject();
// TODO: specify correct reason
cJSON_AddStringToObject(body, "reason", "pause");
emit_event("stopped", body);
}
static void emit_output_event(const char *category, const char *output)
{
cJSON *body = cJSON_CreateObject();
cJSON_AddStringToObject(body, "category", category);
cJSON_AddStringToObject(body, "output", output);
emit_event("output", body);
}
static void cmd_initialize(cJSON *args, cJSON *resp)
{
cJSON *body;
cJSON_AddItemToObjectCS(resp, "body", body = cJSON_CreateObject());
cJSON_AddBoolToObject(body, "supportsConfigurationDoneRequest", true);
//cJSON_AddBoolToObject(body, "supportsFunctionBreakpoints", true);
//cJSON_AddBoolToObject(body, "supportsConditionalBreakpoints", true);
//cJSON_AddBoolToObject(body, "supportsHitConditionalBreakpoints", true);
cJSON_AddBoolToObject(body, "supportsEvaluateForHovers", true);
//cJSON_AddBoolToObject(body, "supportsSetVariable", true);
//cJSON_AddBoolToObject(body, "supportsSetExpression", true);
//cJSON_AddBoolToObject(body, "supportsTerminateRequest", true);
cJSON_AddBoolToObject(body, "supportsInstructionBreakpoints", true);
send_response(resp, true);
emit_initialized_event();
dap_state = DAP_INITIALIZED;
}
static void cmd_launch(cJSON *args, cJSON *resp)
{
if (dap_state != DAP_INITIALIZED) {
send_response(resp, false);
return;
}
// TODO: handle noDebug option
send_response(resp, true);
dap_state = DAP_RUNNING;
}
static void cmd_configurationDone(cJSON *args, cJSON *resp)
{
send_response(resp, true);
}
static void cmd_stackTrace(cJSON *args, cJSON *resp)
{
cJSON *body, *stack_frames, *frame;
// FIXME: we ignore startFrame/levels arguments
cJSON_AddItemToObjectCS(resp, "body", body = cJSON_CreateObject());
cJSON_AddNumberToObject(body, "totalFrames", call_stack_ptr);
cJSON_AddItemToObjectCS(body, "stackFrames", stack_frames = cJSON_CreateArray());
for (int i = 0; i < call_stack_ptr; i++) {
cJSON_AddItemToArray(stack_frames, frame = cJSON_CreateObject());
cJSON_AddNumberToObject(frame, "id", i);
// this *shouldn't* happen, but since we're in the debugger...
int fno = call_stack[i].fno;
if (fno < 0 || fno >= ain->nr_functions) {
cJSON_AddStringToObject(frame, "name", "<invalid function>");
} else {
json_add_sjis_to_object(frame, "name", ain->functions[fno].name);
}
char ip[9];
if (i == call_stack_ptr - 1) {
snprintf(ip, 9, "%x", (unsigned)instr_ptr);
} else {
snprintf(ip, 9, "%x", call_stack[i].call_address);
}
cJSON_AddStringToObject(frame, "instructionPointerReference", ip);
cJSON_AddNumberToObject(frame, "line", 0);
cJSON_AddNumberToObject(frame, "column", 0);
}
send_response(resp, true);
}
enum var_ref_type {
VAR_REF_ARGUMENTS = 0,
VAR_REF_LOCALS = 1,
VAR_REF_MEMBERS = 2,
VAR_REF_GENERIC = 3,
};
static inline unsigned var_ref(unsigned slot, enum var_ref_type type)
{
return (slot << 4) | type;
}
static inline unsigned var_ref_slot(unsigned var_ref)
{
return var_ref >> 4;
}
static inline enum var_ref_type var_ref_type(unsigned var_ref)
{
return var_ref & 0xF;
}
static void cmd_scopes(cJSON *args, cJSON *resp)
{
if (!args) {
send_response(resp, false);
return;
}
cJSON *j_id = cJSON_GetObjectItemCaseSensitive(args, "frameId");
if (!j_id || !cJSON_IsNumber(j_id)) {
send_response(resp, false);
return;
}
int id = j_id->valueint;
if (id < 0 || id >= call_stack_ptr) {
send_response(resp, false);
return;
}
if (call_stack[id].fno < 0 || call_stack[id].fno >= ain->nr_functions) {
send_response(resp, false);
return;
}
cJSON *body, *scopes, *arg_scope, *loc_scope, *mem_scope;
cJSON_AddItemToObjectCS(resp, "body", body = cJSON_CreateObject());
cJSON_AddItemToObjectCS(body, "scopes", scopes = cJSON_CreateArray());
int l_page = call_stack[id].page_slot;
if (page_index_valid(l_page) && heap_get_page(l_page)->type == LOCAL_PAGE) {
int arg_ref = var_ref(l_page, VAR_REF_ARGUMENTS);
int loc_ref = var_ref(l_page, VAR_REF_LOCALS);
cJSON_AddItemToArray(scopes, arg_scope = cJSON_CreateObject());
cJSON_AddStringToObject(arg_scope, "name", "Arguments");
cJSON_AddStringToObject(arg_scope, "presentationHint", "arguments");
cJSON_AddNumberToObject(arg_scope, "variablesReference", arg_ref);
cJSON_AddItemToArray(scopes, loc_scope = cJSON_CreateObject());
cJSON_AddStringToObject(loc_scope, "name", "Locals");
cJSON_AddStringToObject(loc_scope, "presentationHint", "locals");
cJSON_AddNumberToObject(loc_scope, "variablesReference", loc_ref);
}
int s_page = call_stack[id].struct_page;
if (page_index_valid(s_page) && heap_get_page(s_page)->type == STRUCT_PAGE) {
int mem_ref = var_ref(s_page, VAR_REF_MEMBERS);
cJSON_AddItemToArray(scopes, mem_scope = cJSON_CreateObject());
cJSON_AddStringToObject(mem_scope, "name", "Members");
cJSON_AddStringToObject(mem_scope, "presentationHint", "locals");
cJSON_AddNumberToObject(mem_scope, "variablesReference", mem_ref);
}
// TODO: stack values?
send_response(resp, true);
}
static bool type_is_structured(struct ain_type *type)
{
switch (type->data) {
case AIN_STRUCT:
case AIN_REF_STRUCT:
case AIN_ARRAY_TYPE:
case AIN_REF_ARRAY_TYPE:
return true;
default:
return false;
}
}
static int make_var_ref(struct ain_type *type, union vm_value value)
{
if (type_is_structured(type) && page_index_valid(value.i))
return var_ref(value.i, VAR_REF_GENERIC);
return 0;
}
static cJSON *value_to_json(const char *name, struct ain_type *type, union vm_value value)
{
char *s_type = ain_strtype_d(ain, type);
struct string *s_val = dbg_value_to_string(type, value, 0);
cJSON *json = cJSON_CreateObject();
json_add_sjis_to_object(json, "name", name);
json_add_sjis_to_object(json, "value", s_val->text);
json_add_sjis_to_object(json, "type", s_type);
cJSON_AddNumberToObject(json, "variablesReference", make_var_ref(type, value));
free_string(s_val);
free(s_type);
return json;
}
static cJSON *var_to_json(struct ain_variable *var, union vm_value value)
{
return value_to_json(var->name, &var->type, value);
}
static void add_arguments_to_array(cJSON *array, struct page *page)
{
struct ain_function *f = &ain->functions[page->index];
for (int i = 0; i < f->nr_args; i++) {
cJSON_AddItemToArray(array, var_to_json(&f->vars[i], page->values[i]));
}
}
static void add_locals_to_array(cJSON *array, struct page *page)
{
struct ain_function *f = &ain->functions[page->index];
for (int i = f->nr_args; i < f->nr_vars; i++) {
cJSON_AddItemToArray(array, var_to_json(&f->vars[i], page->values[i]));
}
}
static void add_variables_to_array(cJSON *array, struct page *page)
{
struct ain_function *f = &ain->functions[page->index];
for (int i = 0; i < f->nr_vars; i++) {
cJSON_AddItemToArray(array, var_to_json(&f->vars[i], page->values[i]));
}
}
static void add_members_to_array(cJSON *array, struct page *page)
{
struct ain_struct *s = &ain->structures[page->index];
for (int i = 0; i < s->nr_members; i++) {
cJSON_AddItemToArray(array, var_to_json(&s->members[i], page->values[i]));
}
}
static void add_globals_to_array(cJSON *array, struct page *page)
{
for (int i = 0; i < ain->nr_globals; i++) {
cJSON_AddItemToArray(array, var_to_json(&ain->globals[i], page->values[i]));
}
}
static void add_array_elements_to_array(cJSON *array, struct page *page)
{
if (!page)
return;
for (int i = 0; i < page->nr_vars; i++) {
char name[512];
snprintf(name, 512, "[%d]", i);
struct ain_type type;
type.data = variable_type(page, i, &type.struc, &type.rank);
cJSON_AddItemToArray(array, value_to_json(name, &type, page->values[i]));
}
}
static void add_page_to_array(cJSON *array, struct page *page)
{
switch (page->type) {
case GLOBAL_PAGE:
add_globals_to_array(array, page);
break;
case LOCAL_PAGE:
add_variables_to_array(array, page);
break;
case STRUCT_PAGE:
add_members_to_array(array, page);
break;
case ARRAY_PAGE:
add_array_elements_to_array(array, page);
break;
default:
break;
}
}
static cJSON *var_ref_to_json(struct page *page, enum var_ref_type type)
{
cJSON *vars = cJSON_CreateArray();
if (type == VAR_REF_ARGUMENTS) {
add_arguments_to_array(vars, page);
} else if (type == VAR_REF_LOCALS) {
add_locals_to_array(vars, page);
} else if (type == VAR_REF_MEMBERS) {
add_members_to_array(vars, page);
} else if (type == VAR_REF_GENERIC) {
add_page_to_array(vars, page);
} else {
cJSON_Delete(vars);
return NULL;
}
return vars;
}
static void cmd_variables(cJSON *args, cJSON *resp)
{
if (!args) {
send_response(resp, false);
return;
}
cJSON *j_ref = cJSON_GetObjectItemCaseSensitive(args, "variablesReference");
if (!j_ref || !cJSON_IsNumber(j_ref)) {
send_response(resp, false);
return;
}
int slot = var_ref_slot(j_ref->valueint);
enum var_ref_type type = var_ref_type(j_ref->valueint);
if (!page_index_valid(slot)) {
send_response(resp, false);
return;
}
struct page *page = heap_get_page(slot);
// FIXME: filter/start/count are ignored
cJSON *vars = var_ref_to_json(page, type);
if (!vars) {
send_response(resp, false);
return;
}
cJSON *body = cJSON_CreateObject();
cJSON_AddItemToObjectCS(body, "variables", vars);
cJSON_AddItemToObjectCS(resp, "body", body);
send_response(resp, true);
}
static void cmd_setInstructionBreakpoints(cJSON *args, cJSON *resp)
{
static uint32_t *old_breakpoints = NULL;
static int nr_old_breakpoints = 0;
uint32_t *addresses = NULL;
if (!args) {
goto fail;
}
cJSON *j_bp = cJSON_GetObjectItemCaseSensitive(args, "breakpoints");
if (!j_bp || !cJSON_IsArray(j_bp)) {
goto fail;
}
int nr_breakpoints = cJSON_GetArraySize(j_bp);
addresses = xcalloc(nr_breakpoints, sizeof(uint32_t));
int i;
cJSON *e;
cJSON_ArrayForEachIndex(i, e, j_bp) {
if (!cJSON_IsObject(e)) {
goto fail;
}
cJSON *ref = cJSON_GetObjectItemCaseSensitive(e, "instructionReference");
if (!ref || !cJSON_IsString(ref)) {
goto fail;
}
char *endptr;
addresses[i] = strtol(ref->valuestring, &endptr, 16);
if (ref->valuestring[0] == '\0' || *endptr != '\0') {
goto fail;
}
// FIXME: offset is ignored
// TODO: condition
// TODO: hitCondition
}
// clear old breakpoints
for (int i = 0; i < nr_old_breakpoints; i++) {
dbg_clear_breakpoint(old_breakpoints[i], NULL);
}
cJSON *body, *breakpoints, *bp;
cJSON_AddItemToObjectCS(resp, "body", body = cJSON_CreateObject());
cJSON_AddItemToObjectCS(body, "breakpoints", breakpoints = cJSON_CreateArray());
for (int i = 0; i < nr_breakpoints; i++) {
char s_addr[9];
snprintf(s_addr, 9, "%x", addresses[i]);
cJSON_AddItemToArray(breakpoints, bp = cJSON_CreateObject());
cJSON_AddStringToObject(breakpoints, "instructionReference", s_addr);
bool verified = dbg_set_address_breakpoint(addresses[i], NULL, NULL);
cJSON_AddBoolToObject(bp, "verified", verified);
// TODO: id, message, offset
}
// save new breakpoints list
free(old_breakpoints);
old_breakpoints = addresses;
nr_old_breakpoints = nr_breakpoints;
send_response(resp, true);
return;
fail:
free(addresses);
send_response(resp, false);
}
static void cmd_evaluate(cJSON *args, cJSON *resp)
{
if (!args) {
send_response(resp, false);
return;
}
cJSON *j_expr = cJSON_GetObjectItemCaseSensitive(args, "expression");
if (!j_expr || !cJSON_IsString(j_expr)) {
send_response(resp, false);
return;
}
// TODO: frameId
struct ain_type type;
union vm_value val = dbg_eval_string(j_expr->valuestring, &type);
struct string *s_val = dbg_value_to_string(&type, val, 0);
char *s_type = ain_strtype_d(ain, &type);
cJSON *body;
cJSON_AddItemToObjectCS(resp, "body", body = cJSON_CreateObject());
json_add_sjis_to_object(body, "result", s_val->text);
json_add_sjis_to_object(body, "type", s_type);
cJSON_AddNumberToObject(body, "variablesReference", make_var_ref(&type, val));
// TODO: presentationHint
send_response(resp, true);
}
static void cmd_continue(cJSON *args, cJSON *resp)
{
send_response(resp, true);
dap_state = DAP_RUNNING;
dbg_continue();
}
static void cmd_pause(cJSON *args, cJSON *resp)
{
if (dap_state < DAP_RUNNING) {
cJSON_AddBoolToObject(resp, "success", false);
return;
}
cJSON_AddBoolToObject(resp, "success", true);
send_json(resp);
if (dap_state != DAP_STOPPED) {
dbg_repl();
}
}
static void cmd_stepIn(cJSON *args, cJSON *resp)
{
dbg_set_step_into_breakpoint();
send_response(resp, true);
dap_state = DAP_RUNNING;
dbg_continue();
}
static void cmd_stepOut(cJSON *args, cJSON *resp)
{
dbg_set_finish_breakpoint();
send_response(resp, true);
dap_state = DAP_RUNNING;
dbg_continue();
}
static void cmd_next(cJSON *args, cJSON *resp)
{
dbg_set_step_over_breakpoint();
send_response(resp, true);
dap_state = DAP_RUNNING;
dbg_continue();
}
static void cmd_threads(cJSON *args, cJSON *resp)
{
cJSON *body, *threads, *thread;
cJSON_AddItemToObjectCS(resp, "body", body = cJSON_CreateObject());
cJSON_AddItemToObjectCS(body, "threads", threads = cJSON_CreateArray());
cJSON_AddItemToArray(threads, thread = cJSON_CreateObject());
cJSON_AddNumberToObject(thread, "id", 0);
cJSON_AddStringToObject(thread, "name", "main_thread");
send_response(resp, true);
}
static void cmd_setVariable(cJSON *args, cJSON *resp)
{
// TODO
send_response(resp, false);
}
static void cmd_disconnect(cJSON *args, cJSON *resp)
{
// TODO
send_response(resp, false);
}
static bool handle_request(cJSON *request)
{
bool continue_repl = true;
cJSON *resp = cJSON_CreateObject();
cJSON_AddStringToObject(resp, "type", "response");
cJSON *request_seq = cJSON_DetachItemFromObjectCaseSensitive(request, "seq");
cJSON_AddItemToObjectCS(resp, "request_seq", request_seq);
cJSON *command = cJSON_DetachItemFromObjectCaseSensitive(request, "command");
cJSON_AddItemToObjectCS(resp, "command", command);
cJSON *args = cJSON_GetObjectItemCaseSensitive(request, "arguments");
if (!cJSON_IsString(command)) {
WARNING("protocol error: command is not a string");
cJSON_Delete(resp);
return continue_repl;
}
if (!strcmp(command->valuestring, "initialize")) {
cmd_initialize(args, resp);
} else if (!strcmp(command->valuestring, "launch")) {
cmd_launch(args, resp);
} else if (!strcmp(command->valuestring, "configurationDone")) {
cmd_configurationDone(args, resp);
} else if (!strcmp(command->valuestring, "continue")) {
cmd_continue(args, resp);
continue_repl = false;
} else if (!strcmp(command->valuestring, "stackTrace")) {
cmd_stackTrace(args, resp);
} else if (!strcmp(command->valuestring, "stepIn")) {
cmd_stepIn(args, resp);
continue_repl = false;
} else if (!strcmp(command->valuestring, "stepOut")) {
cmd_stepOut(args, resp);
continue_repl = false;
} else if (!strcmp(command->valuestring, "next")) {
cmd_next(args, resp);
continue_repl = false;
} else if (!strcmp(command->valuestring, "pause")) {
cmd_pause(args, resp);
} else if (!strcmp(command->valuestring, "evaluate")) {
cmd_evaluate(args, resp);
} else if (!strcmp(command->valuestring, "setInstructionBreakpoints")) {
cmd_setInstructionBreakpoints(args, resp);
} else if (!strcmp(command->valuestring, "threads")) {
cmd_threads(args, resp);
} else if (!strcmp(command->valuestring, "scopes")) {
cmd_scopes(args, resp);
} else if (!strcmp(command->valuestring, "variables")) {
cmd_variables(args, resp);
} else if (!strcmp(command->valuestring, "setVariable")) {
cmd_setVariable(args, resp);
} else if (!strcmp(command->valuestring, "disconnect")) {
cmd_disconnect(args, resp);
} else {
WARNING("unknown command \"%s\"", command->valuestring);
}
return continue_repl;
}
static bool handle_message(char *msg)
{
cJSON *json = cJSON_Parse(msg);
cJSON *type = cJSON_GetObjectItemCaseSensitive(json, "type");
bool continue_repl = true;
if (cJSON_IsString(type) && !strcmp(type->valuestring, "request"))
continue_repl = handle_request(json);
cJSON_Delete(json);
free(msg);
return continue_repl;
}
static int read_command_thread(void *data)
{
int content_length = -1;
char header[512];
while (fgets(header, sizeof(header), stdin)) {
if (sscanf(header, "Content-Length: %d", &content_length) == 1) {
continue;
} else if ((header[0] == '\r' && header[1] == '\n') || header[0] == '\n') {
if (content_length < 0) {
WARNING("Debug Adapter Protocol error: no Content-Length header");
continue;
}
char *buf = malloc(content_length);
if (fread(buf, content_length, 1, stdin) != 1) {
WARNING("fread(stdin): %s", strerror(errno));
free(buf);
continue;
}
msgq_enqueue(queue, buf);
content_length = -1;
} else {
WARNING("Unknown Debug Adapter Protocol header: %s", header);
}
}
msgq_enqueue(queue, NULL); // EOF
return 0;
}
void dbg_dap_init(void)
{
queue = msgq_new();
#ifdef _WIN32
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
#endif
SDL_CreateThread(read_command_thread, "Debugger", NULL);
while (dap_state < DAP_RUNNING) {
char *msg = msgq_dequeue(queue);
if (!msg)
break;
handle_message(msg);
}
}
void dbg_dap_quit(void)
{
emit_terminated_event();
}
void dbg_dap_repl(void)
{
emit_stopped_event();
dap_state = DAP_STOPPED;
bool continue_repl = true;
while (continue_repl) {
char *msg = msgq_dequeue(queue);
if (!msg)
break;
continue_repl = handle_message(msg);
}
}
void dbg_dap_handle_messages(void)
{
while (!msgq_isempty(queue)) {
char *msg = msgq_dequeue(queue);
if (!msg)
break;
handle_message(msg);
}
}
void dbg_dap_log(const char *log, const char *fmt, va_list ap)
{
size_t len = max(1024, strlen(fmt) * 2);
char *buf = xmalloc(len);
vsnprintf(buf, len, fmt, ap);
emit_output_event(log, buf);
free(buf);
}
+1 -1
View File
@@ -45,7 +45,7 @@ HLL_WARN_UNIMPLEMENTED( , void, CrayfishLogViewer, SetWindowTitleName,
static bool CrayfishLogViewer_AddText(struct string *text)
{
sys_message("%s", display_sjis0(text->text));
log_message("Crayfish", "%s", display_sjis0(text->text));
return true;
}
+16 -3
View File
@@ -23,12 +23,25 @@
#include "hll.h"
#include "xsystem4.h"
static void OutputLog_Output(int handle, struct string *s)
static struct string **logs = NULL;
static int nr_logs = 0;
int OutputLog_Create(struct string *name)
{
sys_message("%s", display_sjis0(s->text));
logs = xrealloc_array(logs, nr_logs, nr_logs + 1, sizeof(struct string*));
logs[nr_logs++] = string_dup(name);
return nr_logs - 1;
}
static void OutputLog_Output(int handle, struct string *s)
{
if (handle < 0 || handle >= nr_logs) {
log_message("OutputLog", "%s", display_sjis0(s->text));
} else {
log_message(display_sjis0(logs[handle]->text), "%s", display_sjis1(s->text));
}
}
HLL_WARN_UNIMPLEMENTED(0, int, OutputLog, Create, struct string *name);
HLL_WARN_UNIMPLEMENTED( , void, OutputLog, Clear, int handle);
HLL_WARN_UNIMPLEMENTED(0, int, OutputLog, Save, int handle, struct string *filename);
HLL_WARN_UNIMPLEMENTED(0, bool, OutputLog, EnableAutoSave, int handle, struct string *filename);
+2
View File
@@ -544,5 +544,7 @@ void handle_events(void)
break;
}
}
if (dbg_dap)
dbg_dap_handle_messages();
}
+2
View File
@@ -20,6 +20,7 @@ xsystem4 = [version_h,
'heap.c',
'id_pool.c',
'input.c',
'msgqueue.c',
'page.c',
'resume.c',
'savedata.c',
@@ -137,6 +138,7 @@ if get_option('debugger').allowed()
add_project_arguments('-DDEBUGGER_ENABLED', language : 'c')
xsystem4 += 'debug.c'
xsystem4 += 'debugger_cmd.c'
xsystem4 += 'debugger_dap.c'
if chibi.found()
xsystem4_deps += chibi
xsystem4 += 'debugger_scm.c'
+95
View File
@@ -0,0 +1,95 @@
/*
* Copyright (C) 2021 kichikuou <KichikuouChrome@gmail.com>
*
* 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
*
*/
#include <stdlib.h>
#include "msgqueue.h"
struct msgq_elem {
void *msg;
struct msgq_elem *next;
};
struct msgq *msgq_new(void) {
struct msgq *q = calloc(1, sizeof(struct msgq));
q->mutex = SDL_CreateMutex();
q->cond_nonempty = SDL_CreateCond();
return q;
}
void msgq_free(struct msgq *q) {
SDL_DestroyMutex(q->mutex);
SDL_DestroyCond(q->cond_nonempty);
free(q);
}
void msgq_enqueue(struct msgq *q, void *msg) {
struct msgq_elem *e = malloc(sizeof(struct msgq_elem));
e->msg = msg;
e->next = NULL;
SDL_LockMutex(q->mutex);
if (!q->head) {
q->head = q->last = e;
} else {
q->last->next = e;
q->last = e;
}
SDL_UnlockMutex(q->mutex);
SDL_CondSignal(q->cond_nonempty);
}
void *msgq_dequeue(struct msgq *q) {
SDL_LockMutex(q->mutex);
while (!q->head)
SDL_CondWait(q->cond_nonempty, q->mutex);
struct msgq_elem *e = q->head;
q->head = e->next;
if (!e->next)
q->last = NULL;
SDL_UnlockMutex(q->mutex);
void *msg = e->msg;
free(e);
return msg;
}
void *msgq_dequeue_timeout(struct msgq *q, uint32_t timeout_ms) {
SDL_LockMutex(q->mutex);
while (!q->head && SDL_CondWaitTimeout(q->cond_nonempty, q->mutex, timeout_ms) == 0)
;
if (!q->head) { // timed out
SDL_UnlockMutex(q->mutex);
return NULL;
}
struct msgq_elem *e = q->head;
q->head = e->next;
if (!e->next)
q->last = NULL;
SDL_UnlockMutex(q->mutex);
void *msg = e->msg;
free(e);
return msg;
}
+132 -132
View File
@@ -23,64 +23,64 @@
static void parts_cg_print(struct parts_cg *cg, int indent)
{
indent_printf(indent, "cg.no = %d,\n", cg->no);
indent_message(indent, "cg.no = %d,\n", cg->no);
}
static void parts_text_print(struct parts_text *text, int indent)
{
indent_printf(indent, "text.lines = {\n");
indent_message(indent, "text.lines = {\n");
for (unsigned i = 0; i < text->nr_lines; i++) {
struct string *s = parts_text_line_get(&text->lines[i]);
indent_printf(indent+1, "contents = \"%s\",\n", display_sjis0(s->text));
indent_printf(indent+1, "width = %u,\n", text->lines[i].width);
indent_printf(indent+1, "height = %u,\n", text->lines[i].height);
indent_message(indent+1, "contents = \"%s\",\n", display_sjis0(s->text));
indent_message(indent+1, "width = %u,\n", text->lines[i].width);
indent_message(indent+1, "height = %u,\n", text->lines[i].height);
free_string(s);
}
indent_printf(indent, "},\n");
indent_printf(indent, "text.line_space = %u,\n", text->line_space);
indent_printf(indent, "text.cursor = ");
indent_message(indent, "},\n");
indent_message(indent, "text.line_space = %u,\n", text->line_space);
indent_message(indent, "text.cursor = ");
gfx_print_point(&text->cursor);
printf(",\n");
indent_printf(indent, "text.ts = ");
sys_message(",\n");
indent_message(indent, "text.ts = ");
gfx_print_text_style(&text->ts, indent);
printf("\n");
sys_message("\n");
}
static void parts_animation_print(struct parts_animation *anim, int indent)
{
indent_printf(indent, "anim.start_no = %u,\n", anim->start_no);
indent_printf(indent, "anim.frame_time = %u,\n", anim->frame_time);
indent_printf(indent, "anim.elapsed = %u,\n", anim->elapsed);
indent_printf(indent, "anim.current_frame = %u,\n", anim->current_frame);
indent_printf(indent, "anim.frames = {\n");
indent_message(indent, "anim.start_no = %u,\n", anim->start_no);
indent_message(indent, "anim.frame_time = %u,\n", anim->frame_time);
indent_message(indent, "anim.elapsed = %u,\n", anim->elapsed);
indent_message(indent, "anim.current_frame = %u,\n", anim->current_frame);
indent_message(indent, "anim.frames = {\n");
for (unsigned i = 0; i < anim->nr_frames; i++) {
indent_printf(indent+1, "[%u] = ", i);
indent_message(indent+1, "[%u] = ", i);
gfx_print_texture(&anim->frames[i], indent+1);
indent_printf(indent+1, ",\n");
indent_message(indent+1, ",\n");
}
indent_printf(indent, "}\n");
indent_message(indent, "}\n");
}
static void parts_numeral_print(struct parts_numeral *num, int indent)
{
indent_printf(indent, "num.have_num = %s,\n", num->have_num ? "true" : "false");
indent_printf(indent, "num.num = %d,\n", num->num);
indent_printf(indent, "num.space = %d,\n", num->space);
indent_printf(indent, "num.show_comma = %d,\n", num->show_comma);
indent_printf(indent, "num.length = %d,\n", num->length);
indent_printf(indent, "num.cg_no = %d,\n", num->cg_no);
indent_printf(indent, "num.cg = {\n");
indent_message(indent, "num.have_num = %s,\n", num->have_num ? "true" : "false");
indent_message(indent, "num.num = %d,\n", num->num);
indent_message(indent, "num.space = %d,\n", num->space);
indent_message(indent, "num.show_comma = %d,\n", num->show_comma);
indent_message(indent, "num.length = %d,\n", num->length);
indent_message(indent, "num.cg_no = %d,\n", num->cg_no);
indent_message(indent, "num.cg = {\n");
for (int i = 0; i < 12; i++) {
indent_printf(indent+1, "[%d] = ", i);
indent_message(indent+1, "[%d] = ", i);
gfx_print_texture(&num->cg[i], indent+1);
indent_printf(indent+1, ",\n");
indent_message(indent+1, ",\n");
}
indent_printf(indent, "}\n");
indent_message(indent, "}\n");
}
static void parts_gauge_print(struct parts_gauge *gauge, int indent)
{
indent_printf(indent, "gauge.cg = ");
indent_message(indent, "gauge.cg = ");
gfx_print_texture(&gauge->cg, indent);
}
@@ -99,78 +99,78 @@ static void parts_construction_process_print(struct parts_construction_process *
[PARTS_CP_COPY_TEXT] = "PARTS_CP_COPY_TEXT",
};
indent_printf(indent, "cproc.ops = {\n");
indent_message(indent, "cproc.ops = {\n");
indent++;
int i = 0;
struct parts_cp_op *op;
TAILQ_FOREACH(op, &cproc->ops, entry) {
indent_printf(indent, "[%d] = {\n", i++);
indent_message(indent, "[%d] = {\n", i++);
indent++;
const char *type = "INVALID_CONSTRUCTION_PROCERSS_TYPE";
if (op->type >= 0 && op->type < PARTS_NR_CP_TYPES)
type = type_names[op->type];
indent_printf(indent, "type = %s,\n", type);
indent_message(indent, "type = %s,\n", type);
switch (op->type) {
case PARTS_CP_CREATE:
case PARTS_CP_CREATE_PIXEL_ONLY:
indent_printf(indent, "create = {w=%d,h=%d}\n", op->create.w, op->create.h);
indent_message(indent, "create = {w=%d,h=%d}\n", op->create.w, op->create.h);
break;
case PARTS_CP_CG:
indent_printf(indent, "cg.no = %d\n", op->cg.no);
indent_message(indent, "cg.no = %d\n", op->cg.no);
break;
case PARTS_CP_FILL:
case PARTS_CP_FILL_ALPHA_COLOR:
case PARTS_CP_FILL_AMAP:
indent_printf(indent, "fill.rect = {x=%d,y=%d,w=%d,h=%d},\n",
indent_message(indent, "fill.rect = {x=%d,y=%d,w=%d,h=%d},\n",
op->fill.x, op->fill.y, op->fill.w, op->fill.h);
indent_printf(indent, "fill.color = (%d,%d,%d,%d)\n",
indent_message(indent, "fill.color = (%d,%d,%d,%d)\n",
op->fill.r, op->fill.g, op->fill.b, op->fill.a);
break;
case PARTS_CP_DRAW_CUT_CG:
case PARTS_CP_COPY_CUT_CG:
indent_printf(indent, "cut_cg.cg_no = %d,\n", op->cut_cg.cg_no);
indent_printf(indent, "cut_cg.dst = {x=%d,y=%d,w=%d,h=%d},\n",
indent_message(indent, "cut_cg.cg_no = %d,\n", op->cut_cg.cg_no);
indent_message(indent, "cut_cg.dst = {x=%d,y=%d,w=%d,h=%d},\n",
op->cut_cg.dx, op->cut_cg.dy, op->cut_cg.dw, op->cut_cg.dh);
indent_printf(indent, "cut_cg.src = {x=%d,y=%d,w=%d,h=%d},\n",
indent_message(indent, "cut_cg.src = {x=%d,y=%d,w=%d,h=%d},\n",
op->cut_cg.sx, op->cut_cg.sy, op->cut_cg.sw, op->cut_cg.sh);
indent_printf(indent, "cut_cg.interp_type = %d\n", op->cut_cg.interp_type);
indent_message(indent, "cut_cg.interp_type = %d\n", op->cut_cg.interp_type);
break;
case PARTS_CP_DRAW_TEXT:
case PARTS_CP_COPY_TEXT:
indent_printf(indent, "text.text = \"%s\",\n", display_sjis0(op->text.text->text));
indent_printf(indent, "text.pos = {x=%d,y=%d},\n", op->text.x, op->text.y);
indent_printf(indent, "text.line_space = %d,\n", op->text.line_space);
indent_printf(indent, "text.style = ");
indent_message(indent, "text.text = \"%s\",\n", display_sjis0(op->text.text->text));
indent_message(indent, "text.pos = {x=%d,y=%d},\n", op->text.x, op->text.y);
indent_message(indent, "text.line_space = %d,\n", op->text.line_space);
indent_message(indent, "text.style = ");
gfx_print_text_style(&op->text.style, indent);
printf("\n");
sys_message("\n");
break;
}
indent--;
indent_printf(indent, "},\n");
indent_message(indent, "},\n");
}
indent--;
indent_printf(indent, "}\n");
indent_message(indent, "}\n");
}
static void parts_print_state(struct parts_state *state, int indent)
{
if (state->type == PARTS_UNINITIALIZED) {
printf("UNINITIALIZED");
sys_message("UNINITIALIZED");
return;
}
printf("{\n");
sys_message("{\n");
indent++;
struct parts_common *com = &state->common;
indent_printf(indent, "dims = {w=%d,h=%d},\n", state->common.w, state->common.h);
indent_printf(indent, "origin_offset = "); gfx_print_point(&com->origin_offset); printf(",\n");
indent_printf(indent, "hitbox = "); gfx_print_rectangle(&com->hitbox); printf(",\n");
indent_printf(indent, "surface_area = "); gfx_print_rectangle(&com->surface_area); printf(",\n");
indent_message(indent, "dims = {w=%d,h=%d},\n", state->common.w, state->common.h);
indent_message(indent, "origin_offset = "); gfx_print_point(&com->origin_offset); sys_message(",\n");
indent_message(indent, "hitbox = "); gfx_print_rectangle(&com->hitbox); sys_message(",\n");
indent_message(indent, "surface_area = "); gfx_print_rectangle(&com->surface_area); sys_message(",\n");
switch (state->type) {
case PARTS_UNINITIALIZED:
break;
@@ -196,22 +196,22 @@ static void parts_print_state(struct parts_state *state, int indent)
}
indent--;
indent_printf(indent, "}");
indent_message(indent, "}");
}
static void parts_print_motion_param(union parts_motion_param param, enum parts_motion_type type)
{
switch (type) {
case PARTS_MOTION_POS:
printf("{x=%d,y=%d}", param.x, param.y);
sys_message("{x=%d,y=%d}", param.x, param.y);
break;
case PARTS_MOTION_VIBRATION_SIZE:
printf("{w=%d,h=%d}", param.x, param.y);
sys_message("{w=%d,h=%d}", param.x, param.y);
break;
case PARTS_MOTION_ALPHA:
case PARTS_MOTION_CG:
case PARTS_MOTION_NUMERAL_NUMBER:
printf("%d", param.i);
sys_message("%d", param.i);
break;
case PARTS_MOTION_HGAUGE_RATE:
case PARTS_MOTION_VGAUGE_RATE:
@@ -220,7 +220,7 @@ static void parts_print_motion_param(union parts_motion_param param, enum parts_
case PARTS_MOTION_ROTATE_X:
case PARTS_MOTION_ROTATE_Y:
case PARTS_MOTION_ROTATE_Z:
printf("%f", param.f);
sys_message("%f", param.f);
break;
}
}
@@ -246,55 +246,55 @@ static void parts_print_motion(struct parts_motion *motion, int indent)
if (motion->type >= 0 && motion->type < PARTS_NR_MOTION_TYPES)
type = type_names[motion->type];
printf("{\n");
sys_message("{\n");
indent++;
indent_printf(indent, "type = %s,\n", type);
indent_printf(indent, "begin = ");
indent_message(indent, "type = %s,\n", type);
indent_message(indent, "begin = ");
parts_print_motion_param(motion->begin, motion->type);
printf(",\n");
indent_printf(indent, "end = ");
sys_message(",\n");
indent_message(indent, "end = ");
parts_print_motion_param(motion->end, motion->type);
printf(",\n");
indent_printf(indent, "begin_time = %d,\n", motion->begin_time);
indent_printf(indent, "end_time = %d,\n", motion->end_time);
sys_message(",\n");
indent_message(indent, "begin_time = %d,\n", motion->begin_time);
indent_message(indent, "end_time = %d,\n", motion->end_time);
indent--;
indent_printf(indent, "}");
indent_message(indent, "}");
}
static void parts_print_params(struct parts_params *global, struct parts_params *local, int indent)
{
printf("{\n");
sys_message("{\n");
indent++;
indent_printf(indent, "z = %d (%d),\n", global->z, local->z);
indent_printf(indent, "pos = ");
indent_message(indent, "z = %d (%d),\n", global->z, local->z);
indent_message(indent, "pos = ");
gfx_print_point(&global->pos);
printf(" (");
sys_message(" (");
gfx_print_point(&local->pos);
printf("),\n");
indent_printf(indent, "show = %s (%s),\n", global->show ? "true" : "false",
sys_message("),\n");
indent_message(indent, "show = %s (%s),\n", global->show ? "true" : "false",
local->show ? "true" : "false");
indent_printf(indent, "alpha = %u (%u),\n", (unsigned)global->alpha, (unsigned)local->alpha);
indent_printf(indent, "scale = {x=%f,y=%f} ({x=%f,y=%f}),\n", global->scale.x, global->scale.y,
indent_message(indent, "alpha = %u (%u),\n", (unsigned)global->alpha, (unsigned)local->alpha);
indent_message(indent, "scale = {x=%f,y=%f} ({x=%f,y=%f}),\n", global->scale.x, global->scale.y,
local->scale.x, local->scale.y);
indent_printf(indent, "rotation = {x=%f,y=%f,z=%f} ({x=%f,y=%f,z=%f}),\n",
indent_message(indent, "rotation = {x=%f,y=%f,z=%f} ({x=%f,y=%f,z=%f}),\n",
global->rotation.x, global->rotation.y, global->rotation.z,
local->rotation.x, local->rotation.y, local->rotation.z);
indent_printf(indent, "add_color = ");
indent_message(indent, "add_color = ");
gfx_print_color(&global->add_color);
printf(" (");
sys_message(" (");
gfx_print_color(&local->add_color);
printf("),\n");
indent_printf(indent, "multiply_color = ");
sys_message("),\n");
indent_message(indent, "multiply_color = ");
gfx_print_color(&global->multiply_color);
printf(" (");
sys_message(" (");
gfx_print_color(&local->multiply_color);
printf("),\n");
sys_message("),\n");
indent--;
indent_printf(indent, "}");
indent_message(indent, "}");
}
static void _parts_print(struct parts *parts, int indent)
@@ -308,71 +308,71 @@ static void _parts_print(struct parts *parts, int indent)
if (parts->state >= 0 && parts->state < PARTS_NR_STATES)
state = state_names[parts->state];
indent_printf(indent, "parts %d = {\n", parts->no);
indent_message(indent, "parts %d = {\n", parts->no);
indent++;
// print states
indent_printf(indent, "state = %s,\n", state);
indent_message(indent, "state = %s,\n", state);
for (int i = 0; i < PARTS_NR_STATES; i++) {
if (parts->states[i].type == PARTS_UNINITIALIZED && i != parts->state)
continue;
indent_printf(indent, "state[%s] = ", state_names[i]);
indent_message(indent, "state[%s] = ", state_names[i]);
parts_print_state(&parts->states[i], indent);
printf(",\n");
sys_message(",\n");
}
// print params
indent_printf(indent, "local = ");
indent_message(indent, "local = ");
parts_print_params(&parts->global, &parts->local, indent);
printf(",\n");
sys_message(",\n");
// print misc. data
if (parts->delegate_index >= 0)
indent_printf(indent, "delegate_index = %d,\n", parts->delegate_index);
indent_printf(indent, "sprite_deform = %d,\n", parts->sprite_deform);
indent_printf(indent, "clickable = %s,\n", parts->clickable ? "true" : "false");
indent_message(indent, "delegate_index = %d,\n", parts->delegate_index);
indent_message(indent, "sprite_deform = %d,\n", parts->sprite_deform);
indent_message(indent, "clickable = %s,\n", parts->clickable ? "true" : "false");
if (parts->on_cursor_sound >= 0)
indent_printf(indent, "on_cursor_sound = %d,\n", parts->on_cursor_sound);
indent_message(indent, "on_cursor_sound = %d,\n", parts->on_cursor_sound);
if (parts->on_click_sound >= 0)
indent_printf(indent, "on_click_sound = %d,\n", parts->on_click_sound);
indent_printf(indent, "origin_mode = %d,\n", parts->origin_mode);
indent_printf(indent, "parent = %d,\n", parts->parent ? parts->parent->no : -1);
indent_message(indent, "on_click_sound = %d,\n", parts->on_click_sound);
indent_message(indent, "origin_mode = %d,\n", parts->origin_mode);
indent_message(indent, "parent = %d,\n", parts->parent ? parts->parent->no : -1);
if (parts->linked_to >= 0)
indent_printf(indent, "linked_to = %d,\n", parts->linked_to);
indent_message(indent, "linked_to = %d,\n", parts->linked_to);
if (parts->linked_from >= 0)
indent_printf(indent, "linked_from = %d,\n", parts->linked_from);
indent_printf(indent, "draw_filter = %d,\n", parts->draw_filter);
indent_message(indent, "linked_from = %d,\n", parts->linked_from);
indent_message(indent, "draw_filter = %d,\n", parts->draw_filter);
// print motion data
if (TAILQ_EMPTY(&parts->motion)) {
indent_printf(indent, "motion = {},\n");
indent_message(indent, "motion = {},\n");
} else {
indent_printf(indent, "motion = {\n");
indent_message(indent, "motion = {\n");
int i = 0;
struct parts_motion *motion;
TAILQ_FOREACH(motion, &parts->motion, entry) {
indent_printf(indent+1, "[%d] = ", i++);
indent_message(indent+1, "[%d] = ", i++);
parts_print_motion(motion, indent+1);
printf(",\n");
sys_message(",\n");
}
indent_printf(indent, "},\n");
indent_message(indent, "},\n");
}
// print children
if (TAILQ_EMPTY(&parts->children)) {
} else {
indent_printf(indent, "children = {\n");
indent_message(indent, "children = {\n");
struct parts *child;
PARTS_FOREACH_CHILD(child, parts) {
_parts_print(child, indent+1);
printf(",\n");
sys_message(",\n");
}
indent_printf(indent, "},\n");
indent_message(indent, "},\n");
}
indent--;
indent_printf(indent, "}");
indent_message(indent, "}");
}
void parts_print(struct parts *parts)
@@ -413,77 +413,77 @@ static void parts_cmd_parts(unsigned nr_args, char **args)
static void parts_list_print(struct parts *parts, int indent)
{
indent_printf(indent, parts->local.show ? "+ " : "- ");
printf("parts %d ", parts->no);
indent_message(indent, parts->local.show ? "+ " : "- ");
sys_message("parts %d ", parts->no);
struct parts_state *state = &parts->states[parts->state];
switch (state->type) {
case PARTS_UNINITIALIZED:
printf("(uninitialized)");
sys_message("(uninitialized)");
break;
case PARTS_CG:
if (state->cg.name)
printf("(cg %s)", display_sjis0(state->cg.name->text));
sys_message("(cg %s)", display_sjis0(state->cg.name->text));
else
printf("(cg %d)", state->cg.no);
sys_message("(cg %d)", state->cg.no);
break;
case PARTS_TEXT:
printf("(text)"); // TODO? store actual text and print it here
sys_message("(text)"); // TODO? store actual text and print it here
break;
case PARTS_ANIMATION:
printf("(animation %d+%d)", state->anim.start_no, state->anim.nr_frames);
sys_message("(animation %d+%d)", state->anim.start_no, state->anim.nr_frames);
break;
case PARTS_NUMERAL:
printf("(numeral %d)", state->num.cg_no);
sys_message("(numeral %d)", state->num.cg_no);
break;
case PARTS_HGAUGE:
printf("(hgauge)"); // TODO? store rate and cg and print them here
sys_message("(hgauge)"); // TODO? store rate and cg and print them here
break;
case PARTS_VGAUGE:
printf("(vgauge)");
sys_message("(vgauge)");
break;
case PARTS_CONSTRUCTION_PROCESS: {
printf("(construction process:");
sys_message("(construction process:");
struct parts_cp_op *op;
TAILQ_FOREACH(op, &state->cproc.ops, entry) {
switch (op->type) {
case PARTS_CP_CREATE:
printf(" create");
sys_message(" create");
break;
case PARTS_CP_CREATE_PIXEL_ONLY:
printf(" create-pixel-only");
sys_message(" create-pixel-only");
break;
case PARTS_CP_CG:
printf(" cg");
sys_message(" cg");
break;
case PARTS_CP_FILL:
printf(" fill");
sys_message(" fill");
break;
case PARTS_CP_FILL_ALPHA_COLOR:
printf(" fill-alpha-color");
sys_message(" fill-alpha-color");
break;
case PARTS_CP_FILL_AMAP:
printf(" fill-amap");
sys_message(" fill-amap");
break;
case PARTS_CP_DRAW_CUT_CG:
printf(" draw-cut-cg");
sys_message(" draw-cut-cg");
break;
case PARTS_CP_COPY_CUT_CG:
printf(" copy-cut-cg");
sys_message(" copy-cut-cg");
break;
case PARTS_CP_DRAW_TEXT:
printf(" draw-text");
sys_message(" draw-text");
break;
case PARTS_CP_COPY_TEXT:
printf(" copy-text");
sys_message(" copy-text");
break;
}
}
printf(")");
sys_message(")");
break;
}
}
printf(" @ z=%d (%d)\n", parts->global.z, parts->local.z);
sys_message(" @ z=%d (%d)\n", parts->global.z, parts->local.z);
struct parts *child;
PARTS_FOREACH_CHILD(child, parts) {
+8 -8
View File
@@ -139,15 +139,15 @@ void scene_set_sprite_z2(struct sprite *sp, int z, int z2)
void scene_print_sprite(struct sprite *sp, int indent)
{
printf("{\n");
sys_message("{\n");
indent++;
indent_printf(indent, "z = (%d,%d),\n", sp->z, sp->z2);
indent_printf(indent, "has_pixel = %s,\n", sp->has_pixel ? "true" : "false");
indent_printf(indent, "has_alpha = %s,\n", sp->has_alpha ? "true" : "false");
indent_printf(indent, "hidden = %s,\n", sp->hidden ? "true" : "false");
indent_printf(indent, "in_scene = %s,\n", sp->in_scene ? "true" : "false");
indent_message(indent, "z = (%d,%d),\n", sp->z, sp->z2);
indent_message(indent, "has_pixel = %s,\n", sp->has_pixel ? "true" : "false");
indent_message(indent, "has_alpha = %s,\n", sp->has_alpha ? "true" : "false");
indent_message(indent, "hidden = %s,\n", sp->hidden ? "true" : "false");
indent_message(indent, "in_scene = %s,\n", sp->in_scene ? "true" : "false");
indent--;
printf("}");
sys_message("}");
}
@@ -158,7 +158,7 @@ void scene_print(void)
if (p->debug_print) {
p->debug_print(p);
} else {
printf("unknown_scene_entity ");
sys_message("unknown_scene_entity ");
scene_print_sprite(p, 0);
putchar('\n');
}
+39 -39
View File
@@ -468,79 +468,79 @@ void sprite_call_plugins(void)
void gfx_print_color(SDL_Color *c)
{
printf("(%d,%d,%d,%d)", c->r, c->g, c->b, c->a);
sys_message("(%d,%d,%d,%d)", c->r, c->g, c->b, c->a);
}
void gfx_print_rectangle(Rectangle *r)
{
printf("{x=%d,y=%d,w=%d,h=%d}", r->x, r->y, r->w, r->h);
sys_message("{x=%d,y=%d,w=%d,h=%d}", r->x, r->y, r->w, r->h);
}
void gfx_print_point(Point *p)
{
printf("{x=%d,y=%d}", p->x, p->y);
sys_message("{x=%d,y=%d}", p->x, p->y);
}
void gfx_print_texture(struct texture *t, int indent)
{
printf("{\n");
indent_printf(indent+1, "initialized = %s,\n", t->handle ? "true" : "false");
indent_printf(indent+1, "size = (%d,%d),\n", t->w, t->h);
indent_printf(indent+1, "has_alpha = %s,\n", t->has_alpha ? "true" : "false");
indent_printf(indent, "}");
sys_message("{\n");
indent_message(indent+1, "initialized = %s,\n", t->handle ? "true" : "false");
indent_message(indent+1, "size = (%d,%d),\n", t->w, t->h);
indent_message(indent+1, "has_alpha = %s,\n", t->has_alpha ? "true" : "false");
indent_message(indent, "}");
}
void sprite_print(struct sact_sprite *sp)
{
int indent = 0;
indent_printf(indent, "sprite %d = {\n", sp->no);
indent_message(indent, "sprite %d = {\n", sp->no);
indent++;
indent_printf(indent, "sp = {\n");
indent_message(indent, "sp = {\n");
indent++;
indent_printf(indent, "z = (%d,%d),\n", sp->sp.z, sp->sp.z2);
indent_printf(indent, "has_pixel = %s,\n", sp->sp.has_pixel ? "true" : "false");
indent_printf(indent, "has_alpha = %s,\n", sp->sp.has_alpha ? "true" : "false");
indent_printf(indent, "hidden = %s,\n", sp->sp.hidden ? "true" : "false");
indent_printf(indent, "in_scene = %s,\n", sp->sp.in_scene ? "true" : "false");
indent_message(indent, "z = (%d,%d),\n", sp->sp.z, sp->sp.z2);
indent_message(indent, "has_pixel = %s,\n", sp->sp.has_pixel ? "true" : "false");
indent_message(indent, "has_alpha = %s,\n", sp->sp.has_alpha ? "true" : "false");
indent_message(indent, "hidden = %s,\n", sp->sp.hidden ? "true" : "false");
indent_message(indent, "in_scene = %s,\n", sp->sp.in_scene ? "true" : "false");
indent--;
indent_printf(indent, "},\n");
indent_message(indent, "},\n");
indent_printf(indent, "texture = "); gfx_print_texture(&sp->texture, 1); printf(",\n");
indent_printf(indent, "color = "); gfx_print_color(&sp->color); printf(",\n");
indent_printf(indent, "blend_rate = %d,\n", sp->blend_rate);
indent_printf(indent, "multiply_color = "); gfx_print_color(&sp->multiply_color); printf(",\n");
indent_printf(indent, "add_color = "); gfx_print_color(&sp->add_color); printf(",\n");
indent_message(indent, "texture = "); gfx_print_texture(&sp->texture, 1); sys_message(",\n");
indent_message(indent, "color = "); gfx_print_color(&sp->color); sys_message(",\n");
indent_message(indent, "blend_rate = %d,\n", sp->blend_rate);
indent_message(indent, "multiply_color = "); gfx_print_color(&sp->multiply_color); sys_message(",\n");
indent_message(indent, "add_color = "); gfx_print_color(&sp->add_color); sys_message(",\n");
switch (sp->draw_method) {
case DRAW_METHOD_NORMAL: indent_printf(indent, "draw_method = normal,\n"); break;
case DRAW_METHOD_SCREEN: indent_printf(indent, "draw_method = screen,\n"); break;
case DRAW_METHOD_MULTIPLY: indent_printf(indent, "draw_method = multiply,\n"); break;
case DRAW_METHOD_ADDITIVE: indent_printf(indent, "draw_method = additive,\n"); break;
default: indent_printf(indent, "draw_method = unknown,\n"); break;
case DRAW_METHOD_NORMAL: indent_message(indent, "draw_method = normal,\n"); break;
case DRAW_METHOD_SCREEN: indent_message(indent, "draw_method = screen,\n"); break;
case DRAW_METHOD_MULTIPLY: indent_message(indent, "draw_method = multiply,\n"); break;
case DRAW_METHOD_ADDITIVE: indent_message(indent, "draw_method = additive,\n"); break;
default: indent_message(indent, "draw_method = unknown,\n"); break;
}
indent_printf(indent, "rect = "); gfx_print_rectangle(&sp->rect); printf(",\n");
indent_message(indent, "rect = "); gfx_print_rectangle(&sp->rect); sys_message(",\n");
indent_printf(indent, "text = {\n");
indent_message(indent, "text = {\n");
indent++;
indent_printf(indent, "texture = "); gfx_print_texture(&sp->text.texture, 2); printf(",\n");
indent_printf(indent, "home = "); gfx_print_point(&sp->text.home); printf(",\n");
indent_printf(indent, "pos = "); gfx_print_point(&sp->text.pos); printf(",\n");
indent_printf(indent, "char_space = %d,\n", sp->text.char_space);
indent_printf(indent, "line_space = %d,\n", sp->text.line_space);
indent_message(indent, "texture = "); gfx_print_texture(&sp->text.texture, 2); sys_message(",\n");
indent_message(indent, "home = "); gfx_print_point(&sp->text.home); sys_message(",\n");
indent_message(indent, "pos = "); gfx_print_point(&sp->text.pos); sys_message(",\n");
indent_message(indent, "char_space = %d,\n", sp->text.char_space);
indent_message(indent, "line_space = %d,\n", sp->text.line_space);
if (sp->plugin) {
if (sp->plugin->debug_print) {
indent_printf(indent, "plugin = {\n");
indent_message(indent, "plugin = {\n");
sp->plugin->debug_print(sp, indent + 1);
indent_printf(indent, "},\n");
indent_message(indent, "},\n");
} else {
indent_printf(indent, "plugin = %s,\n", sp->plugin->name);
indent_message(indent, "plugin = %s,\n", sp->plugin->name);
}
}
indent--;
indent_printf(indent, "},\n");
indent_message(indent, "},\n");
indent_printf(indent, "cg_no = %d\n", sp->cg_no);
indent_message(indent, "cg_no = %d\n", sp->cg_no);
indent--;
indent_printf(indent, "}\n");
indent_message(indent, "}\n");
}
+6 -7
View File
@@ -376,6 +376,7 @@ enum {
#ifdef DEBUGGER_ENABLED
LOPT_NODEBUG,
LOPT_DEBUG,
LOPT_DEBUG_API,
#endif
};
@@ -420,6 +421,7 @@ int main(int argc, char *argv[])
#ifdef DEBUGGER_ENABLED
{ "nodebug", no_argument, 0, LOPT_NODEBUG },
{ "debug", no_argument, 0, LOPT_DEBUG },
{ "debug-api", no_argument, 0, LOPT_DEBUG_API },
#endif
{ 0 }
};
@@ -477,6 +479,10 @@ int main(int argc, char *argv[])
case LOPT_DEBUG:
dbg_start_in_debugger = true;
break;
case LOPT_DEBUG_API:
dbg_dap = true;
sys_silent = true;
break;
#endif
}
}
@@ -536,14 +542,7 @@ int main(int argc, char *argv[])
}
apply_game_specific_hacks(ain);
asset_manager_init();
#ifdef DEBUGGER_ENABLED
dbg_init();
if (dbg_start_in_debugger)
dbg_repl();
#endif
sys_exit(vm_execute_ain(ain));
}
+12 -12
View File
@@ -455,21 +455,21 @@ void gfx_set_font_name(const char *name)
void gfx_print_text_style(struct text_style *style, int indent)
{
printf("{\n");
sys_message("{\n");
indent++;
indent_printf(indent, "face = %u,\n", style->face);
indent_printf(indent, "size = %f,\n", style->size);
indent_printf(indent, "bold_width = %f,\n", style->bold_width);
indent_printf(indent, "weight = %u,\n", style->weight);
indent_printf(indent, "edge_weight = {l=%f,u=%f,r=%f,d=%f},\n",
indent_message(indent, "face = %u,\n", style->face);
indent_message(indent, "size = %f,\n", style->size);
indent_message(indent, "bold_width = %f,\n", style->bold_width);
indent_message(indent, "weight = %u,\n", style->weight);
indent_message(indent, "edge_weight = {l=%f,u=%f,r=%f,d=%f},\n",
style->edge_left, style->edge_up, style->edge_right, style->edge_down);
indent_printf(indent, "color = "); gfx_print_color(&style->color); printf(",\n");
indent_printf(indent, "edge_color = "); gfx_print_color(&style->edge_color); printf(",\n");
indent_printf(indent, "scale_x = %f,\n", style->scale_x);
indent_printf(indent, "space_scale_x = %f,\n", style->space_scale_x);
indent_printf(indent, "font_spacing = %f,\n", style->font_spacing);
indent_message(indent, "color = "); gfx_print_color(&style->color); sys_message(",\n");
indent_message(indent, "edge_color = "); gfx_print_color(&style->edge_color); sys_message(",\n");
indent_message(indent, "scale_x = %f,\n", style->scale_x);
indent_message(indent, "space_scale_x = %f,\n", style->space_scale_x);
indent_message(indent, "font_spacing = %f,\n", style->font_spacing);
indent--;
indent_printf(indent, "}");
indent_message(indent, "}");
}
+15 -2
View File
@@ -18,6 +18,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <ctype.h>
@@ -25,6 +26,7 @@
#include "system4/utfsjis.h"
#include "xsystem4.h"
#include "debugger.h"
// In a Windows environment, console output should be SJIS-encoded
// (assuming the user is using Japanese non-unicode locale).
@@ -173,13 +175,24 @@ void get_time(int *hour, int *min, int *sec, int *ms)
*ms = ts.tv_nsec / 1000000;
}
void indent_printf(int indent, const char *fmt, ...)
void indent_message(int indent, const char *fmt, ...)
{
for (int i = 0; i < indent; i++)
putchar('\t');
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
sys_vmessage(fmt, ap);
va_end(ap);
}
void log_message(const char *log, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (dbg_dap)
dbg_dap_log(log, fmt, ap);
else
sys_vmessage(fmt, ap);
va_end(ap);
}
+1 -3
View File
@@ -482,7 +482,7 @@ static void system_call(enum syscall_code code)
}
case SYS_OUTPUT: {// system.Output(string szText)
struct string *str = stack_peek_string(0);
sys_message("%s", display_sjis0(str->text));
log_message("stdout", "%s", display_sjis0(str->text));
// XXX: caller S_POPs
break;
}
@@ -2380,9 +2380,7 @@ _Noreturn void _vm_error(const char *fmt, ...)
va_end(ap);
sys_warning("at %s (0x%X) in:\n", current_instruction_name(), instr_ptr);
vm_stack_trace();
#ifdef DEBUGGER_ENABLED
dbg_repl();
#endif
sys_exit(1);
}