fixes
[henge/apc.git] / src / ir.c
1 /*!@file
2 \brief IR Memory Implementation
3 \details Intermediary memory management
4 \author Jordan Lavatai
5 \date Aug 2016
6 ----------------------------------------------------------------------------*/
7 /* Standard */
8 #include <stdlib.h> //exit, malloc
9 #include <stdio.h> //print
10 #include <stdarg.h> //va_args
11 #include <stdint.h> //uint64_t
12 #include <string.h> //memset, str*
13 /* Unicode */
14 #include <unistd.h> //u8_* functions
15 #include <unitypes.h> //uint8_t as a char
16 #include <unistr.h> //u32_cpy
17 /* Local */
18 #include "apc.h"
19 #include "ir.h"
20 /* Public */
21 int ir_init(void);
22 void ir_quit(void);
23 int ir_linker(void);
24 int ir_condenser(void);
25 /* Private */
26 extern //apc.c
27 long sys_pagesize;
28 static
29
30 static inline
31 struct ir_framebox_t* ir_set_add_framebox(struct ir_set_t*, uint8_t*);
32 static
33 void ir_free_pages(struct pagenode_t*);
34 static inline
35 int bytes_identical(uint8_t*,uint8_t*);
36 static
37 void* stack_alloc(size_t);
38 /* Memory allocator */
39 struct pagenode_t {
40 struct pagenode_t* next;
41 char* head;
42 char root[];
43 }* pagenode_root, * pagenode_head;
44 #define PN_ALLOCSIZE (sys_pagesize)
45 #define PN_HEADERSIZE() (sizeof(struct pagenode_t*) + sizeof(char*))
46 #define PN_MEMSIZE() (PN_ALLOCSIZE - PN_HEADERSIZE())
47 #define PN_HEADSIZE() (pagenode_head->head - pagenode_head->root)
48 #define PN_HEADSPACE() (PN_MEMSIZE() - PN_HEADSIZE())
49 /* Enumerated types */
50 enum dtype { FSDAT, MSDAT, ADAT, LDAT, FBDAT };
51 enum ltype { OLINK, MLINK, VLINK, ALINK };
52 /* Set data mem */
53 struct ir_setdata_header_t
54 { enum dtype type;
55 uint8_t* src_filename, * data_name;
56 union ir_setdata_t* nextsib;
57 };
58 struct ir_frameinfo_t
59 { int facing, w, h; };
60 struct ir_framedata_t
61 { struct ir_setdata_header_t header;
62 struct ir_frameinfo_t frameinfo;
63 }** framedatas;
64 struct ir_framebox_t
65 { struct ir_setdata_header_t header;
66 struct ir_framedata_t framesheets[FACING_MAX];
67 struct ir_framedata_t mapsheets[FACING_MAX];
68 }** frameboxes;
69 struct ir_simplex_t
70 { struct ir_setdat_header_t header;
71 }** simplexes;
72 struct ir_link_t
73 { struct ir_setdat_header_t header;
74 struct ir_set_t* src, * trg;
75 enum ltype type;
76 }** links;
77 union ir_setdata_t
78 { struct ir_setdata_header_t header;
79 struct ir_framebox_t framebox;
80 struct ir_framedata_t framesheet;
81 struct ir_framedata_t mapsheet;
82 struct ir_simplex_t audio;
83 struct ir_link_t link;
84 };
85 struct ir_class_t
86 { struct ir_class_t* nextchild, * nextsib;
87 struct ir_set_t* root_set;
88 uint8_t* name;
89 }** classes;
90 struct ir_set_t
91 { struct ir_set_t* nextchild, * nextsib;
92 struct ir_class_t* class;
93 long long ref;
94 uint8_t* name;
95 struct framebox_t* frameboxes;
96 struct simplex_t* audio;
97 struct link_t* links;
98 }** sets;
99 /* Function-Like Macros */
100 #define do_warn() do { \
101 } while (0)
102 #define wprint(str) do { \
103 fprintf(stderr, str); \
104 do_warn(); \
105 } while (0)
106 #define wprintf(fmt,...) do { \
107 fprintf(stderr, fmt, __VA_ARGS__); \
108 do_warn(); \
109 } while (0)
110 #define do_error() do { \
111 exit(-1); \
112 } while (0)
113 #define eprint(str) do { \
114 fprintf(stderr, str); \
115 do_error(); \
116 } while (0)
117 #define eprintf(fmt,...) do { \
118 fprintf(stderr, fmt, __VA_ARGS__); \
119 do_error(); \
120 } while (0)
121 #define struct_alloc(_T) ((struct _T*) stack_alloc(sizeof(struct _T)))
122
123
124 static
125 struct ir_class_t root_class = { .name = "." };
126
127 /* Init */
128 int ir_init
129 ( void )
130 { pagenode_root = calloc(struct pagenode_t*) calloc(PN_ALLOCSIZE);
131 if (pagenode_root == NULL)
132 return -1;
133 pagenode_root->head = pagenode_root->root;
134 pagenode_head = pagenode_root;
135 return 0;
136 }
137
138 /* Quit/Cleanup
139 Recursively clean pagenode linked list
140 */
141 void ir_quit
142 ( void )
143 { ir_free_pages(pagenode_root); }
144
145 static
146 void ir_free_pages
147 ( struct pagenode_t* pagenode )
148 { if (pagenode->next != NULL)
149 ir_free_pages(pagenode->next);
150 free(pagenode);
151 }
152
153 /* Link
154 */
155 int ir_linker
156 ( void )
157 { return 0; }
158
159 /* Condense
160 */
161 int ir_condenser
162 ( void )
163 { return 0; }
164
165 /* Return a pointer to the root class */
166 struct ir_class_t* ir_class_root
167 ( void )
168 { return &root_class; }
169
170 /* Add a subclass to a class
171 Attempts to create a new subclass in the provided class, returning
172 the class if it already exists
173 */
174 struct ir_class_t* ir_class_addchild
175 ( struct ir_class_t* class,
176 uint8_t* name
177 )
178 { struct ir_class_t* iter;
179 if (class->nextchild == NULL)
180 return class->nextchild = struct_alloc(ir_class_t);
181 iter = class->nextchild;
182 check:
183 if (bytes_identical(iter->name, name))
184 return iter;
185 if (iter->nextsib != NULL)
186 { iter = iter->nextsib;
187 goto check;
188 }
189 return iter->nextsib = struct_alloc(ir_class_t);
190 }
191
192 /* Add a set to a class
193 Attempts to create a new root set in the specified class, returning
194 the set if it already exists
195 */
196 struct ir_set_t* ir_class_addset
197 ( struct ir_class_t* class,
198 uint8_t* name
199 )
200 { struct ir_set_t* iter;
201 if (class->root_set == NULL)
202 return class->root_set = struct_alloc(ir_set_t);
203 iter = class->root_set;
204 check:
205 if (bytes_identical(iter->name, name))
206 return iter;
207 if (iter->nextsib != NULL)
208 { iter = iter->nextsib;
209 goto check;
210 }
211 return iter->nextsib = struct_alloc(ir_set_t);
212 }
213
214 /* Add a set to a set
215 Attempts to create a new subset of the specified set, returning the
216 child if it already exists
217 */
218 struct ir_set_t* ir_set_addchild
219 ( struct ir_set_t* set,
220 uint8_t* name
221 )
222 { struct ir_set_t* iter;
223 if (set->nextchild == NULL)
224 return set->nextchild = struct_alloc(ir_set_t);
225 iter = set->nextchild;
226 check:
227 if (bytes_identical(iter->name, name))
228 return iter;
229 if (iter->nextsib != NULL)
230 { iter = iter->nextsib;
231 goto check;
232 }
233 return iter->nextsib = struct_alloc(ir_set_t);
234 }
235
236 /* Add a framebox to a set
237 Attempts to create a new framebox of the specified set, returning
238 the framebox if it already exists
239 */
240 static inline
241 struct ir_framebox_t* ir_set_add_framebox
242 ( struct ir_set_t* set,
243 uint8_t* name
244 )
245 { struct ir_framebox_t* iter;
246 if (set->frameboxes == NULL)
247 return set->frameboxes = struct_alloc(ir_framebox_t);
248 iter = set->frameboxes;
249 check:
250 if (bytes_identical(iter->header.name, name))
251 return iter;
252 if (iter->header.nextsib != NULL)
253 { iter = iter->header.nextsib;
254 goto check;
255 }
256 return iter->header.nextsib = struct_alloc(ir_framebox_t);
257 }
258
259 /* Match two null-terminated bytestrings
260 Return 1 if the two bytestrings are identical, else 0
261 */
262 static inline
263 int bytes_identical
264 ( uint8_t* stra,
265 uint8_t* strb
266 )
267 { while (*stra && *strb)
268 if (*stra++ != *strb++)
269 return 0;
270 return *stra == *strb;
271 }
272
273 /* Assign Setdata to Set
274
275 */
276 void ir_set_assign_data
277 ( struct ir_set_t* set,
278 union ir_setdata_t* setdata
279 )
280 { struct ir_framebox_t* framebox;
281 struct ir_simplex_t* simplex;
282 struct ir_link_t* link;
283 switch (setdata->header.type)
284 { case FSDAT:
285 framebox = ir_set_add_framebox(set, setdata->header.name);
286 if (framebox->framesheets[setdata->framesheet.frameinfo.facing] != NULL)
287 wprintf("Duplicate framesheet [%i] %s\n",
288 setdata->framesheet.frameinfo.facing, setdata->header.data_name);
289 framebox->framesheets[setdata->framesheet.frameinfo.facing] = setdata->framesheet;
290 break;
291 case MSDAT:
292 framebox = ir_set_add_framebox(set, setdata->header.name);
293 if (framebox->mapsheets[setdata->mapsheet.frameinfo.facing] != NULL)
294 wprintf("Duplicate mapsheet [%i] %s\n",
295 setdata->mapsheet.frameinfo.facing, setdata->header.data_name);
296 framebox->mapsheets[setdata->mapsheet.frameinfo.facing] = setdata->mapsheet;
297 break;
298 case ADAT:
299 if (set->audio == NULL)
300 { set->audio = &setdata->audio;
301 return;
302 }
303 simplex = set->audio;
304 while (simplex->header.nextsib != NULL;)
305 if (bytes_identical(simplex->header.data_name, setdata->header.data_name))
306 { wprintf("Duplicate audio %s\n", setdata->header.data_name);
307 *simplex = setdata->audio;
308 return;
309 }
310 else
311 simplex = simplex->header.nextsib;
312 simplex->header.nextsib = &setdata->audio;
313 break;
314 case LDAT:
315 if (set->links == NULL)
316 { set->links = &setdata->link;
317 return;
318 }
319 link = set->links;
320 while (link->header.nextsib != NULL)
321 link = link->header.nextsib;
322 link->header.nextsib = &setdata->link;
323 break;
324 default:
325 fprintf(stderr, "Unknown setdata type %x\n", setdata->header.type);
326 exit(-1);
327 }
328 }
329
330 void ir_set_assign_ref
331 ( ir_set_t* set,
332 long long ref
333 )
334 { if (set->ref != 0)
335 wprintf("Ref override: 0x%x -> 0x%x for set %s\n",
336 set->ref, ref, set->name);
337 set->ref = ref;
338 //TODO: reflist_add(set);
339 }
340
341 void ir_data_assign_path
342 ( union ir_setdata_t* setdata,
343 uint8_t* path
344 )
345 { if (set->header.src_filename)
346 wprintf("Path override: %s -> %s for set %s\n",
347 set->header.src_filename, path, set->name);
348 set->header.src_filename = path;
349 //TODO: internal strdup, not assign (= path;)
350 }
351
352
353 //TODO: Macro ir_framsheet and mapsheet?
354 union ir_setdata_t* ir_framesheet
355 ( uint8_t* name,
356 apc_facing d,
357 int width,
358 int height
359 )
360 { struct ir_framedata_t* framesheet = struct_alloc(ir_framedata_t);
361 framesheet->header->type = FSDAT;
362 framesheet->header.data_name = name;
363 framesheet->frameinfo.facing = d;
364 framesheet->frameinfo.w = width;
365 framesheet->frameinfo.h = height;
366 return (union ir_setdata_t*) framesheet;
367 }
368
369 union ir_setdata_t* ir_mapsheet
370 ( uint8_t* name,
371 apc_facing d,
372 int width,
373 int height,
374 )
375 { struct ir_framedata_t* mapsheet = struct_alloc(ir_framedata_t);
376 mapsheet->header.type = MSDAT;
377 mapsheet->header.data_name = name;
378 mapsheet->frameinfo.facing = d;
379 mapsheet->frameinfo.w = width;
380 mapsheet->frameinfo.h = height;
381 return (union ir_setdata_t*) mapsheet;
382 }
383
384 union ir_setdata_t* ir_audio
385 ( uint8_t* name )
386 { struct ir_simplex_t* audio = struct_alloc(ir_simplex_t);
387 audio->header.type = ADAT;
388 audio->header.data_name = name;
389 return (union ir_setdata_t*) audio;
390 }
391
392 static
393 void* stack_alloc(size_t bytes)
394 { if (!bytes)
395 { wprint("Attempting to allocate 0 bytes in stack_alloc");
396 return pagenode_head->head;
397 }
398 if (PN_HEADSPACE() < bytes)
399 { pagenode_head->next = (struct pagenode_t*) calloc(PN_ALLOCSIZE);
400 pagenode_head = pagenode_head->next;
401 pagenode_head->head = pagenode_head->root;
402 }
403 pagenode_head->head += bytes;
404 return (void*) pagenode_head->head - bytes;
405 }
406