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