An emulator, assembler, and disassembler for the Sega Game Gear
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

161 lines
4.0 KiB

  1. /* Copyright (C) 2014 Ben Kurtovic <ben.kurtovic@gmail.com>
  2. Released under the terms of the MIT License. See LICENSE for details. */
  3. #include <dirent.h>
  4. #include <errno.h>
  5. #include <stdbool.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sys/types.h>
  10. #include "src/errors.h"
  11. #include "src/rom.h"
  12. #include "src/version.h"
  13. #define ROMS_DIR "roms"
  14. /* Print command-line help/usage. */
  15. static void print_help(char *arg1)
  16. {
  17. printf("%s [--help|-h] [--version|-v] [rom_path]\n", arg1);
  18. }
  19. /* Print crater's version. */
  20. static void print_version()
  21. {
  22. printf("crater %s\n", CRATER_VERSION);
  23. }
  24. /* Parse the command-line arguments for any special flags. */
  25. static void parse_args(int argc, char *argv[])
  26. {
  27. char *arg;
  28. int i;
  29. for (i = 1; i < argc; i++) {
  30. arg = argv[i];
  31. if (arg[0] != '-')
  32. continue;
  33. do
  34. arg++;
  35. while (arg[0] == '-');
  36. if (!strcmp(arg, "h") || !strcmp(arg, "help")) {
  37. print_help(argv[0]);
  38. exit(0);
  39. } else if (!strcmp(arg, "v") || !strcmp(arg, "version")) {
  40. print_version();
  41. exit(0);
  42. } else {
  43. printf("Error: unknown argument: %s\n", argv[i]);
  44. exit(1);
  45. }
  46. }
  47. }
  48. /* Return whether the given string ends with the given suffix. */
  49. static bool ends_with(char *input, char *suffix)
  50. {
  51. size_t ilen = strlen(input), slen = strlen(suffix);
  52. if (ilen < slen)
  53. return false;
  54. return strcmp(input + (ilen - slen), suffix) == 0;
  55. }
  56. /* Load all potential ROM files in roms/ into a data structure. */
  57. static int load_rom_paths(char ***path_ptr)
  58. {
  59. DIR *dirp;
  60. struct dirent *entry;
  61. char **paths = NULL, *path;
  62. int psize = 8, npaths = 0;
  63. dirp = opendir(ROMS_DIR);
  64. if (dirp) {
  65. paths = malloc(sizeof(char*) * psize);
  66. if (!paths)
  67. out_of_memory();
  68. while ((entry = readdir(dirp))) {
  69. path = entry->d_name;
  70. if (ends_with(path, ".gg") || ends_with(path, ".bin")) {
  71. if (npaths >= psize) {
  72. paths = realloc(paths, sizeof(char*) * (psize *= 2));
  73. if (!paths)
  74. out_of_memory();
  75. }
  76. paths[npaths] = malloc(sizeof(char*) *
  77. (strlen(path) + strlen(ROMS_DIR) + 1));
  78. if (!paths[npaths])
  79. out_of_memory();
  80. strcpy(paths[npaths], ROMS_DIR "/");
  81. strcat(paths[npaths], path);
  82. npaths++;
  83. }
  84. }
  85. closedir(dirp);
  86. } else {
  87. if (errno == ENOENT)
  88. printf("Warning: couldn't find roms/ directory.\n");
  89. else
  90. perror("Warning: couldn't open roms/ directory");
  91. }
  92. *path_ptr = paths;
  93. return npaths;
  94. }
  95. /* Find all potential ROM files in the roms/ directory, then ask the user which
  96. * one they want to run.
  97. */
  98. static char* get_rom_path_from_user()
  99. {
  100. char **paths, *path, *input = NULL;
  101. int npaths, i;
  102. long int index;
  103. size_t size = 0;
  104. ssize_t len;
  105. npaths = load_rom_paths(&paths);
  106. for (i = 0; i < npaths; i++)
  107. printf("[%2d] %s\n", i + 1, paths[i]);
  108. if (npaths)
  109. printf("Enter a ROM number from above, or the path to a ROM image: ");
  110. else
  111. printf("Enter the path to a ROM image: ");
  112. len = getline(&input, &size, stdin);
  113. if (!input)
  114. out_of_memory();
  115. if (len > 0 && input[len - 1] == '\n')
  116. input[len - 1] = '\0';
  117. index = strtol(input, NULL, 10);
  118. if (index < 1 || index > npaths)
  119. path = input;
  120. else
  121. path = paths[index - 1];
  122. for (i = 0; i < npaths; i++) {
  123. if (paths[i] != path)
  124. free(paths[i]);
  125. }
  126. if (paths)
  127. free(paths);
  128. return path;
  129. }
  130. int main(int argc, char *argv[])
  131. {
  132. char *rom_path;
  133. parse_args(argc, argv);
  134. rom_path = argc > 1 ? argv[1] : get_rom_path_from_user();
  135. // TODO: main logic hook here
  136. printf("Loading ROM: %s\n", rom_path);
  137. if (argc <= 1)
  138. free(rom_path);
  139. return 0;
  140. }