Browse Source

Make assembler output file optional; sanity checks; bugfixes.

master
Ben Kurtovic 9 years ago
parent
commit
5d426648bd
5 changed files with 69 additions and 13 deletions
  1. +6
    -3
      README.md
  2. +1
    -1
      crater.c
  3. +57
    -9
      src/config.c
  4. +1
    -0
      src/config.h
  5. +4
    -0
      src/rom.c

+ 6
- 3
README.md View File

@@ -52,6 +52,9 @@ detailed information about emulation state while running, including register
values and memory contents. You can also pause emulation to set breakpoints and values and memory contents. You can also pause emulation to set breakpoints and
change state. change state.


`--assemble <input> <output>` (`-a`) converts z80 assembly source code into a
`.gg` binary that can be run by crater. `--disassemble <input> <output>` (`-d`)
executes the opposite operation.
`--assemble <input> [<output>]` (`-a`) converts z80 assembly source code into a
`.gg` binary that can be run by crater. `--disassemble <input> [<output>]`
(`-d`) executes the opposite operation. If no output file is given, crater will
use the name of the input file, with the extension replaced with `.gg` for `-a`
and `.s` for `-d`. By default, this will never overwrite the original filename;
pass `--overwrite` (`-r`) to let crater do so.

+ 1
- 1
crater.c View File

@@ -24,7 +24,7 @@ int main(int argc, char *argv[])
#endif #endif


if (config->assemble) { if (config->assemble) {
printf("Running assembler: %s -> %s.\n",config->src_path, config->dst_path);
printf("Running assembler: %s -> %s.\n", config->src_path, config->dst_path);
} else if (config->disassemble) { } else if (config->disassemble) {
printf("Running disassembler: %s -> %s.\n", config->src_path, config->dst_path); printf("Running disassembler: %s -> %s.\n", config->src_path, config->dst_path);
} else { } else {


+ 57
- 9
src/config.c View File

@@ -34,9 +34,12 @@ static void print_help(const char *arg1)
" -g, --debug display information about emulation state while running,\n" " -g, --debug display information about emulation state while running,\n"
" including register and memory values; can also pause\n" " including register and memory values; can also pause\n"
" emulation, set breakpoints, and change state\n" " emulation, set breakpoints, and change state\n"
" -a, --assemble <in> <out> convert z80 assembly source code into a\n"
" binary file that can be run by crater\n"
" -d, --disassemble <in> <out> convert a binary file into z80 assembly code\n",
" -a, --assemble <in> [<out>] convert z80 assembly source code into a\n"
" binary file that can be run by crater\n"
" -d, --disassemble <in> [<out>] convert a binary file into z80 assembly\n"
" source code\n"
" -r, --overwrite allow crater to write assembler output to the same\n"
" filename as the input\n",
arg1); arg1);
} }


@@ -160,6 +163,8 @@ static int parse_args(Config *config, int argc, char *argv[])
} }


path = malloc(sizeof(char) * (strlen(arg) + 1)); path = malloc(sizeof(char) * (strlen(arg) + 1));
if (!path)
OUT_OF_MEMORY()
strcpy(path, arg); strcpy(path, arg);


if (paths_read == 1) { if (paths_read == 1) {
@@ -220,6 +225,8 @@ static int parse_args(Config *config, int argc, char *argv[])
config->rom_path = NULL; config->rom_path = NULL;
} }
config->disassemble = true; config->disassemble = true;
} else if (!strcmp(arg, "r") || !strcmp(arg, "overwrite")) {
config->overwrite = true;
} else { } else {
ERROR("unknown argument: %s", argv[i]) ERROR("unknown argument: %s", argv[i])
return CONFIG_EXIT_FAILURE; return CONFIG_EXIT_FAILURE;
@@ -243,30 +250,69 @@ static int parse_args(Config *config, int argc, char *argv[])
} }


/* /*
If no output file is specified for the assembler, this function picks a
filename based on the input file, replacing its extension with '.gg' or
'.s' (or adding it, if none is present).
*/
static void guess_assembler_output_file(Config* config)
{
char *src = config->src_path, *ptr = src + strlen(src) - 1,
*ext = config->assemble ? ".gg" : ".s";
size_t until_ext = ptr - src + 1;

do {
if (*ptr == '.') {
until_ext = ptr - src;
break;
}
} while (ptr-- >= src);

config->dst_path = malloc(sizeof(char) * (until_ext + 4));
if (!config->dst_path)
OUT_OF_MEMORY()
strcpy(stpncpy(config->dst_path, src, until_ext), ext);
}

/*
Ensure that the combination of arguments in a config object are valid. Ensure that the combination of arguments in a config object are valid.

Some modifications are made in the case of missing arguments, like guessing
the filenames for assembler output files.
*/ */
bool sanity_check(Config* config)
static bool sanity_check(Config* config)
{ {
bool assembler = config->assemble || config->disassemble;

if (config->fullscreen && config->scale > 1) { if (config->fullscreen && config->scale > 1) {
ERROR("cannot specify a scale in fullscreen mode") ERROR("cannot specify a scale in fullscreen mode")
return false; return false;
} else if (config->assemble && config->disassemble) { } else if (config->assemble && config->disassemble) {
ERROR("cannot assemble and disassemble at the same time") ERROR("cannot assemble and disassemble at the same time")
return false; return false;
} else if ((config->assemble || config->disassemble) &&
(config->debug || config->fullscreen || config->scale > 1)) {
} else if (assembler && (config->debug || config->fullscreen || config->scale > 1)) {
ERROR("cannot specify emulator options in assembler mode") ERROR("cannot specify emulator options in assembler mode")
return false; return false;
} else if ((config->assemble || config->disassemble) &&
!(config->src_path && config->dst_path)) {
ERROR("assembler mode requires both an input and an output file")
} else if (assembler && !config->src_path) {
ERROR("assembler mode requires an input file")
return false;
}

if (assembler && !config->dst_path) {
guess_assembler_output_file(config);
}
if (assembler && !config->overwrite && !strcmp(config->src_path, config->dst_path)) {
ERROR("refusing to overwrite the assembler input file; pass -r to override")
return false; return false;
} }

return true; return true;
} }


/* /*
Create a new config object and load default values into it. Create a new config object and load default values into it.

Return value is one of CONFIG_OK, CONFIG_EXIT_SUCCESS, CONFIG_EXIT_FAILURE
and indicates how the caller should proceed.
*/ */
int config_create(Config** config_ptr, int argc, char* argv[]) int config_create(Config** config_ptr, int argc, char* argv[])
{ {
@@ -286,6 +332,7 @@ int config_create(Config** config_ptr, int argc, char* argv[])
config->rom_path = NULL; config->rom_path = NULL;
config->src_path = NULL; config->src_path = NULL;
config->dst_path = NULL; config->dst_path = NULL;
config->overwrite = false;


retval = parse_args(config, argc, argv); retval = parse_args(config, argc, argv);
if (retval == CONFIG_OK && !sanity_check(config)) if (retval == CONFIG_OK && !sanity_check(config))
@@ -337,5 +384,6 @@ void config_dump_args(Config* config)
DEBUG("- dst_path: %s", config->dst_path) DEBUG("- dst_path: %s", config->dst_path)
else else
DEBUG("- dst_path: (null)") DEBUG("- dst_path: (null)")
DEBUG("- overwrite: %s", config->overwrite ? "true" : "false")
} }
#endif #endif

+ 1
- 0
src/config.h View File

@@ -26,6 +26,7 @@ typedef struct {
char *rom_path; char *rom_path;
char *src_path; char *src_path;
char *dst_path; char *dst_path;
bool overwrite;
} Config; } Config;


/* Functions */ /* Functions */


+ 4
- 0
src/rom.c View File

@@ -38,6 +38,10 @@ ROM* rom_open(const char *path)
return NULL; return NULL;
} }
rom->name = malloc(sizeof(char) * (strlen(path) + 1)); rom->name = malloc(sizeof(char) * (strlen(path) + 1));
if (!rom->name) {
fclose(fp);
return NULL;
}
strcpy(rom->name, path); strcpy(rom->name, path);


// TODO: load data from file into a buffer // TODO: load data from file into a buffer


Loading…
Cancel
Save