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.
 
 
 
 
 

134 lines
3.2 KiB

  1. /* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
  2. Released under the terms of the MIT License. See LICENSE for details. */
  3. #include <errno.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <sys/stat.h>
  8. #include "io.h"
  9. #include "../logging.h"
  10. /*
  11. Deallocate a LineBuffer previously created with read_source_file().
  12. */
  13. void line_buffer_free(LineBuffer *buffer)
  14. {
  15. Line *line = buffer->lines, *temp;
  16. while (line) {
  17. temp = line->next;
  18. free(line->data);
  19. free(line);
  20. line = temp;
  21. }
  22. free(buffer->filename);
  23. free(buffer);
  24. }
  25. /*
  26. Read the contents of the source file at the given path into a line buffer.
  27. Return the buffer if reading was successful; it must be freed with
  28. line_buffer_free() when done. Return NULL if an error occurred while
  29. reading. If print_errors is true, a message will also be printed to stderr.
  30. */
  31. LineBuffer* read_source_file(const char *path, bool print_errors)
  32. {
  33. FILE *fp;
  34. struct stat st;
  35. if (!(fp = fopen(path, "r"))) {
  36. if (print_errors)
  37. ERROR_ERRNO("couldn't open source file")
  38. return NULL;
  39. }
  40. if (fstat(fileno(fp), &st)) {
  41. fclose(fp);
  42. if (print_errors)
  43. ERROR_ERRNO("couldn't open source file")
  44. return NULL;
  45. }
  46. if (!(st.st_mode & S_IFREG)) {
  47. fclose(fp);
  48. if (print_errors)
  49. ERROR("couldn't open source file: %s", st.st_mode & S_IFDIR ?
  50. "Is a directory" : "Is not a regular file")
  51. return NULL;
  52. }
  53. LineBuffer *source = malloc(sizeof(LineBuffer));
  54. if (!source)
  55. OUT_OF_MEMORY()
  56. source->lines = NULL;
  57. source->filename = strdup(path);
  58. if (!source->filename)
  59. OUT_OF_MEMORY()
  60. Line dummy = {.next = NULL};
  61. Line *line, *prev = &dummy;
  62. size_t lineno = 1;
  63. while (1) {
  64. char *data = NULL;
  65. size_t cap = 0;
  66. ssize_t len;
  67. if ((len = getline(&data, &cap, fp)) < 0) {
  68. if (feof(fp))
  69. break;
  70. if (errno == ENOMEM)
  71. OUT_OF_MEMORY()
  72. if (print_errors)
  73. ERROR_ERRNO("couldn't read source file")
  74. fclose(fp);
  75. source->lines = dummy.next;
  76. line_buffer_free(source);
  77. return NULL;
  78. }
  79. line = malloc(sizeof(Line));
  80. if (!line)
  81. OUT_OF_MEMORY()
  82. line->data = data;
  83. line->length = feof(fp) ? len : (len - 1);
  84. line->lineno = lineno++;
  85. line->next = NULL;
  86. prev->next = line;
  87. prev = line;
  88. }
  89. fclose(fp);
  90. source->lines = dummy.next;
  91. return source;
  92. }
  93. /*
  94. Write an assembled binary file to the given path.
  95. Return whether the file was written successfully. On error, a message is
  96. printed to stderr.
  97. */
  98. bool write_binary_file(const char *path, const uint8_t *data, size_t size)
  99. {
  100. FILE *fp;
  101. if (!(fp = fopen(path, "wb"))) {
  102. ERROR_ERRNO("couldn't open destination file")
  103. return false;
  104. }
  105. if (!fwrite(data, size, 1, fp)) {
  106. fclose(fp);
  107. ERROR_ERRNO("couldn't write to destination file")
  108. return false;
  109. }
  110. fclose(fp);
  111. return true;
  112. }