simplify gitignore
[vg.git] / dep / stb / stb_include.h
1 // stb_include.h - v0.02 - parse and process #include directives - public domain
2 //
3 // To build this, in one source file that includes this file do
4 // #define STB_INCLUDE_IMPLEMENTATION
5 //
6 // This program parses a string and replaces lines of the form
7 // #include "foo"
8 // with the contents of a file named "foo". It also embeds the
9 // appropriate #line directives. Note that all include files must
10 // reside in the location specified in the path passed to the API;
11 // it does not check multiple directories.
12 //
13 // If the string contains a line of the form
14 // #inject
15 // then it will be replaced with the contents of the string 'inject' passed to the API.
16 //
17 // Options:
18 //
19 // Define STB_INCLUDE_LINE_GLSL to get GLSL-style #line directives
20 // which use numbers instead of filenames.
21 //
22 // Define STB_INCLUDE_LINE_NONE to disable output of #line directives.
23 //
24 // Standard libraries:
25 //
26 // stdio.h FILE, fopen, fclose, fseek, ftell
27 // stdlib.h malloc, realloc, free
28 // string.h strcpy, strncmp, memcpy
29 //
30 // Credits:
31 //
32 // Written by Sean Barrett.
33 //
34 // Fixes:
35 // Michal Klos
36
37 #ifndef STB_INCLUDE_STB_INCLUDE_H
38 #define STB_INCLUDE_STB_INCLUDE_H
39
40 // Do include-processing on the string 'str'. To free the return value, pass it to free()
41 char *stb_include_string(char *str, char *inject, char *path_to_includes, char *filename_for_line_directive, char error[256]);
42
43 // Concatenate the strings 'strs' and do include-processing on the result. To free the return value, pass it to free()
44 char *stb_include_strings(char **strs, int count, char *inject, char *path_to_includes, char *filename_for_line_directive, char error[256]);
45
46 // Load the file 'filename' and do include-processing on the string therein. note that
47 // 'filename' is opened directly; 'path_to_includes' is not used. To free the return value, pass it to free()
48 char *stb_include_file(char *filename, char *inject, char *path_to_includes, char error[256]);
49
50 #endif
51
52
53 #ifdef STB_INCLUDE_IMPLEMENTATION
54
55 #include <stdio.h>
56 #include <string.h>
57
58 #ifndef STB_MALLOC
59 #define STB_STDLIB
60 #define STB_MALLOC malloc
61 #endif
62
63 #ifndef STB_FREE
64 #define STB_STDLIB
65 #define STB_FREE free
66 #endif
67
68 #ifndef STB_REALLOC
69 #define STB_STDLIB
70 #define STB_REALLOC realloc
71 #endif
72
73 #ifdef STB_STDLIB
74 #include <stdlib.h>
75 #endif
76
77 static char *stb_include_load_file(char *filename, size_t *plen)
78 {
79 char *text;
80 size_t len;
81 FILE *f = fopen(filename, "rb");
82 if (f == 0) return 0;
83 fseek(f, 0, SEEK_END);
84 len = (size_t) ftell(f);
85 if (plen) *plen = len;
86 text = (char *) STB_MALLOC(len+1);
87 if (text == 0) return 0;
88 fseek(f, 0, SEEK_SET);
89 fread(text, 1, len, f);
90 fclose(f);
91 text[len] = 0;
92 return text;
93 }
94
95 typedef struct
96 {
97 int offset;
98 int end;
99 char *filename;
100 int next_line_after;
101 } include_info;
102
103 static include_info *stb_include_append_include(include_info *array, int len, int offset, int end, char *filename, int next_line)
104 {
105 include_info *z = (include_info *)STB_REALLOC(array, sizeof(*z) * (len+1));
106 z[len].offset = offset;
107 z[len].end = end;
108 z[len].filename = filename;
109 z[len].next_line_after = next_line;
110 return z;
111 }
112
113 static void stb_include_free_includes(include_info *array, int len)
114 {
115 int i;
116 for (i=0; i < len; ++i)
117 STB_FREE(array[i].filename);
118 STB_FREE(array);
119 }
120
121 static int stb_include_isspace(int ch)
122 {
123 return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
124 }
125
126 // find location of all #include and #inject
127 static int stb_include_find_includes(char *text, include_info **plist)
128 {
129 int line_count = 1;
130 int inc_count = 0;
131 char *s = text, *start;
132 include_info *list = NULL;
133 while (*s) {
134 // parse is always at start of line when we reach here
135 start = s;
136 while (*s == ' ' || *s == '\t')
137 ++s;
138 if (*s == '#') {
139 ++s;
140 while (*s == ' ' || *s == '\t')
141 ++s;
142 if (0==strncmp(s, "include", 7) && stb_include_isspace(s[7])) {
143 s += 7;
144 while (*s == ' ' || *s == '\t')
145 ++s;
146 if (*s == '"') {
147 char *t = ++s;
148 while (*t != '"' && *t != '\n' && *t != '\r' && *t != 0)
149 ++t;
150 if (*t == '"') {
151 char *filename = (char *) STB_MALLOC(t-s+1);
152 memcpy(filename, s, t-s);
153 filename[t-s] = 0;
154 s=t;
155 while (*s != '\r' && *s != '\n' && *s != 0)
156 ++s;
157 // s points to the newline, so s-start is everything except the newline
158 list = stb_include_append_include(list, inc_count++, start-text, s-text, filename, line_count+1);
159 }
160 }
161 } else if (0==strncmp(s, "inject", 6) && (stb_include_isspace(s[6]) || s[6]==0)) {
162 while (*s != '\r' && *s != '\n' && *s != 0)
163 ++s;
164 list = stb_include_append_include(list, inc_count++, start-text, s-text, NULL, line_count+1);
165 }
166 }
167 while (*s != '\r' && *s != '\n' && *s != 0)
168 ++s;
169 if (*s == '\r' || *s == '\n') {
170 s = s + (s[0] + s[1] == '\r' + '\n' ? 2 : 1);
171 }
172 ++line_count;
173 }
174 *plist = list;
175 return inc_count;
176 }
177
178 // avoid dependency on sprintf()
179 static void stb_include_itoa(char str[9], int n)
180 {
181 int i;
182 for (i=0; i < 8; ++i)
183 str[i] = ' ';
184 str[i] = 0;
185
186 for (i=1; i < 8; ++i) {
187 str[7-i] = '0' + (n % 10);
188 n /= 10;
189 if (n == 0)
190 break;
191 }
192 }
193
194 static char *stb_include_append(char *str, size_t *curlen, char *addstr, size_t addlen)
195 {
196 str = (char *)STB_REALLOC(str, *curlen + addlen);
197 memcpy(str + *curlen, addstr, addlen);
198 *curlen += addlen;
199 return str;
200 }
201
202 char *stb_include_string(char *str, char *inject, char *path_to_includes, char *filename, char error[256])
203 {
204 char temp[4096];
205 include_info *inc_list;
206 int i, num = stb_include_find_includes(str, &inc_list);
207 size_t source_len = strlen(str);
208 char *text=0;
209 size_t textlen=0, last=0;
210 for (i=0; i < num; ++i) {
211 text = stb_include_append(text, &textlen, str+last, inc_list[i].offset - last);
212 // write out line directive for the include
213 #ifndef STB_INCLUDE_LINE_NONE
214 #ifdef STB_INCLUDE_LINE_GLSL
215 if (textlen != 0) // GLSL #version must appear first, so don't put a #line at the top
216 #endif
217 {
218 strcpy(temp, "#line ");
219 stb_include_itoa(temp+6, 1);
220 strcat(temp, " ");
221 #ifdef STB_INCLUDE_LINE_GLSL
222 stb_include_itoa(temp+15, i+1);
223 #else
224 strcat(temp, "\"");
225 if (inc_list[i].filename == 0)
226 strcmp(temp, "INJECT");
227 else
228 strcat(temp, inc_list[i].filename);
229 strcat(temp, "\"");
230 #endif
231 strcat(temp, "\n");
232 text = stb_include_append(text, &textlen, temp, strlen(temp));
233 }
234 #endif
235 if (inc_list[i].filename == 0) {
236 if (inject != 0)
237 text = stb_include_append(text, &textlen, inject, strlen(inject));
238 } else {
239 char *inc;
240 strcpy(temp, path_to_includes);
241 strcat(temp, "/");
242 strcat(temp, inc_list[i].filename);
243 inc = stb_include_file(temp, inject, path_to_includes, error);
244 if (inc == NULL) {
245 stb_include_free_includes(inc_list, num);
246 return NULL;
247 }
248 text = stb_include_append(text, &textlen, inc, strlen(inc));
249 STB_FREE(inc);
250 }
251 // write out line directive
252 #ifndef STB_INCLUDE_LINE_NONE
253 strcpy(temp, "\n#line ");
254 stb_include_itoa(temp+6, inc_list[i].next_line_after);
255 strcat(temp, " ");
256 #ifdef STB_INCLUDE_LINE_GLSL
257 stb_include_itoa(temp+15, 0);
258 #else
259 strcat(temp, filename != 0 ? filename : "source-file");
260 #endif
261 text = stb_include_append(text, &textlen, temp, strlen(temp));
262 // no newlines, because we kept the #include newlines, which will get appended next
263 #endif
264 last = inc_list[i].end;
265 }
266 text = stb_include_append(text, &textlen, str+last, source_len - last + 1); // append '\0'
267 stb_include_free_includes(inc_list, num);
268 return text;
269 }
270
271 char *stb_include_strings(char **strs, int count, char *inject, char *path_to_includes, char *filename, char error[256])
272 {
273 char *text;
274 char *result;
275 int i;
276 size_t length=0;
277 for (i=0; i < count; ++i)
278 length += strlen(strs[i]);
279 text = (char *) STB_MALLOC(length+1);
280 length = 0;
281 for (i=0; i < count; ++i) {
282 strcpy(text + length, strs[i]);
283 length += strlen(strs[i]);
284 }
285 result = stb_include_string(text, inject, path_to_includes, filename, error);
286 STB_FREE(text);
287 return result;
288 }
289
290 char *stb_include_file(char *filename, char *inject, char *path_to_includes, char error[256])
291 {
292 size_t len;
293 char *result;
294 char *text = stb_include_load_file(filename, &len);
295 if (text == NULL) {
296 strcpy(error, "Error: couldn't load '");
297 strcat(error, filename);
298 strcat(error, "'");
299 return 0;
300 }
301 result = stb_include_string(text, inject, path_to_includes, filename, error);
302 STB_FREE(text);
303 return result;
304 }
305
306 #if 0 // @TODO, GL_ARB_shader_language_include-style system that doesn't touch filesystem
307 char *stb_include_preloaded(char *str, char *inject, char *includes[][2], char error[256])
308 {
309
310 }
311 #endif
312
313 #endif // STB_INCLUDE_IMPLEMENTATION