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.
 
 
 
 
 

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