From 5d426648bd76fd9b3d53144c4a4e31ed66e2fe01 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Mon, 23 Mar 2015 02:19:23 -0400 Subject: [PATCH] Make assembler output file optional; sanity checks; bugfixes. --- README.md | 9 ++++++--- crater.c | 2 +- src/config.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++--------- src/config.h | 1 + src/rom.c | 4 ++++ 5 files changed, 69 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 4821b26..4b2dcf8 100644 --- a/README.md +++ b/README.md @@ -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 change state. -`--assemble ` (`-a`) converts z80 assembly source code into a -`.gg` binary that can be run by crater. `--disassemble ` (`-d`) -executes the opposite operation. +`--assemble []` (`-a`) converts z80 assembly source code into a +`.gg` binary that can be run by crater. `--disassemble []` +(`-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. diff --git a/crater.c b/crater.c index 87de115..4e50b5c 100644 --- a/crater.c +++ b/crater.c @@ -24,7 +24,7 @@ int main(int argc, char *argv[]) #endif 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) { printf("Running disassembler: %s -> %s.\n", config->src_path, config->dst_path); } else { diff --git a/src/config.c b/src/config.c index 25197be..8b18090 100644 --- a/src/config.c +++ b/src/config.c @@ -34,9 +34,12 @@ static void print_help(const char *arg1) " -g, --debug display information about emulation state while running,\n" " including register and memory values; can also pause\n" " emulation, set breakpoints, and change state\n" -" -a, --assemble convert z80 assembly source code into a\n" -" binary file that can be run by crater\n" -" -d, --disassemble convert a binary file into z80 assembly code\n", +" -a, --assemble [] convert z80 assembly source code into a\n" +" binary file that can be run by crater\n" +" -d, --disassemble [] 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); } @@ -160,6 +163,8 @@ static int parse_args(Config *config, int argc, char *argv[]) } path = malloc(sizeof(char) * (strlen(arg) + 1)); + if (!path) + OUT_OF_MEMORY() strcpy(path, arg); if (paths_read == 1) { @@ -220,6 +225,8 @@ static int parse_args(Config *config, int argc, char *argv[]) config->rom_path = NULL; } config->disassemble = true; + } else if (!strcmp(arg, "r") || !strcmp(arg, "overwrite")) { + config->overwrite = true; } else { ERROR("unknown argument: %s", argv[i]) 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. + + 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) { ERROR("cannot specify a scale in fullscreen mode") return false; } else if (config->assemble && config->disassemble) { ERROR("cannot assemble and disassemble at the same time") 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") 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 true; } /* 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[]) { @@ -286,6 +332,7 @@ int config_create(Config** config_ptr, int argc, char* argv[]) config->rom_path = NULL; config->src_path = NULL; config->dst_path = NULL; + config->overwrite = false; retval = parse_args(config, argc, argv); if (retval == CONFIG_OK && !sanity_check(config)) @@ -337,5 +384,6 @@ void config_dump_args(Config* config) DEBUG("- dst_path: %s", config->dst_path) else DEBUG("- dst_path: (null)") + DEBUG("- overwrite: %s", config->overwrite ? "true" : "false") } #endif diff --git a/src/config.h b/src/config.h index d8067dc..47fbff2 100644 --- a/src/config.h +++ b/src/config.h @@ -26,6 +26,7 @@ typedef struct { char *rom_path; char *src_path; char *dst_path; + bool overwrite; } Config; /* Functions */ diff --git a/src/rom.c b/src/rom.c index 109047a..2ba40fe 100644 --- a/src/rom.c +++ b/src/rom.c @@ -38,6 +38,10 @@ ROM* rom_open(const char *path) return NULL; } rom->name = malloc(sizeof(char) * (strlen(path) + 1)); + if (!rom->name) { + fclose(fp); + return NULL; + } strcpy(rom->name, path); // TODO: load data from file into a buffer