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