mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-03 20:38:13 +03:00
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:
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -544,5 +544,7 @@ void handle_events(void)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dbg_dap)
|
||||
dbg_dap_handle_messages();
|
||||
}
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
Submodule subprojects/libsys4 updated: 22fdbf0b4b...05b4cec8a6
Reference in New Issue
Block a user