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