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 /* Memory allocation structures */
26 struct pagenode_t;
27 struct pagenode_header_t {
28 struct pagenode_t* next;
29 char* head;
30 };
31 struct pagenode_t {
32 struct pagenode_header_t header;
33 char root[];
34 };
35 struct pagelist_t {
36 struct pagenode_t* root, * head;
37 size_t pagesize;
38 };
39 /* Set link data */
40 enum dtype { FSDAT, MSDAT, ADAT, LDAT, FBDAT };
41 enum ltype { OLINK, MLINK, VLINK, ALINK };
42 struct ir_namelist_t;
43 struct ir_namelist_t
44 { struct ir_namelist_t* nextsib;
45 uint8_t* name;
46 };
47 struct ir_classld_t
48 { struct ir_class_t* root_class;
49 struct ir_namelist_t* namelist, * namelist_head;
50 };
51 struct ir_setld_t
52 { struct ir_classld_t* classld;
53 long long ref;
54 struct ir_namelist_t* namelist, * namelist_head;
55 };
56 /* Set data mem */
57 struct ir_setdata_header_t
58 { enum dtype type;
59 uint8_t* src_filename, * data_name;
60 union ir_setdata_t* nextsib;
61 };
62 struct ir_frameinfo_t
63 { int facing, w, h; };
64 struct ir_framedata_t
65 { struct ir_setdata_header_t header;
66 struct ir_frameinfo_t frameinfo;
67 };
68 struct ir_framebox_t
69 { struct ir_setdata_header_t header;
70 struct ir_framedata_t framesheets[FACING_MAX];
71 struct ir_framedata_t mapsheets[FACING_MAX];
72 };
73 struct ir_simplex_t { struct ir_setdata_header_t header; };
74 struct ir_link_t
75 { struct ir_setdata_header_t header;
76 struct ir_classld_t* classld;
77 struct ir_setld_t* setld;
78 enum ltype type;
79 };
80 union ir_setdata_t
81 { struct ir_setdata_header_t header;
82 struct ir_framebox_t framebox;
83 struct ir_framedata_t framesheet;
84 struct ir_framedata_t mapsheet;
85 struct ir_simplex_t audio;
86 struct ir_link_t link;
87 };
88 struct ir_class_t
89 { struct ir_class_t* nextchild, * nextsib;
90 struct ir_set_t* root_set;
91 uint8_t* name;
92 };
93 struct ir_set_t
94 { struct ir_set_t* nextchild, * nextsib;
95 struct ir_class_t* class;
96 long long ref;
97 uint8_t* name;
98 struct ir_framebox_t* frameboxes;
99 struct ir_simplex_t* audio;
100 struct ir_link_t* links;
101 };
102 /* Functions */
103 static inline
104 int init_pagelist(struct pagelist_t*,size_t);
105 static inline
106 struct ir_framebox_t* ir_set_add_framebox(struct ir_set_t*, uint8_t*);
107 static
108 void ir_free_pagenodes(struct pagenode_t*);
109 static inline
110 int bytes_identical(uint8_t*,uint8_t*);
111 static
112 void* stack_alloc(size_t);
113 static
114 uint8_t* name_alloc(uint8_t*);
115 static inline
116 union ir_setdata_t* ir_framedata (enum dtype,uint8_t*,apc_facing,int,int);
117 /* Function-Like Macros */
118 #define do_warn() do { \
119 } while (0)
120 #define wprint(str) do { \
121 fprintf(stderr, str); \
122 do_warn(); \
123 } while (0)
124 #define wprintf(fmt,...) do { \
125 fprintf(stderr, fmt, __VA_ARGS__); \
126 do_warn(); \
127 } while (0)
128 #define do_error() do { \
129 exit(-1); \
130 } while (0)
131 #define eprint(str) do { \
132 fprintf(stderr, str); \
133 do_error(); \
134 } while (0)
135 #define eprintf(fmt,...) do { \
136 fprintf(stderr, fmt, __VA_ARGS__); \
137 do_error(); \
138 } while (0)
139 #define struct_alloc(_T) ((struct _T*) stack_alloc(sizeof(struct _T)))
140 #define DATA_PAGESIZE (sys_pagesize)
141 #define NAME_PAGESIZE (APC_NAME_MAX * 1024)
142 #define PL_HEADERSIZE (sizeof(struct pagenode_header_t))
143 #define PL_HEADSIZE(_PL) (_PL.head->header.head - _PL.head->root)
144 #define PL_HEADMEM(_PL) (_PL.pagesize - PL_HEADERSIZE - PL_HEADSIZE(_PL))
145 /* Memory */
146 extern //apc.c
147 long sys_pagesize;
148 static
149 struct pagelist_t datapages, namepages;
150 static
151 struct ir_class_t root_class = { .name = (uint8_t*)"." };
152
153 /* Init */
154 int ir_init
155 ( void )
156 { if (init_pagelist(&datapages, (size_t)DATA_PAGESIZE))
157 eprint("Memory allocation error\n");
158 if (init_pagelist(&namepages, (size_t)NAME_PAGESIZE))
159 eprint("Memory allocation error\n");
160 return 0;
161 }
162
163 static inline
164 int init_pagelist
165 ( struct pagelist_t* pl,
166 size_t size
167 )
168 { pl->pagesize = size;
169 pl->root = (struct pagenode_t*) calloc(size,1);
170 if (pl->root == NULL)
171 return -1;
172 pl->root->header.head = pl->root->root;
173 pl->head = pl->root;
174 return 0;
175 }
176
177 /* Quit/Cleanup
178 Recursively clean pagenode linked list
179 */
180 void ir_quit
181 ( void )
182 { ir_free_pagenodes(datapages.root);
183 ir_free_pagenodes(namepages.root);
184 }
185
186 static
187 void ir_free_pagenodes
188 ( struct pagenode_t* pagenode )
189 { if (pagenode->header.next != NULL)
190 ir_free_pagenodes(pagenode->header.next);
191 free(pagenode);
192 }
193
194 /* Link
195 */
196 int ir_linker
197 ( void )
198 { return 0; }
199
200 /* Condense
201 */
202 int ir_condenser
203 ( void )
204 { return 0; }
205
206 /* Return a pointer to the root class */
207 struct ir_class_t* ir_class_root
208 ( void )
209 { return &root_class; }
210
211 /* Add a subclass to a class
212 Attempts to create a new subclass in the provided class, returning
213 the class if it already exists
214 */
215 struct ir_class_t* ir_class_addchild
216 ( struct ir_class_t* class,
217 uint8_t* name
218 )
219 { struct ir_class_t* iter;
220 if (class->nextchild == NULL)
221 return class->nextchild = struct_alloc(ir_class_t);
222 iter = class->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 iter = struct_alloc(ir_class_t);
231 iter->nextsib = class->nextchild;
232 iter->name = name_alloc(name);
233 return class->nextchild = iter;
234 }
235
236 /* Add a set to a class
237 Attempts to create a new root set in the specified class, returning
238 the set if it already exists
239 */
240 struct ir_set_t* ir_class_addset
241 ( struct ir_class_t* class,
242 uint8_t* name
243 )
244 { struct ir_set_t* iter;
245 if (class->root_set == NULL)
246 return class->root_set = struct_alloc(ir_set_t);
247 iter = class->root_set;
248 check:
249 if (bytes_identical(iter->name, name))
250 return iter;
251 if (iter->nextsib != NULL)
252 { iter = iter->nextsib;
253 goto check;
254 }
255 iter = struct_alloc(ir_set_t);
256 iter->nextsib = class->root_set;
257 iter->name = name_alloc(name);
258 return class->root_set = iter;
259 }
260
261 /* Add a set to a set
262 Attempts to create a new subset of the specified set, returning the
263 child if it already exists
264 */
265 struct ir_set_t* ir_set_addchild
266 ( struct ir_set_t* set,
267 uint8_t* name
268 )
269 { struct ir_set_t* iter;
270 if (set->nextchild == NULL)
271 return set->nextchild = struct_alloc(ir_set_t);
272 iter = set->nextchild;
273 check:
274 if (bytes_identical(iter->name, name))
275 return iter;
276 if (iter->nextsib != NULL)
277 { iter = iter->nextsib;
278 goto check;
279 }
280 iter = struct_alloc(ir_set_t);
281 iter->nextsib = set->nextchild;
282 iter->name = name_alloc(name);
283 return set->nextchild = iter;
284 }
285
286 /* Add a framebox to a set
287 Attempts to create a new framebox of the specified set, returning
288 the framebox if it already exists
289 */
290 static inline
291 struct ir_framebox_t* ir_set_add_framebox
292 ( struct ir_set_t* set,
293 uint8_t* name
294 )
295 { struct ir_framebox_t* iter;
296 if (set->frameboxes == NULL)
297 return set->frameboxes = struct_alloc(ir_framebox_t);
298 iter = set->frameboxes;
299 check:
300 if (bytes_identical(iter->header.data_name, name))
301 return iter;
302 if (iter->header.nextsib != NULL)
303 { iter = (struct ir_framebox_t*) iter->header.nextsib;
304 goto check;
305 }
306 iter = struct_alloc(ir_framebox_t);
307 iter->header.nextsib = (union ir_setdata_t*) set->frameboxes;
308 iter->header.data_name = name_alloc(name);
309 return set->frameboxes = iter;
310 }
311
312 /* Match two null-terminated bytestrings
313 Return 1 if the two bytestrings are identical, else 0
314 */
315 static inline
316 int bytes_identical
317 ( uint8_t* stra,
318 uint8_t* strb
319 )
320 { int ca, cb;
321 do {
322 ca = *stra++;
323 cb = *strb++;
324 } while (ca && ca == cb);
325 return (ca == cb);
326 }
327
328 /* Assign Setdata to Set
329
330 */
331 void ir_set_assign_data
332 ( struct ir_set_t* set,
333 union ir_setdata_t* setdata
334 )
335 { struct ir_framebox_t* framebox;
336 struct ir_simplex_t* simplex;
337 switch (setdata->header.type)
338 { case FSDAT:
339 framebox = ir_set_add_framebox(set, setdata->header.data_name);
340 if (framebox->framesheets[setdata->framesheet.frameinfo.facing].header.data_name != NULL)
341 wprintf("Duplicate framesheet [%i] %s\n",
342 setdata->framesheet.frameinfo.facing, setdata->header.data_name);
343 framebox->framesheets[setdata->framesheet.frameinfo.facing] = setdata->framesheet;
344 break;
345 case MSDAT:
346 framebox = ir_set_add_framebox(set, setdata->header.data_name);
347 if (framebox->mapsheets[setdata->mapsheet.frameinfo.facing].header.data_name != NULL)
348 wprintf("Duplicate mapsheet [%i] %s\n",
349 setdata->mapsheet.frameinfo.facing, setdata->header.data_name);
350 framebox->mapsheets[setdata->mapsheet.frameinfo.facing] = setdata->mapsheet;
351 break;
352 case ADAT:
353 if (set->audio == NULL)
354 { set->audio = (struct ir_simplex_t*) setdata;
355 return;
356 }
357 simplex = set->audio;
358 while (simplex->header.nextsib != NULL)
359 if (bytes_identical(simplex->header.data_name, setdata->header.data_name))
360 { wprintf("Duplicate audio %s\n", setdata->header.data_name);
361 *simplex = setdata->audio;
362 //setdata is now a pointer to redundant, unused memory.
363 return;
364 }
365 else
366 simplex = (struct ir_simplex_t*) simplex->header.nextsib;
367 setdata->audio.header.nextsib = (union ir_setdata_t*) set->audio;
368 set->audio = (struct ir_simplex_t*) setdata;
369 break;
370 case LDAT:
371 setdata->link.header.nextsib = (union ir_setdata_t*) set->links;
372 set->links = (struct ir_link_t*) setdata;
373 break;
374 default:
375 fprintf(stderr, "Unknown setdata type %x\n", setdata->header.type);
376 exit(-1);
377 }
378 }
379
380 void ir_set_assign_ref
381 ( struct ir_set_t* set,
382 long long ref
383 )
384 { if (set->ref != 0)
385 wprintf("Ref override: 0x%lx -> 0x%lx for set %s\n",
386 (long unsigned) set->ref, (long unsigned) ref, set->name);
387 set->ref = ref;
388 //TODO: reflist_add(set);
389 }
390
391 void ir_data_assign_path
392 ( union ir_setdata_t* setdata,
393 uint8_t* path
394 )
395 { if (setdata->header.src_filename != NULL)
396 wprintf("Path override: %s -> %s for setdata %s\n",
397 setdata->header.src_filename, path, setdata->header.data_name);
398 setdata->header.src_filename = name_alloc(path);
399 }
400
401 union ir_setdata_t* ir_framesheet
402 ( uint8_t* name,
403 apc_facing d,
404 int width,
405 int height
406 )
407 { return ir_framedata(FSDAT, name, d, width, height); }
408
409 union ir_setdata_t* ir_mapsheet
410 ( uint8_t* name,
411 apc_facing d,
412 int width,
413 int height
414 )
415 { return ir_framedata(MSDAT, name, d, width, height); }
416
417 static inline
418 union ir_setdata_t* ir_framedata
419 ( enum dtype type,
420 uint8_t* name,
421 apc_facing d,
422 int width,
423 int height
424 )
425 { struct ir_framedata_t* framedata = struct_alloc(ir_framedata_t);
426 framedata->header.type = type;
427 framedata->header.data_name = name_alloc(name);
428 framedata->frameinfo.facing = d;
429 framedata->frameinfo.w = width;
430 framedata->frameinfo.h = height;
431 return (union ir_setdata_t*) framedata;
432 }
433
434 union ir_setdata_t* ir_audio
435 ( uint8_t* name )
436 { struct ir_simplex_t* audio = struct_alloc(ir_simplex_t);
437 audio->header.type = ADAT;
438 audio->header.data_name = name_alloc(name);
439 return (union ir_setdata_t*) audio;
440 }
441
442
443 /* Create classld that points to a class */
444 struct ir_classld_t* ir_classld_from_class
445 ( struct ir_class_t* class )
446 { struct ir_classld_t* classld;
447 classld = struct_alloc(ir_classld_t);
448 classld->root_class = class;
449 return classld;
450 }
451
452 struct ir_setld_t* ir_setld_from_ref
453 ( long long ref )
454 { struct ir_setld_t* setld;
455 setld = struct_alloc(ir_setld_t);
456 setld->ref = ref;
457 return setld;
458 }
459
460 struct ir_setld_t* ir_setld_from_classld
461 ( struct ir_classld_t* classld,
462 uint8_t* name
463 )
464 { struct ir_setld_t* setld;
465 setld = struct_alloc(ir_setld_t);
466 setld->namelist = struct_alloc(ir_namelist_t);
467 setld->namelist_head = setld->namelist;
468 setld->namelist_head->name = name_alloc(name);
469 setld->classld = classld;
470 return setld;
471 }
472
473 struct ir_setld_t* ir_setld_addchild
474 ( struct ir_setld_t* setld,
475 uint8_t* name
476 )
477 { if (setld->namelist == NULL)
478 { setld->namelist = struct_alloc(ir_namelist_t);
479 setld->namelist_head = setld->namelist;
480 }
481 else
482 { setld->namelist_head->nextsib = struct_alloc(ir_namelist_t);
483 setld->namelist_head = setld->namelist_head->nextsib;
484 }
485 setld->namelist_head->name = name_alloc(name);
486 return setld;
487 }
488
489 union ir_setdata_t* ir_link
490 ( enum ltype link_type,
491 struct ir_setld_t* setld,
492 uint8_t* name
493 )
494 { struct ir_link_t* link;
495 link = struct_alloc(ir_link_t);
496 link->header.type = LDAT;
497 link->type = link_type;
498 link->classld = setld->classld;
499 link->setld = setld;
500 if (link_type != OLINK && name != NULL)
501 link->header.data_name = name_alloc(name);
502 return (union ir_setdata_t*) link;
503 }
504
505
506 static
507 void* stack_alloc
508 ( size_t bytes )
509 { if (!bytes) //valid behavior to attain current head
510 return datapages.head->header.head;
511 if (PL_HEADMEM(datapages) < bytes)
512 { datapages.head->header.next = (struct pagenode_t*) calloc(datapages.pagesize,1);
513 if (datapages.head->header.next == NULL)
514 eprint("Memory allocation error \n");
515 datapages.head = datapages.head->header.next;
516 datapages.head->header.head = datapages.head->root;
517 }
518 datapages.head->header.head += bytes;
519 return (void*) datapages.head->header.head - bytes;
520 }
521
522 static
523 uint8_t* name_alloc
524 ( uint8_t* name_src )
525 { uint8_t* iter, * name;
526 int head_mem;
527 copy:
528 name = (uint8_t*)namepages.head->header.head;
529 iter = name_src;
530 for (head_mem = PL_HEADMEM(namepages); *iter && head_mem; head_mem--)
531 *(namepages.head->header.head)++ = *iter++;
532 if (head_mem == 0) //not enough room
533 { namepages.head->header.next = (struct pagenode_t*) calloc(namepages.pagesize,1);
534 if (namepages.head->header.next == NULL)
535 eprint("Memory allocation error\n");
536 namepages.head = namepages.head->header.next;
537 namepages.head->header.head = namepages.head->root;
538 goto copy;
539 }
540 *(namepages.head->header.head)++ = '\0';
541 return name;
542 }