debugging support
[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 #include <unistdio.h> //ulc_fprintf
18 /* Local */
19 #include "print.h"
20 #include "apc.h"
21 #include "ir.h"
22 #undef do_error
23 #define do_error(...) exit(-1)
24 /* Public */
25 int ir_init(void);
26 void ir_quit(void);
27 int ir_linker(void);
28 int ir_condenser(void);
29 /* Memory allocation structures */
30 struct pagenode_t;
31 struct pagenode_header_t {
32 struct pagenode_t* next;
33 char* head;
34 };
35 struct pagenode_t {
36 struct pagenode_header_t header;
37 char root[];
38 };
39 struct pagelist_t {
40 struct pagenode_t* root, * head;
41 size_t pagesize;
42 };
43 #define DATA_PAGESIZE (sys_pagesize)
44 #define NAME_PAGESIZE (APC_NAME_MAX * 1024)
45 #define PL_HEADERSIZE (sizeof(struct pagenode_header_t))
46 #define PL_HEADSIZE(_PL) (_PL.head->header.head - _PL.head->root)
47 #define PL_HEADMEM(_PL) (_PL.pagesize - PL_HEADERSIZE - PL_HEADSIZE(_PL))
48 /* Set data mem */
49 enum dtype { FSDAT, MSDAT, ADAT, LDAT, FBDAT };
50 struct ir_namelist_t;
51 struct ir_namelist_t
52 { struct ir_namelist_t* nextsib;
53 uint8_t* name;
54 };
55 struct ir_classld_t
56 { struct ir_class_t* root_class;
57 struct ir_namelist_t* namelist, * namelist_head;
58 };
59 struct ir_setld_t
60 { struct ir_classld_t* classld;
61 long long ref;
62 struct ir_namelist_t* namelist, * namelist_head;
63 };
64 struct ir_setdata_header_t
65 { enum dtype type;
66 uint8_t* src_filename, * data_name;
67 union ir_setdata_t* nextsib;
68 };
69 struct ir_frameinfo_t
70 { int facing, w, h; };
71 struct ir_framedata_t
72 { struct ir_setdata_header_t header;
73 struct ir_frameinfo_t frameinfo;
74 };
75 struct ir_framebox_t
76 { struct ir_setdata_header_t header;
77 struct ir_framedata_t framesheets[FACING_MAX];
78 struct ir_framedata_t mapsheets[FACING_MAX];
79 };
80 struct ir_simplex_t { struct ir_setdata_header_t header; };
81 struct ir_link_t
82 { struct ir_setdata_header_t header;
83 struct ir_classld_t* classld;
84 struct ir_setld_t* setld;
85 enum ltype type;
86 };
87 union ir_setdata_t
88 { struct ir_setdata_header_t header;
89 struct ir_framebox_t framebox;
90 struct ir_framedata_t framesheet;
91 struct ir_framedata_t mapsheet;
92 struct ir_simplex_t audio;
93 struct ir_link_t link;
94 };
95 struct ir_class_t
96 { struct ir_class_t* nextchild, * nextsib;
97 struct ir_set_t* root_set;
98 uint8_t* name;
99 };
100 struct ir_set_t
101 { struct ir_set_t* nextchild, * nextsib;
102 struct ir_class_t* class;
103 long long ref;
104 uint8_t* name;
105 struct ir_framebox_t* frameboxes;
106 struct ir_simplex_t* audio;
107 struct ir_link_t* links;
108 };
109 /* Functions */
110 static inline
111 struct ir_framebox_t* ir_set_add_framebox(struct ir_set_t*,const uint8_t*);
112 static inline
113 union ir_setdata_t* ir_framedata (enum dtype,const uint8_t*,apc_facing,int,int);
114 static inline
115 int init_pagelist(struct pagelist_t*,size_t);
116 static
117 void ir_free_pagenodes(struct pagenode_t*);
118 static inline
119 int bytes_identical(const uint8_t*,const uint8_t*);
120 static
121 void* stack_alloc(size_t);
122 #define struct_alloc(_T) ((struct _T*) stack_alloc(sizeof(struct _T)))
123 static
124 uint8_t* name_alloc(const uint8_t*);
125 extern //apc.c
126 long sys_pagesize;
127 static
128 struct pagelist_t datapages, namepages;
129 static
130 struct ir_class_t root_class = { .name = (uint8_t*)"." };
131
132 /* Init */
133 int ir_init
134 ( void )
135 { if (init_pagelist(&datapages, (size_t)DATA_PAGESIZE))
136 eprintf("Memory allocation error\n");
137 if (init_pagelist(&namepages, (size_t)NAME_PAGESIZE))
138 eprintf("Memory allocation error\n");
139 return 0;
140 }
141
142 static inline
143 int init_pagelist
144 ( struct pagelist_t* pl,
145 size_t size
146 )
147 { pl->pagesize = size;
148 pl->root = (struct pagenode_t*) calloc(size,1);
149 if (pl->root == NULL)
150 return -1;
151 pl->root->header.head = pl->root->root;
152 pl->head = pl->root;
153 return 0;
154 }
155
156 /* Quit/Cleanup
157 Recursively clean pagenode linked list
158 */
159 void ir_quit
160 ( void )
161 { ir_free_pagenodes(datapages.root);
162 ir_free_pagenodes(namepages.root);
163 }
164
165 static
166 void ir_free_pagenodes
167 ( struct pagenode_t* pagenode )
168 { if (pagenode->header.next != NULL)
169 ir_free_pagenodes(pagenode->header.next);
170 free(pagenode);
171 }
172
173 /* Link
174 */
175 int ir_linker
176 ( void )
177 { return 0; }
178
179 /* Condense
180 */
181 int ir_condenser
182 ( void )
183 { return 0; }
184
185 /* Return the class's name string */
186 uint8_t* ir_class_name
187 ( struct ir_class_t* class )
188 { return class->name; }
189
190 /* Return a pointer to the root class */
191 struct ir_class_t* ir_class_root
192 ( void )
193 { return &root_class; }
194
195 /* Add a subclass to a class
196 Attempts to create a new subclass in the provided class, returning
197 the class if it already exists
198 */
199 struct ir_class_t* ir_class_addchild
200 ( struct ir_class_t* class,
201 const uint8_t* name
202 )
203 { struct ir_class_t* iter;
204 if (class->nextchild == NULL)
205 goto alloc;
206 iter = class->nextchild;
207 if (iter->name == NULL)
208 eprintf("Null name pointer in class %p\n", iter);
209 if (name == NULL)
210 eprintf("Null child added to class %s\n", iter->name);
211 check:
212 if (bytes_identical(iter->name, name))
213 return iter;
214 if (iter->nextsib != NULL)
215 { iter = iter->nextsib;
216 goto check;
217 }
218 alloc:
219 iter = struct_alloc(ir_class_t);
220 iter->nextsib = class->nextchild;
221 iter->name = name_alloc(name);
222 return class->nextchild = iter;
223 }
224
225 /* Add a set to a class
226 Attempts to create a new root set in the specified class, returning
227 the set if it already exists
228 */
229 struct ir_set_t* ir_class_addset
230 ( struct ir_class_t* class,
231 const uint8_t* name
232 )
233 { struct ir_set_t* iter;
234 if (class->root_set == NULL)
235 goto alloc;
236 iter = class->root_set;
237 if (iter->name == NULL)
238 eprintf("Null name pointer in class %p\n", iter);
239 if (name == NULL)
240 eprintf("Null set added to class %U\n", iter->name);
241 check:
242 if (bytes_identical(iter->name, name))
243 return iter;
244 if (iter->nextsib != NULL)
245 { iter = iter->nextsib;
246 goto check;
247 }
248 alloc:
249 iter = struct_alloc(ir_set_t);
250 iter->nextsib = class->root_set;
251 iter->name = name_alloc(name);
252 return class->root_set = iter;
253 }
254
255 /* Add a set to a set
256 Attempts to create a new subset of the specified set, returning the
257 child if it already exists
258 */
259 struct ir_set_t* ir_set_addchild
260 ( struct ir_set_t* set,
261 const uint8_t* name
262 )
263 { struct ir_set_t* iter;
264 if (set->nextchild == NULL)
265 goto alloc;
266 iter = set->nextchild;
267 if (iter->name == NULL)
268 eprintf("Null name pointer in set %p\n", iter);
269 if (name == NULL)
270 eprintf("Null child added to set %s\n", iter->name);
271 check:
272 if (bytes_identical(iter->name, name))
273 return iter;
274 if (iter->nextsib != NULL)
275 { iter = iter->nextsib;
276 goto check;
277 }
278 alloc:
279 iter = struct_alloc(ir_set_t);
280 iter->nextsib = set->nextchild;
281 iter->name = name_alloc(name);
282 return set->nextchild = iter;
283 }
284
285 /* Add a framebox to a set
286 Attempts to create a new framebox of the specified set, returning
287 the framebox if it already exists
288 */
289 static inline
290 struct ir_framebox_t* ir_set_add_framebox
291 ( struct ir_set_t* set,
292 const uint8_t* name
293 )
294 { struct ir_framebox_t* iter;
295 if (set->frameboxes == NULL)
296 goto alloc;
297 iter = set->frameboxes;
298 check:
299 if (bytes_identical(iter->header.data_name, name))
300 return iter;
301 if (iter->header.nextsib != NULL)
302 { iter = (struct ir_framebox_t*) iter->header.nextsib;
303 goto check;
304 }
305 alloc:
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 ( const uint8_t* stra,
318 const uint8_t* strb
319 )
320 { int ca, cb;
321 do {
322 ca = *stra++;
323 cb = *strb++;
324 } while (ca && 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 const uint8_t* path
394 )
395 { if (path == NULL)
396 eprintf("Null path in data %s\n", setdata->header.data_name);
397 if (setdata->header.src_filename != NULL)
398 wprintf("Path override: %s -> %s for setdata %s\n",
399 setdata->header.src_filename, path, setdata->header.data_name);
400 setdata->header.src_filename = name_alloc(path);
401 }
402
403 union ir_setdata_t* ir_framesheet
404 ( const uint8_t* name,
405 apc_facing d,
406 int width,
407 int height
408 )
409 { return ir_framedata(FSDAT, name, d, width, height); }
410
411 union ir_setdata_t* ir_mapsheet
412 ( const uint8_t* name,
413 apc_facing d,
414 int width,
415 int height
416 )
417 { return ir_framedata(MSDAT, name, d, width, height); }
418
419 static inline
420 union ir_setdata_t* ir_framedata
421 ( enum dtype type,
422 const uint8_t* name,
423 apc_facing d,
424 int width,
425 int height
426 )
427 { struct ir_framedata_t* framedata = struct_alloc(ir_framedata_t);
428 if (name == NULL)
429 eprintf("Null name in set allocation\n");
430 framedata->header.type = type;
431 framedata->header.data_name = name_alloc(name);
432 framedata->frameinfo.facing = d;
433 framedata->frameinfo.w = width;
434 framedata->frameinfo.h = height;
435 return (union ir_setdata_t*) framedata;
436 }
437
438 union ir_setdata_t* ir_audio
439 ( const uint8_t* name )
440 { struct ir_simplex_t* audio = struct_alloc(ir_simplex_t);
441 if (name == NULL)
442 eprintf("Null audio\n");
443 audio->header.type = ADAT;
444 audio->header.data_name = name_alloc(name);
445 return (union ir_setdata_t*) audio;
446 }
447
448
449 /* Create classld that points to a class */
450 struct ir_classld_t* ir_classld_from_class
451 ( struct ir_class_t* class )
452 { struct ir_classld_t* classld;
453 if (class == NULL)
454 eprintf("Null class in classld\n");
455 classld = struct_alloc(ir_classld_t);
456 classld->root_class = class;
457 return classld;
458 }
459
460 struct ir_setld_t* ir_setld_from_ref
461 ( long long ref )
462 { struct ir_setld_t* setld;
463 setld = struct_alloc(ir_setld_t);
464 setld->ref = ref;
465 return setld;
466 }
467
468 struct ir_setld_t* ir_setld_from_classld
469 ( struct ir_classld_t* classld,
470 const uint8_t* name
471 )
472 { struct ir_setld_t* setld;
473 setld = struct_alloc(ir_setld_t);
474 setld->namelist = struct_alloc(ir_namelist_t);
475 setld->namelist_head = setld->namelist;
476 setld->namelist_head->name = name_alloc(name);
477 setld->classld = classld;
478 return setld;
479 }
480
481 struct ir_setld_t* ir_setld_addchild
482 ( struct ir_setld_t* setld,
483 const uint8_t* name
484 )
485 { if (setld->namelist == NULL)
486 { setld->namelist = struct_alloc(ir_namelist_t);
487 setld->namelist_head = setld->namelist;
488 }
489 else
490 { setld->namelist_head->nextsib = struct_alloc(ir_namelist_t);
491 setld->namelist_head = setld->namelist_head->nextsib;
492 }
493 setld->namelist_head->name = name_alloc(name);
494 return setld;
495 }
496
497 union ir_setdata_t* ir_link
498 ( enum ltype link_type,
499 struct ir_setld_t* setld,
500 const uint8_t* name
501 )
502 { struct ir_link_t* link;
503 link = struct_alloc(ir_link_t);
504 link->header.type = LDAT;
505 link->type = link_type;
506 link->classld = setld->classld;
507 link->setld = setld;
508 if (link_type != OLINK && name != NULL)
509 link->header.data_name = name_alloc(name);
510 return (union ir_setdata_t*) link;
511 }
512
513
514 static
515 void* stack_alloc
516 ( size_t bytes )
517 { if (!bytes) //valid behavior to attain current head
518 return datapages.head->header.head;
519 if (PL_HEADMEM(datapages) < bytes)
520 { datapages.head->header.next = (struct pagenode_t*) calloc(datapages.pagesize,1);
521 if (datapages.head->header.next == NULL)
522 eprintf("Memory allocation error \n");
523 datapages.head = datapages.head->header.next;
524 datapages.head->header.head = datapages.head->root;
525 }
526 datapages.head->header.head += bytes;
527 return (void*) datapages.head->header.head - bytes;
528 }
529
530 static
531 uint8_t* name_alloc
532 ( const uint8_t* name_src )
533 { const uint8_t* iter;
534 uint8_t* name;
535 int head_mem;
536 copy:
537 name = (uint8_t*)namepages.head->header.head;
538 iter = name_src;
539 for (head_mem = PL_HEADMEM(namepages); *iter && *iter != '_' && head_mem; head_mem--)
540 *(namepages.head->header.head)++ = *iter++;
541 if (head_mem == 0) //not enough room
542 { namepages.head->header.next = (struct pagenode_t*) calloc(namepages.pagesize,1);
543 if (namepages.head->header.next == NULL)
544 eprintf("Memory allocation error\n");
545 namepages.head = namepages.head->header.next;
546 namepages.head->header.head = namepages.head->root;
547 goto copy;
548 }
549 *(namepages.head->header.head)++ = '\0';
550 return name;
551 }