1
0
mirror of https://github.com/pevans/erc-c.git synced 2024-11-27 20:51:17 +00:00

Add resume command, finder function, arg parser, execute

This commit is contained in:
Peter Evans 2018-02-24 16:30:46 -06:00
parent a614c1e5df
commit ec253905ad
3 changed files with 217 additions and 19 deletions

View File

@ -1,24 +1,8 @@
#ifndef _VM_DEBUG_H_
#define _VM_DEBUG_H_
typedef struct {
/*
* Most commands that need an argument will simply use addr1, but a
* few have more than one address--hence addr2.
*/
int addr1;
int addr2;
/*
* If we have a thing we want to work with, but want to leave what
* that is up to the helper func, then you can write it into the
* target.
*
* If a command uses target, followed by an address, that address
* will be in addr1.
*/
char target[256];
} vm_debug_args;
struct vm_debug_args;
typedef struct vm_debug_args vm_debug_args;
typedef void (*vm_debug_func)(vm_debug_args *);
@ -52,9 +36,38 @@ typedef struct {
char *desc;
} vm_debug_cmd;
struct vm_debug_args {
/*
* Most commands that need an argument will simply use addr1, but a
* few have more than one address--hence addr2.
*/
int addr1;
int addr2;
/*
* If we have a thing we want to work with, but want to leave what
* that is up to the helper func, then you can write it into the
* target.
*
* If a command uses target, followed by an address, that address
* will be in addr1.
*/
char *target;
/*
* The command our arguments are attached to; from here we can call
* the handler with ourselves. (Very meta.)
*/
vm_debug_cmd *cmd;
};
#define DEBUG_CMD(x) \
void vm_debug_cmd_##x (vm_debug_args *args)
extern vm_debug_cmd *vm_debug_find_cmd(const char *);
extern void vm_debug_execute(const char *);
extern DEBUG_CMD(help);
extern DEBUG_CMD(resume);
#endif

View File

@ -2,18 +2,149 @@
* vm_debug.c
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include "vm_debug.h"
#include "vm_di.h"
#include "vm_reflect.h"
vm_debug_cmd cmdtable[] = {
{ "help", "h", 0, vm_debug_cmd_help, "",
"Print out this list of commands", },
{ "resume", "r", 0, vm_debug_cmd_resume, "",
"Resume execution", },
};
#define CMDTABLE_SIZE (sizeof(cmdtable) / sizeof(vm_debug_cmd))
char *
vm_debug_next_arg(char **str)
{
char *tok;
while ((tok = strsep(str, " "))) {
if (tok == NULL) {
return NULL;
}
if (*tok == '\0') {
continue;
}
break;
}
return tok;
}
int
vm_debug_addr(const char *str)
{
int addr;
if (str == NULL) {
return -1;
}
addr = strtol(str, NULL, 16);
if (addr == 0 && errno == EINVAL) {
return -1;
}
return addr;
}
void
vm_debug_execute(const char *str)
{
char *tok, *ebuf;
vm_debug_cmd *cmd;
vm_debug_args args;
ebuf = strdup(str);
cmd = NULL;
tok = vm_debug_next_arg(&ebuf);
// No input
if (tok == NULL) {
return;
}
cmd = vm_debug_find_cmd(tok);
// No command found
if (cmd == NULL) {
return;
}
args.addr1 = 0;
args.addr2 = 0;
args.target = NULL;
switch (cmd->nargs) {
case 2:
args.target = vm_debug_next_arg(&ebuf);
// This _may_ be -1 if we have a string target for argument
// 1, as in the writestate command
args.addr1 = vm_debug_addr(args.target);
args.addr2 = vm_debug_addr(vm_debug_next_arg(&ebuf));
// But if this is -1, then something went wrong
if (args.addr2 == -1) {
return;
}
break;
case 1:
args.addr1 = vm_debug_addr(vm_debug_next_arg(&ebuf));
// Oh no
if (args.addr1 == -1) {
return;
}
break;
case 0:
default:
break;
}
cmd->handler(&args);
}
static int
cmd_compar(const void *k, const void *elem)
{
const char *key = (const char *)k;
const vm_debug_cmd *cmd = (const vm_debug_cmd *)elem;
if (strlen(key) < 3) {
return strcmp(key, cmd->abbrev);
}
return strcmp(key, cmd->name);
}
/*
* Return the cmd struct for a command that matches str, which can
* either be an abbreviation (if 1 or 2 characters) or a full name (if
* otherwise). If no matching cmd can be found, return NULL.
*/
vm_debug_cmd *
vm_debug_find_cmd(const char *str)
{
return (vm_debug_cmd *)bsearch(str, &cmdtable, CMDTABLE_SIZE,
sizeof(vm_debug_cmd), cmd_compar);
}
DEBUG_CMD(help)
{
FILE *stream = (FILE *)vm_di_get(VM_OUTPUT);
@ -25,3 +156,8 @@ DEBUG_CMD(help)
cmd->argdesc, cmd->desc);
}
}
DEBUG_CMD(resume)
{
vm_reflect_pause(NULL);
}

View File

@ -2,13 +2,20 @@
#include <stdio.h>
#include <stdlib.h>
#include "apple2.h"
#include "apple2.reflect.h"
#include "vm_debug.h"
#include "vm_di.h"
#include "vm_reflect.h"
static char buf[BUFSIZ];
static FILE *stream = NULL;
static vm_debug_args args;
static apple2 *mach;
static vm_reflect *ref;
static void
setup()
{
@ -24,6 +31,15 @@ setup()
// Writing to stream will now write to buf
setvbuf(stream, buf, _IOFBF, BUFSIZ);
ref = vm_reflect_create();
vm_di_set(VM_REFLECT, ref);
mach = apple2_create(100, 100);
vm_di_set(VM_MACHINE, mach);
vm_di_set(VM_CPU, mach->cpu);
apple2_reflect_init();
}
static void
@ -31,6 +47,8 @@ teardown()
{
memset(buf, 0, BUFSIZ);
fclose(stream);
apple2_free(mach);
}
TestSuite(vm_debug, .init = setup, .fini = teardown);
@ -43,5 +61,36 @@ Test(vm_debug, cmd_help)
{
vm_debug_cmd_help(&args);
cr_assert_neq(strlen(buf), 0);
printf("%s", buf);
}
Test(vm_debug, execute)
{
vm_debug_execute("help");
cr_assert_neq(strlen(buf), 0);
}
Test(vm_debug, find_cmd)
{
vm_debug_cmd *cmd;
// Can we find anything?
cr_assert_neq(vm_debug_find_cmd("resume"), NULL);
// Make sure NULL is returned for bad commands
cr_assert_eq(vm_debug_find_cmd("THIS_DOESNT_EXIST"), NULL);
// Find a second command...
cmd = vm_debug_find_cmd("help");
cr_assert_neq(cmd, NULL);
// and see if we can find the short version
cr_assert_eq(vm_debug_find_cmd("h"), cmd);
}
Test(vm_debug, cmd_resume)
{
mach->paused = true;
vm_debug_cmd_resume(&args);
cr_assert_eq(mach->paused, false);
}