| @@ -1,190 +1,42 @@ | |||
| /* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
| Released under the terms of the MIT License. See LICENSE for details. */ | |||
| #include <dirent.h> | |||
| #include <errno.h> | |||
| #include <stdbool.h> | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <sys/types.h> | |||
| #include "src/errors.h" | |||
| #include "src/config.h" | |||
| #include "src/logging.h" | |||
| #include "src/rom.h" | |||
| #include "src/version.h" | |||
| #define ROMS_DIR "roms" | |||
| /* Print command-line help/usage. */ | |||
| static void print_help(const char *arg1) | |||
| { | |||
| printf("%s [-h] [-v] [-f] [-s <n>] [<rom_path>] ...\n" | |||
| "\n" | |||
| "basic options:\n" | |||
| " -h, --help show this help message and exit\n" | |||
| " -v, --version show crater's version number and exit\n" | |||
| " -f, --fullscreen enable fullscreen mode\n" | |||
| " -s, --scale <n> scale the game screen by an integer factor\n" | |||
| " (applies to windowed mode only)\n" | |||
| " <rom_path> path to the rom file to execute; if not given, will look\n" | |||
| " in the roms/ directory and prompt the user\n" | |||
| "\n" | |||
| "advanced options:\n" | |||
| " -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 <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", | |||
| arg1); | |||
| } | |||
| /* Print crater's version. */ | |||
| static void print_version() | |||
| { | |||
| printf("crater %s\n", CRATER_VERSION); | |||
| } | |||
| /* Parse the command-line arguments for any special flags. */ | |||
| static void parse_args(int argc, char *argv[]) | |||
| { | |||
| char *arg; | |||
| int i; | |||
| for (i = 1; i < argc; i++) { | |||
| arg = argv[i]; | |||
| if (arg[0] != '-') | |||
| continue; | |||
| do | |||
| arg++; | |||
| while (arg[0] == '-'); | |||
| if (!strcmp(arg, "h") || !strcmp(arg, "help")) { | |||
| print_help(argv[0]); | |||
| exit(0); | |||
| } else if (!strcmp(arg, "v") || !strcmp(arg, "version")) { | |||
| print_version(); | |||
| exit(0); | |||
| // f fullscreen | |||
| // s scale | |||
| // g debug | |||
| // a assemble | |||
| // d disassemble | |||
| } else { | |||
| FATAL("unknown argument: %s", argv[i]) | |||
| } | |||
| } | |||
| } | |||
| /* Return whether the given string ends with the given suffix. */ | |||
| static bool ends_with(const char *input, const char *suffix) | |||
| { | |||
| size_t ilen = strlen(input), slen = strlen(suffix); | |||
| if (ilen < slen) | |||
| return false; | |||
| return strcmp(input + (ilen - slen), suffix) == 0; | |||
| } | |||
| /* Load all potential ROM files in roms/ into a data structure. */ | |||
| static int get_rom_paths(char ***path_ptr) | |||
| { | |||
| DIR *dirp; | |||
| struct dirent *entry; | |||
| char **paths = NULL, *path; | |||
| int psize = 8, npaths = 0; | |||
| dirp = opendir(ROMS_DIR); | |||
| if (dirp) { | |||
| paths = malloc(sizeof(char*) * psize); | |||
| if (!paths) | |||
| OUT_OF_MEMORY() | |||
| while ((entry = readdir(dirp))) { | |||
| path = entry->d_name; | |||
| if (ends_with(path, ".gg") || ends_with(path, ".bin")) { | |||
| if (npaths >= psize) { | |||
| paths = realloc(paths, sizeof(char*) * (psize *= 2)); | |||
| if (!paths) | |||
| OUT_OF_MEMORY() | |||
| } | |||
| paths[npaths] = malloc(sizeof(char*) * | |||
| (strlen(path) + strlen(ROMS_DIR) + 1)); | |||
| if (!paths[npaths]) | |||
| OUT_OF_MEMORY() | |||
| strcpy(paths[npaths], ROMS_DIR "/"); | |||
| strcat(paths[npaths], path); | |||
| npaths++; | |||
| } | |||
| } | |||
| closedir(dirp); | |||
| } else { | |||
| WARN_ERRNO("couldn't open 'roms/'") | |||
| } | |||
| *path_ptr = paths; | |||
| return npaths; | |||
| } | |||
| /* Find all potential ROM files in the roms/ directory, then ask the user which | |||
| one they want to run. */ | |||
| static char* get_rom_path_from_user() | |||
| { | |||
| char **paths, *path, *input = NULL; | |||
| int npaths, i; | |||
| long int index; | |||
| size_t size = 0; | |||
| ssize_t len; | |||
| npaths = get_rom_paths(&paths); | |||
| for (i = 0; i < npaths; i++) | |||
| printf("[%2d] %s\n", i + 1, paths[i]); | |||
| if (npaths) | |||
| printf("Enter a ROM number from above, or the path to a ROM image: "); | |||
| else | |||
| printf("Enter the path to a ROM image: "); | |||
| len = getline(&input, &size, stdin); | |||
| if (!input) | |||
| OUT_OF_MEMORY() | |||
| if (len > 0 && input[len - 1] == '\n') | |||
| input[len - 1] = '\0'; | |||
| index = strtol(input, NULL, 10); | |||
| if (index < 1 || index > npaths) | |||
| path = input; | |||
| else | |||
| path = paths[index - 1]; | |||
| for (i = 0; i < npaths; i++) { | |||
| if (paths[i] != path) | |||
| free(paths[i]); | |||
| } | |||
| if (paths) | |||
| free(paths); | |||
| return path; | |||
| } | |||
| /* | |||
| Main function. | |||
| */ | |||
| int main(int argc, char *argv[]) | |||
| { | |||
| char *rom_path; | |||
| rom_type *rom; | |||
| Config *config; | |||
| ROM *rom; | |||
| int retval; | |||
| retval = config_create(&config, argc, argv); | |||
| if (retval != CONFIG_OK) | |||
| return retval == CONFIG_EXIT_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE; | |||
| parse_args(argc, argv); | |||
| printf("crater: a Sega Game Gear emulator\n\n"); | |||
| rom_path = argc > 1 ? argv[1] : get_rom_path_from_user(); | |||
| if (rom_path[0] == '\0') | |||
| FATAL("no image given") | |||
| if (!(rom = rom_open(rom_path))) { | |||
| #ifdef DEBUG_MODE | |||
| config_dump_args(config); | |||
| #endif | |||
| if (!(rom = rom_open(config->rom_path))) { | |||
| if (errno == ENOMEM) | |||
| OUT_OF_MEMORY() | |||
| else | |||
| FATAL_ERRNO("couldn't load ROM image '%s'", rom_path) | |||
| FATAL_ERRNO("couldn't load ROM image '%s'", config->rom_path) | |||
| } | |||
| if (argc <= 1) | |||
| free(rom_path); | |||
| printf("Loaded ROM image: %s.\n", rom->name); | |||
| // TODO: start from here | |||
| rom_close(rom); | |||
| return 0; | |||
| config_destroy(config); | |||
| return EXIT_SUCCESS; | |||
| } | |||
| @@ -0,0 +1,340 @@ | |||
| /* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
| Released under the terms of the MIT License. See LICENSE for details. */ | |||
| #include <dirent.h> | |||
| #include <errno.h> | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <sys/types.h> | |||
| #include "config.h" | |||
| #include "logging.h" | |||
| #include "version.h" | |||
| #define ROMS_DIR "roms" | |||
| /* | |||
| Print command-line help/usage. | |||
| */ | |||
| static void print_help(const char *arg1) | |||
| { | |||
| printf("%s [-h] [-v] [-f] [-s <n>] [<rom_path>] ...\n" | |||
| "\n" | |||
| "basic options:\n" | |||
| " -h, --help show this help message and exit\n" | |||
| " -v, --version show crater's version number and exit\n" | |||
| " -f, --fullscreen enable fullscreen mode\n" | |||
| " -s, --scale <n> scale the game screen by an integer factor\n" | |||
| " (applies to windowed mode only)\n" | |||
| " <rom_path> path to the rom file to execute; if not given, will look\n" | |||
| " in the roms/ directory and prompt the user\n" | |||
| "\n" | |||
| "advanced options:\n" | |||
| " -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 <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", | |||
| arg1); | |||
| } | |||
| /* | |||
| Print crater's version. | |||
| */ | |||
| static void print_version() | |||
| { | |||
| printf("crater %s\n", CRATER_VERSION); | |||
| } | |||
| /* | |||
| Return whether the given string ends with the given suffix. | |||
| */ | |||
| static bool ends_with(const char *input, const char *suffix) | |||
| { | |||
| size_t ilen = strlen(input), slen = strlen(suffix); | |||
| if (ilen < slen) | |||
| return false; | |||
| return strcmp(input + (ilen - slen), suffix) == 0; | |||
| } | |||
| /* | |||
| Load all potential ROM files in roms/ into a data structure. | |||
| */ | |||
| static int get_rom_paths(char ***path_ptr) | |||
| { | |||
| DIR *dirp; | |||
| struct dirent *entry; | |||
| char **paths = NULL, *path; | |||
| int psize = 8, npaths = 0; | |||
| dirp = opendir(ROMS_DIR); | |||
| if (dirp) { | |||
| paths = malloc(sizeof(char*) * psize); | |||
| if (!paths) | |||
| OUT_OF_MEMORY() | |||
| while ((entry = readdir(dirp))) { | |||
| path = entry->d_name; | |||
| if (ends_with(path, ".gg") || ends_with(path, ".bin")) { | |||
| if (npaths >= psize) { | |||
| paths = realloc(paths, sizeof(char*) * (psize *= 2)); | |||
| if (!paths) | |||
| OUT_OF_MEMORY() | |||
| } | |||
| paths[npaths] = malloc(sizeof(char*) * | |||
| (strlen(path) + strlen(ROMS_DIR) + 1)); | |||
| if (!paths[npaths]) | |||
| OUT_OF_MEMORY() | |||
| strcpy(paths[npaths], ROMS_DIR "/"); | |||
| strcat(paths[npaths], path); | |||
| npaths++; | |||
| } | |||
| } | |||
| closedir(dirp); | |||
| } else { | |||
| WARN_ERRNO("couldn't open 'roms/'") | |||
| } | |||
| *path_ptr = paths; | |||
| return npaths; | |||
| } | |||
| /* | |||
| Find all potential ROM files in the roms/ directory, then ask the user | |||
| which one they want to run. | |||
| */ | |||
| static char* get_rom_path_from_user() | |||
| { | |||
| char **paths, *path, *input = NULL; | |||
| int npaths, i; | |||
| long int index; | |||
| size_t size = 0; | |||
| ssize_t len; | |||
| npaths = get_rom_paths(&paths); | |||
| for (i = 0; i < npaths; i++) | |||
| printf("[%2d] %s\n", i + 1, paths[i]); | |||
| if (npaths) | |||
| printf("Enter a ROM number from above, or the path to a ROM image: "); | |||
| else | |||
| printf("Enter the path to a ROM image: "); | |||
| len = getline(&input, &size, stdin); | |||
| if (!input) | |||
| OUT_OF_MEMORY() | |||
| if (len > 0 && input[len - 1] == '\n') | |||
| input[len - 1] = '\0'; | |||
| index = strtol(input, NULL, 10); | |||
| if (index < 1 || index > npaths) | |||
| path = input; | |||
| else | |||
| path = paths[index - 1]; | |||
| for (i = 0; i < npaths; i++) { | |||
| if (paths[i] != path) | |||
| free(paths[i]); | |||
| } | |||
| if (paths) | |||
| free(paths); | |||
| return path; | |||
| } | |||
| /* | |||
| Parse the command-line arguments for any special flags. | |||
| */ | |||
| static int parse_args(Config *config, int argc, char *argv[]) | |||
| { | |||
| char *arg, *path; | |||
| int i, paths_read = 0; | |||
| for (i = 1; i < argc; i++) { | |||
| arg = argv[i]; | |||
| if (arg[0] != '-') { | |||
| // Parsing a path or other variable: | |||
| if (paths_read >= 2) { | |||
| ERROR("too many arguments given - emulator mode accepts one " | |||
| "ROM file,\nand assembler mode accepts one input file " | |||
| "and one output file") | |||
| return CONFIG_EXIT_FAILURE; | |||
| } | |||
| path = malloc(sizeof(char) * (strlen(arg) + 1)); | |||
| strcpy(path, arg); | |||
| if (paths_read == 1) { | |||
| /* If this is the second path given, it can only be an output | |||
| file for the assembler. If the assembler is not enabled by | |||
| subsequent arguments, we'll throw an error. */ | |||
| config->dst_path = path; | |||
| } else { | |||
| /* Otherwise, put the argument in the expected place. If we put | |||
| it in rom_path and the assembler is enabled by later | |||
| arguments, we'll move it. */ | |||
| if (config->assemble || config->disassemble) | |||
| config->src_path = path; | |||
| else | |||
| config->rom_path = path; | |||
| } | |||
| paths_read++; | |||
| continue; | |||
| } | |||
| // Parsing an option: | |||
| do | |||
| arg++; | |||
| while (arg[0] == '-'); | |||
| if (!strcmp(arg, "h") || !strcmp(arg, "help")) { | |||
| print_help(argv[0]); | |||
| return CONFIG_EXIT_SUCCESS; | |||
| } else if (!strcmp(arg, "v") || !strcmp(arg, "version")) { | |||
| print_version(); | |||
| return CONFIG_EXIT_SUCCESS; | |||
| } else if (!strcmp(arg, "f") || !strcmp(arg, "fullscreen")) { | |||
| config->fullscreen = true; | |||
| } else if (!strcmp(arg, "s") || !strcmp(arg, "scale")) { | |||
| if (i++ >= argc) { | |||
| ERROR("the scale option requires an argument") | |||
| return CONFIG_EXIT_FAILURE; | |||
| } | |||
| arg = argv[i]; | |||
| long scale = strtol(arg, NULL, 10); | |||
| if (scale <= 0 || scale > SCALE_MAX) { | |||
| ERROR("scale factor of %s is not an integer or is out of range", arg) | |||
| return CONFIG_EXIT_FAILURE; | |||
| } | |||
| } else if (!strcmp(arg, "g") || !strcmp(arg, "debug")) { | |||
| config->debug = true; | |||
| } else if (!strcmp(arg, "a") || !strcmp(arg, "assemble")) { | |||
| if (paths_read >= 1) { | |||
| config->src_path = config->rom_path; | |||
| config->rom_path = NULL; | |||
| } | |||
| config->assemble = true; | |||
| } else if (!strcmp(arg, "d") || !strcmp(arg, "disassemble")) { | |||
| if (paths_read >= 1) { | |||
| config->src_path = config->rom_path; | |||
| config->rom_path = NULL; | |||
| } | |||
| config->disassemble = true; | |||
| } else { | |||
| ERROR("unknown argument: %s", argv[i]) | |||
| return CONFIG_EXIT_FAILURE; | |||
| } | |||
| } | |||
| if (!config->assemble && !config->disassemble && paths_read >= 2) { | |||
| ERROR("too many arguments given - emulator mode accepts one ROM file") | |||
| return CONFIG_EXIT_FAILURE; | |||
| } | |||
| if (!config->assemble && !config->disassemble && paths_read == 0) { | |||
| path = get_rom_path_from_user(); | |||
| if (path[0] == '\0') { | |||
| ERROR("no ROM image given") | |||
| return CONFIG_EXIT_FAILURE; | |||
| } | |||
| config->rom_path = path; | |||
| } | |||
| return CONFIG_OK; | |||
| } | |||
| /* | |||
| Ensure that the combination of arguments in a config object are valid. | |||
| */ | |||
| bool sanity_check(Config* config) | |||
| { | |||
| if (config->fullscreen && config->scale) { | |||
| 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)) { | |||
| 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") | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| /* | |||
| Create a new config object and load default values into it. | |||
| */ | |||
| int config_create(Config** config_ptr, int argc, char* argv[]) | |||
| { | |||
| Config *config; | |||
| int retval; | |||
| if (!(config = malloc(sizeof(Config)))) { | |||
| OUT_OF_MEMORY() | |||
| return CONFIG_EXIT_FAILURE; | |||
| } | |||
| config->debug = false; | |||
| config->assemble = false; | |||
| config->disassemble = false; | |||
| config->fullscreen = false; | |||
| config->scale = 1; | |||
| config->rom_path = NULL; | |||
| config->src_path = NULL; | |||
| config->dst_path = NULL; | |||
| retval = parse_args(config, argc, argv); | |||
| if (retval == CONFIG_OK && !sanity_check(config)) | |||
| retval = CONFIG_EXIT_FAILURE; | |||
| if (retval != CONFIG_OK) { | |||
| config_destroy(config); | |||
| return retval; | |||
| } | |||
| *config_ptr = config; | |||
| return CONFIG_OK; | |||
| } | |||
| /* | |||
| Destroy a config object previously created with config_create(). | |||
| */ | |||
| void config_destroy(Config *config) | |||
| { | |||
| if (config->rom_path) | |||
| free(config->rom_path); | |||
| if (config->src_path) | |||
| free(config->src_path); | |||
| if (config->dst_path) | |||
| free(config->dst_path); | |||
| free(config); | |||
| } | |||
| #ifdef DEBUG_MODE | |||
| /* | |||
| DEBUG FUNCTION: Print out all config arguments to stdout. | |||
| */ | |||
| void config_dump_args(Config* config) | |||
| { | |||
| DEBUG("Dumping arguments:") | |||
| DEBUG("- fullscreen: %d", config->fullscreen) | |||
| DEBUG("- scale: %d", config->scale) | |||
| DEBUG("- debug: %d", config->debug) | |||
| DEBUG("- assemble: %d", config->assemble) | |||
| DEBUG("- disassemble: %d", config->disassemble) | |||
| if (config->rom_path) | |||
| DEBUG("- rom_path: %s", config->rom_path) | |||
| else | |||
| DEBUG("- rom_path: NULL") | |||
| if (config->src_path) | |||
| DEBUG("- src_path: %s", config->src_path) | |||
| else | |||
| DEBUG("- src_path: NULL") | |||
| if (config->dst_path) | |||
| DEBUG("- dst_path: %s", config->dst_path) | |||
| else | |||
| DEBUG("- dst_path: NULL") | |||
| } | |||
| #endif | |||
| @@ -0,0 +1,38 @@ | |||
| /* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
| Released under the terms of the MIT License. See LICENSE for details. */ | |||
| #pragma once | |||
| #include <stdbool.h> | |||
| #define CONFIG_OK 0 | |||
| #define CONFIG_EXIT_SUCCESS 1 | |||
| #define CONFIG_EXIT_FAILURE 2 | |||
| /* | |||
| We need some sort of maximum scale - with a native resolution of 160 x 144, | |||
| a scale factor of 1024 will let us go up to 163,840 x 147,456 pixels. | |||
| No one has a screen this large. | |||
| */ | |||
| #define SCALE_MAX 1024 | |||
| /* Structs */ | |||
| typedef struct { | |||
| bool debug; | |||
| bool assemble; | |||
| bool disassemble; | |||
| bool fullscreen; | |||
| unsigned scale; | |||
| char *rom_path; | |||
| char *src_path; | |||
| char *dst_path; | |||
| } Config; | |||
| /* Functions */ | |||
| int config_create(Config**, int, char*[]); | |||
| void config_destroy(Config*); | |||
| #ifdef DEBUG_MODE | |||
| void config_dump_args(Config*); | |||
| #endif | |||
| @@ -1,27 +0,0 @@ | |||
| /* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
| Released under the terms of the MIT License. See LICENSE for details. */ | |||
| #pragma once | |||
| #include <errno.h> | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| /* Internal usage only */ | |||
| #define LOG_MSG(level, extra, after, ...) { \ | |||
| fprintf(stderr, level ": " __VA_ARGS__); \ | |||
| extra; \ | |||
| fprintf(stderr, ".\n"); \ | |||
| after; \ | |||
| } | |||
| #define PRINT_ERRNO() fprintf(stderr, ": %s", strerror(errno)) | |||
| /* Public error logging macros */ | |||
| #define FATAL(...) LOG_MSG("Error", {}, exit(EXIT_FAILURE), __VA_ARGS__) | |||
| #define FATAL_ERRNO(...) LOG_MSG("Error", PRINT_ERRNO(), exit(EXIT_FAILURE), __VA_ARGS__) | |||
| #define WARN(...) LOG_MSG("Warning", {}, {}, __VA_ARGS__) | |||
| #define WARN_ERRNO(...) LOG_MSG("Warning", PRINT_ERRNO(), {}, __VA_ARGS__) | |||
| #define OUT_OF_MEMORY() FATAL("couldn't allocate enough memory") | |||
| @@ -0,0 +1,35 @@ | |||
| /* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
| Released under the terms of the MIT License. See LICENSE for details. */ | |||
| #pragma once | |||
| #include <errno.h> | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| /* Internal usage only */ | |||
| #define LOG_MSG(level, extra, tail, after, ...) { \ | |||
| fprintf(stderr, level ": " __VA_ARGS__); \ | |||
| extra; \ | |||
| fprintf(stderr, tail ? ".\n" : "\n"); \ | |||
| after; \ | |||
| } | |||
| #define PRINT_ERRNO() fprintf(stderr, ": %s", strerror(errno)) | |||
| /* Public logging macros */ | |||
| #define FATAL(...) LOG_MSG("Error", {}, 1, exit(EXIT_FAILURE), __VA_ARGS__) | |||
| #define FATAL_ERRNO(...) LOG_MSG("Error", PRINT_ERRNO(), 1, exit(EXIT_FAILURE), __VA_ARGS__) | |||
| #define ERROR(...) LOG_MSG("Error", {}, 1, {}, __VA_ARGS__) | |||
| #define ERROR_ERRNO(...) LOG_MSG("Error", PRINT_ERRNO(), 1, {}, __VA_ARGS__) | |||
| #define WARN(...) LOG_MSG("Warning", {}, 1, {}, __VA_ARGS__) | |||
| #define WARN_ERRNO(...) LOG_MSG("Warning", PRINT_ERRNO(), 1, {}, __VA_ARGS__) | |||
| #ifdef DEBUG_MODE | |||
| #define DEBUG(...) LOG_MSG("[DEBUG]", {}, 0, {}, __VA_ARGS__) | |||
| #define DEBUG_ERRNO(...) LOG_MSG("[DEBUG]", PRINT_ERRNO(), 0, {}, __VA_ARGS__) | |||
| #endif | |||
| #define OUT_OF_MEMORY() FATAL("couldn't allocate enough memory") | |||
| @@ -9,11 +9,13 @@ | |||
| #include "rom.h" | |||
| /* Create and return a ROM object located at the given path. Return NULL if | |||
| there was an error; errno will be set appropriately. */ | |||
| rom_type* rom_open(const char *path) | |||
| /* | |||
| Create and return a ROM object located at the given path. Return NULL if | |||
| there was an error; errno will be set appropriately. | |||
| */ | |||
| ROM* rom_open(const char *path) | |||
| { | |||
| rom_type *rom; | |||
| ROM *rom; | |||
| FILE* fp; | |||
| struct stat s; | |||
| @@ -31,7 +33,7 @@ rom_type* rom_open(const char *path) | |||
| return NULL; | |||
| } | |||
| if (!(rom = malloc(sizeof(rom_type)))) { | |||
| if (!(rom = malloc(sizeof(ROM)))) { | |||
| fclose(fp); | |||
| return NULL; | |||
| } | |||
| @@ -44,8 +46,10 @@ rom_type* rom_open(const char *path) | |||
| return rom; | |||
| } | |||
| /* Free a ROM object previously created with rom_open(). */ | |||
| void rom_close(rom_type *rom) | |||
| /* | |||
| Free a ROM object previously created with rom_open(). | |||
| */ | |||
| void rom_close(ROM *rom) | |||
| { | |||
| free(rom); | |||
| } | |||
| @@ -8,9 +8,9 @@ | |||
| typedef struct { | |||
| char* name; | |||
| char* data; | |||
| } rom_type; | |||
| } ROM; | |||
| /* Functions */ | |||
| rom_type* rom_open(const char*); | |||
| void rom_close(rom_type*); | |||
| ROM* rom_open(const char*); | |||
| void rom_close(ROM*); | |||
| @@ -10,4 +10,4 @@ | |||
| typedef struct { | |||
| int pc; | |||
| } z80_type; | |||
| } Z80; | |||