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 |
10 | static 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 | |
49 | static char *includes[128]; |
50 | |
51 | static 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 | |
62 | static 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 | |
73 | static 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 | |
101 | static 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 |
159 | static 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 | |
168 | static 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 | |
185 | int 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 | |