amalgamate.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <stdarg.h>
  5. #include <ctype.h>
  6. #define OUT_FILE "PicoAll.c"
  7. // files to amalgamate, in order
  8. static const char *files[] =
  9. {
  10. "Pico/Pico.h",
  11. // PicoInt.h includes some CD stuff, so start with them
  12. "Pico/cd/cd_file.h",
  13. "Pico/cd/cd_sys.h",
  14. "Pico/cd/LC89510.h",
  15. "Pico/cd/gfx_cd.h",
  16. "Pico/cd/pcm.h",
  17. "Pico/PicoInt.h",
  18. "Pico/Patch.h",
  19. "Pico/sound/mix.h",
  20. // source
  21. "Pico/Area.c",
  22. "Pico/Cart.c",
  23. "Pico/Draw2.c",
  24. "Pico/Draw.c",
  25. "Pico/VideoPort.c",
  26. "Pico/sound/sound.c",
  27. "Pico/MemoryCmn.c",
  28. "Pico/Memory.c",
  29. "Pico/Misc.c",
  30. "Pico/Patch.c",
  31. "Pico/Sek.c",
  32. "Pico/cd/Area.c",
  33. "Pico/cd/buffering.c",
  34. "Pico/cd/cd_file.c",
  35. "Pico/cd/cd_sys.c",
  36. "Pico/cd/cell_map.c",
  37. "Pico/cd/gfx_cd.c",
  38. "Pico/cd/LC89510.c",
  39. "Pico/cd/Memory.c",
  40. "Pico/cd/Misc.c",
  41. "Pico/cd/pcm.c",
  42. "Pico/cd/Sek.c",
  43. "Pico/cd/Pico.c",
  44. "Pico/Pico.c",
  45. };
  46. static char *includes[128];
  47. static void eprintf(const char *fmt, ...)
  48. {
  49. va_list args;
  50. va_start(args, fmt);
  51. vprintf(fmt, args);
  52. va_end(args);
  53. exit(1);
  54. }
  55. static void emit_header(FILE *f, const char *fname)
  56. {
  57. char tmp[128] = "/* */";
  58. memcpy(tmp + 3, fname, strlen(fname));
  59. fprintf(f, "\n\n");
  60. fprintf(f, "/**************************************************************/\n");
  61. fprintf(f, "/**************************************************************/\n");
  62. fprintf(f, "%s\n", tmp);
  63. fprintf(f, "/**************************************************************/\n");
  64. }
  65. static const char *add_include(const char *include)
  66. {
  67. int i;
  68. char processed_inc[128+4];
  69. // must first quote relative includes
  70. snprintf(processed_inc, sizeof(processed_inc), (include[0] != '<') ? "\"%s\"" : "%s", include);
  71. // find in include list
  72. for (i = 0; includes[i] && i < 128; i++)
  73. {
  74. if (strcmp(processed_inc, includes[i]) == 0) break;
  75. }
  76. if (i == 128) eprintf("add_include: includes overflowed\n");
  77. if (includes[i] != NULL)
  78. {
  79. printf("already have: %s\n", processed_inc);
  80. return NULL;
  81. }
  82. else
  83. {
  84. printf("adding: %s\n", processed_inc);
  85. includes[i] = strdup(processed_inc);
  86. if (includes[i] == NULL) eprintf("add_include: OOM\n");
  87. return includes[i];
  88. }
  89. }
  90. static const char *add_raw_include(const char *include, const char *base)
  91. {
  92. const char *ps, *pe;
  93. char processed_inc[128];
  94. for (ps = include; *ps && isspace(*ps); ps++);
  95. if (*ps == '<')
  96. {
  97. int len = 1;
  98. // system include, search for '>'
  99. for (pe = ps; *pe && *pe != '>'; pe++, len++);
  100. if (*pe == 0 || len > 127) eprintf("add_raw_include: failed sysinclude, len=%i\n", len);
  101. strncpy(processed_inc, ps, len);
  102. processed_inc[len] = 0;
  103. }
  104. else if (*ps == '\"')
  105. {
  106. int len, pos;
  107. // relative include, make path absolute (or relative to base dir)
  108. strcpy(processed_inc, base);
  109. ps++;
  110. while (*ps == '.')
  111. {
  112. if (strncmp(ps, "../", 3) == 0)
  113. {
  114. char *p;
  115. if (processed_inc[0] == 0)
  116. eprintf("add_raw_include: already in root, can't go down: %s | %s\n", ps, include);
  117. p = strrchr(processed_inc, '/');
  118. if (p == NULL) eprintf("add_raw_include: can't happen\n");
  119. *p = 0;
  120. p = strrchr(processed_inc, '/');
  121. if (p != NULL) p[1] = 0;
  122. else processed_inc[0] = 0;
  123. ps += 3;
  124. }
  125. else if (strncmp(ps, "./", 2) == 0)
  126. {
  127. ps += 2; // just skip
  128. }
  129. while (*ps == '/') ps++;
  130. }
  131. if (*ps == 0) eprintf("add_raw_include: failed with %s\n", include);
  132. len = pos = strlen(processed_inc);
  133. for (pe = ps; *pe && *pe != '\"'; pe++, len++);
  134. if (*pe == 0 || len > 127) eprintf("add_raw_include: failed with %s, len=%i\n", include, len);
  135. strncpy(processed_inc + pos, ps, len - pos);
  136. processed_inc[len] = 0;
  137. }
  138. else
  139. eprintf("add_raw_include: unhandled include: %s\n", ps);
  140. return add_include(processed_inc);
  141. }
  142. // returns pointer to location after part in string
  143. static const char *substr_end(const char *string, const char *part)
  144. {
  145. const char *p = string;
  146. int len = strlen(part);
  147. while (*p && isspace(*p)) p++;
  148. return (strncmp(p, part, len) == 0) ? (p + len) : NULL;
  149. }
  150. static void strip_cr(char *str)
  151. {
  152. int len = strlen(str);
  153. char *p = str;
  154. while ((p = strchr(p, '\r')))
  155. {
  156. memmove(p, p + 1, len - (p - str) + 1);
  157. }
  158. if (strlen(str) > 0)
  159. {
  160. p = str + strlen(str) - 1;
  161. while (p >= str && isspace(*p)) { *p = 0; p--; } // strip spaces on line ends
  162. }
  163. strcat(str, "\n"); // re-add newline
  164. }
  165. int main(void)
  166. {
  167. char buff[512]; // tmp buffer
  168. char path[128]; // path to file being included, with ending slash
  169. int i, ifile;
  170. FILE *fo;
  171. memset(includes, 0, sizeof(includes));
  172. fo = fopen(OUT_FILE, "w");
  173. if (fo == NULL) return 1;
  174. // special header
  175. fprintf(fo, "#define PICO_INTERNAL static\n");
  176. fprintf(fo, "#define PICO_INTERNAL_ASM\n");
  177. for (ifile = 0; ifile < sizeof(files) / sizeof(files[0]); ifile++)
  178. {
  179. FILE *fi;
  180. const char *file = files[ifile], *p;
  181. p = strrchr(file, '/');
  182. if (p == NULL) eprintf("main: file in root? %s\n", file);
  183. strncpy(path, file, p - file + 1);
  184. path[p - file + 1] = 0;
  185. fi = fopen(file, "r");
  186. if (fi == NULL) eprintf("main: failed to open %s\n", file);
  187. // if (strcmp(file + strlen(file) - 2, ".h") == 0)
  188. add_include(file);
  189. emit_header(fo, file);
  190. while (!feof(fi))
  191. {
  192. p = fgets(buff, sizeof(buff), fi);
  193. if (p == NULL) break;
  194. strip_cr(buff);
  195. // include?
  196. p = substr_end(buff, "#include");
  197. if (p != NULL)
  198. {
  199. p = add_raw_include(p, path);
  200. if (p != NULL) fprintf(fo, "#include %s\n", p);
  201. continue;
  202. }
  203. // passthrough
  204. fputs(buff, fo);
  205. }
  206. }
  207. emit_header(fo, "EOF");
  208. for (i = 0; includes[i] && i < 128; i++)
  209. {
  210. free(includes[i]);
  211. }
  212. fclose(fo);
  213. return 0;
  214. }