api update
[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 #include <errno.h>
14 /* Unicode */
15 #include <unistd.h> //u8_* functions
16 #include <unitypes.h> //uint8_t as a char
17 #include <unistr.h> //u32_cpy
18 #include <unistdio.h> //ulc_fprintf
19 /* Local */
20 #include "print.h"
21 #include "apc.h"
22 #include "ir.h"
23 #include "pagenode.h"
24 #undef do_error
25 #define do_error(...) exit(-1)
26 #define XXH_PRIVATE_API
27 #include "../xxHash/xxhash.h"
28 /* Public */
29 int ir_init(void);
30 void ir_quit(void);
31 void ir_test(void);
32 int ir_linker(void);
33 int ir_condenser(void);
34 /* Set data mem */
35 enum dtype { FSDAT, MSDAT, ADAT, LDAT, FBDAT };
36 struct ir_namelist_t;
37 struct ir_namelist_t
38 { struct ir_namelist_t* nextsib;
39 uint8_t* name;
40 };
41 struct ir_classld_t
42 { struct ir_class_t* root_class;
43 struct ir_namelist_t* namelist, * namelist_head;
44 };
45 struct ir_setld_t
46 { struct ir_classld_t* classld;
47 long long ref;
48 struct ir_namelist_t* namelist, * namelist_head;
49 };
50 struct ir_setdata_header_t
51 { enum dtype type;
52 uint8_t* src_filename, * data_name;
53 union ir_setdata_t* nextsib;
54 };
55 struct ir_framedata_t
56 { struct ir_setdata_header_t header;
57 struct ir_frameinfo_t frameinfo;
58 };
59 struct ir_framebox_t
60 { struct ir_setdata_header_t header;
61 struct ir_framedata_t framesheets[FACING_MAX];
62 struct ir_framedata_t mapsheets[FACING_MAX];
63 };
64 struct ir_simplex_t { struct ir_setdata_header_t header; };
65 struct ir_link_t
66 { struct ir_setdata_header_t header;
67 struct ir_classld_t* classld;
68 struct ir_setld_t* setld;
69 enum ltype type;
70 };
71 union ir_setdata_t
72 { struct ir_setdata_header_t header;
73 struct ir_framebox_t framebox;
74 struct ir_framedata_t framesheet;
75 struct ir_framedata_t mapsheet;
76 struct ir_simplex_t audio;
77 struct ir_link_t link;
78 };
79 struct ir_class_t
80 { struct ir_class_t* nextchild, * nextsib;
81 struct ir_set_t* root_set;
82 uint8_t* name;
83 };
84 struct ir_set_t
85 { struct ir_set_t* nextchild, * nextsib;
86 uint32_t ref;
87 uint8_t* name;
88 struct ir_framebox_t* frameboxes;
89 struct ir_simplex_t* audio;
90 struct ir_link_t* links;
91 long filepos;
92 };
93 /* Functions */
94 static inline
95 struct ir_framebox_t* ir_set_add_framebox(struct ir_set_t*,uint8_t*);
96 static inline
97 union ir_setdata_t* ir_framedata (enum dtype,const uint8_t*,apc_facing,int,int);
98 static inline
99 int bytes_identical(const uint8_t*,const uint8_t*);
100 static inline
101 int classnames_identical(const uint8_t*,const uint8_t*);
102 static
103 uint8_t* name_alloc(const uint8_t*);
104 static
105 uint8_t* classname_alloc(const uint8_t*);
106 #define struct_clear(_S) (memset((_S), 0, sizeof(*(_S))))
107 #define REFHASH(ref) (XXH32(&ref, sizeof(uint32_t), 0xCEED) & 0xCFF)
108 #define struct_alloc(_T) ((struct _T*) stack_alloc(&datapages, sizeof(struct _T)))
109 extern //apc.c
110 long sys_pagesize;
111 static
112 struct pagelist_t datapages, namepages, refhashpages;
113 static
114 struct ir_class_t root_class = { .name = (uint8_t*)"." };
115
116 /* Init */
117 int ir_init
118 ( void )
119 { pagelist_init(datapages, (size_t)SYS_PAGESIZE);
120 pagelist_init(namepages, (size_t)NAME_PAGESIZE);
121 pagelist_init(refhashpages, (size_t)SYS_PAGESIZE);
122
123 return 0;
124 }
125
126 /* Quit/Cleanup */
127 void ir_quit
128 ( void )
129 { pagenode_free(datapages.root);
130 pagenode_free(namepages.root);
131 pagenode_free(refhashpages.root);
132
133 }
134
135 /* Link */
136 int ir_linker
137 ( void )
138 {
139 return 0;
140 }
141
142 /* Condense */
143 int ir_condenser
144 ( void )
145 { return 0; }
146
147 /* Return the class's name string */
148 uint8_t* ir_class_name
149 ( struct ir_class_t* class )
150 { return class->name; }
151
152 /* Return a pointer to the root class */
153 struct ir_class_t* ir_class_root
154 ( void )
155 { return &root_class; }
156
157 /* Add a subclass to a class
158 Attempts to create a new subclass in the provided class, returning
159 the class if it already exists
160 */
161 struct ir_class_t* ir_class_addchild
162 ( struct ir_class_t* class,
163 const uint8_t* name
164 )
165 { struct ir_class_t* iter;
166 if (class->nextchild == NULL)
167 { class->nextchild = struct_alloc(ir_class_t);
168 struct_clear(class->nextchild);
169 class->nextchild->name = classname_alloc(name);
170 return class->nextchild;
171 }
172 iter = class->nextchild;
173 if (iter->name == NULL)
174 eprintf("Null name pointer in class %p\n", iter);
175 if (name == NULL)
176 eprintf("Null child added to class %s\n", iter->name);
177 check:
178 if (classnames_identical(iter->name, name))
179 return iter;
180 if (iter->nextsib != NULL)
181 { iter = iter->nextsib;
182 goto check;
183 }
184 iter->nextsib = struct_alloc(ir_class_t);
185 struct_clear(iter->nextsib);
186 iter->nextsib->name = classname_alloc(name);
187 return iter->nextsib;
188 }
189
190 /* Add a set to a class
191 Attempts to create a new root set in the specified class, returning
192 the set if it already exists
193 */
194 struct ir_set_t* ir_class_addset
195 ( struct ir_class_t* class,
196 const uint8_t* name
197 )
198 { struct ir_set_t* iter;
199 if (class->root_set == NULL)
200 { class->root_set = struct_alloc(ir_set_t);
201 struct_clear(class->root_set);
202 class->root_set->name = name_alloc(name);
203 return class->root_set;
204 }
205 iter = class->root_set;
206 if (iter->name == NULL)
207 eprintf("Null name pointer in class %p\n", iter);
208 if (name == NULL)
209 eprintf("Null set added to class %U\n", iter->name);
210 check:
211 if (bytes_identical(iter->name, name))
212 return iter;
213 if (iter->nextsib != NULL)
214 { iter = iter->nextsib;
215 goto check;
216 }
217 iter->nextsib = struct_alloc(ir_set_t);
218 struct_clear(iter->nextsib);
219 iter->nextsib->name = name_alloc(name);
220 return iter->nextsib;
221 }
222
223 struct ir_set_t* ir_set_from_ref
224 ( uint32_t ref )
225 { uint16_t hash;
226 struct ir_set_t** iters;
227 struct pagenode_t* iterp;
228 iterp = refhashpages.root;
229 hash = REFHASH(ref);
230 do
231 iters = ((struct ir_set_t**) iterp->root) + hash;
232 while (*iters != NULL && (*iters)->ref != ref && (iterp = iterp->header.next) != NULL);
233 return *iters;
234 }
235
236
237 /* Add a set to a set
238 Attempts to create a new subset of the specified set, returning the
239 child if it already exists
240 */
241 struct ir_set_t* ir_set_addchild
242 ( struct ir_set_t* set,
243 const uint8_t* name
244 )
245 { struct ir_set_t* iter;
246 if (set->nextchild == NULL)
247 { set->nextchild = struct_alloc(ir_set_t);
248 struct_clear(set->nextchild);
249 set->nextchild->name = name_alloc(name);
250 return set->nextchild;
251 }
252 iter = set->nextchild;
253 if (name == NULL)
254 eprintf("Null child added to set %s\n", iter->name);
255 if (iter->name == NULL)
256 eprintf("Null name pointer in set %p\n", iter);
257 check:
258 if (bytes_identical(iter->name, name))
259 return iter;
260 if (iter->nextsib != NULL)
261 { iter = iter->nextsib;
262 goto check;
263 }
264 iter->nextsib = struct_alloc(ir_set_t);
265 struct_clear(iter->nextsib);
266 iter->nextsib->name = name_alloc(name);
267 return iter->nextsib;
268 }
269
270 /* Add a framebox to a set
271 Attempts to create a new framebox of the specified set, returning
272 the framebox if it already exists
273 Name is not allocated, but assigned, unlike other "XXX_add" functions where
274 name is duplicated into IR's internal array.
275 */
276 static inline
277 struct ir_framebox_t* ir_set_add_framebox
278 ( struct ir_set_t* set,
279 uint8_t* name
280 )
281 { struct ir_framebox_t* iter;
282 if (set->frameboxes == NULL)
283 { set->frameboxes = struct_alloc(ir_framebox_t);
284 struct_clear(set->frameboxes);
285 set->frameboxes->header.data_name = name;
286 return set->frameboxes;
287 }
288 iter = set->frameboxes;
289 check:
290 if (bytes_identical(iter->header.data_name, name))
291 return iter;
292 if (iter->header.nextsib != NULL)
293 { iter = (struct ir_framebox_t*) iter->header.nextsib;
294 goto check;
295 }
296 iter->header.nextsib = (union ir_setdata_t*) struct_alloc(ir_framebox_t);
297 struct_clear(iter->header.nextsib);
298 iter->header.nextsib->header.data_name = name;
299 return (struct ir_framebox_t*) (iter->header.nextsib);
300 }
301
302 /* Match two null-terminated bytestrings
303 Return 1 if the two bytestrings are identical, else 0
304 */
305 static inline
306 int bytes_identical
307 ( const uint8_t* stra,
308 const uint8_t* strb
309 )
310 { int ca, cb;
311 do {
312 ca = *stra++;
313 cb = *strb++;
314 } while (ca && ca != '_' && ca == cb);
315 return (ca == cb);
316 }
317
318 static inline
319 int classnames_identical
320 ( const uint8_t* stra,
321 const uint8_t* strb
322 )
323 { int ca, cb;
324 do {
325 ca = *stra++;
326 cb = *strb++;
327 } while (ca && ca == cb);
328 return (ca == cb);
329 }
330
331 /* Assign Setdata to Set */
332 void ir_set_assign_data
333 ( struct ir_set_t* set,
334 union ir_setdata_t* setdata
335 )
336 { struct ir_framebox_t* framebox;
337 struct ir_simplex_t* simplex;
338 switch (setdata->header.type)
339 { case FSDAT:
340 framebox = ir_set_add_framebox(set, setdata->header.data_name);
341 if (framebox->framesheets[setdata->framesheet.frameinfo.facing].header.data_name != NULL)
342 wprintf("Duplicate framesheet [%i] %s\n",
343 setdata->framesheet.frameinfo.facing, setdata->header.data_name);
344 framebox->framesheets[setdata->framesheet.frameinfo.facing] = setdata->framesheet;
345 break;
346 case MSDAT:
347 framebox = ir_set_add_framebox(set, setdata->header.data_name);
348 if (framebox->mapsheets[setdata->mapsheet.frameinfo.facing].header.data_name != NULL)
349 wprintf("Duplicate mapsheet [%i] %s\n",
350 setdata->mapsheet.frameinfo.facing, setdata->header.data_name);
351 framebox->mapsheets[setdata->mapsheet.frameinfo.facing] = setdata->mapsheet;
352 break;
353 case ADAT:
354 if (set->audio == NULL)
355 { set->audio = (struct ir_simplex_t*) setdata;
356 return;
357 }
358 simplex = set->audio;
359 while (simplex->header.nextsib != NULL)
360 if (bytes_identical(simplex->header.data_name, setdata->header.data_name))
361 { wprintf("Duplicate audio %s\n", setdata->header.data_name);
362 *simplex = setdata->audio;
363 //setdata is now a pointer to redundant, unused memory.
364 return;
365 }
366 else
367 simplex = (struct ir_simplex_t*) simplex->header.nextsib;
368 setdata->audio.header.nextsib = (union ir_setdata_t*) set->audio;
369 set->audio = (struct ir_simplex_t*) setdata;
370 break;
371 case LDAT:
372 setdata->link.header.nextsib = (union ir_setdata_t*) set->links;
373 set->links = (struct ir_link_t*) setdata;
374 break;
375 default:
376 fprintf(stderr, "Unknown setdata type %x\n", setdata->header.type);
377 exit(-1);
378 }
379 }
380
381 void ir_set_assign_ref
382 ( struct ir_set_t* set,
383 uint32_t ref
384 )
385 { uint16_t hash, oldhash;
386 struct ir_set_t** iters;
387 struct pagenode_t* iterp;
388 uint32_t oldref;
389 oldref = set->ref;
390 oldhash = 0;
391 hash = REFHASH(ref);
392 iterp = refhashpages.root;
393 check_depth:
394 iters = ((struct ir_set_t**) iterp->root) + hash;
395 if (*iters == NULL || *iters == set)
396 *iters = set;
397 else
398 { if (iterp->header.next == NULL)
399 pagelist_alloc(refhashpages);
400 iterp = iterp->header.next;
401 goto check_depth;
402 }
403 if (oldref != 0)
404 { wprintf("Ref override: 0x%x -> 0x%x for set %s\n", oldref, ref, set->name);
405 if (oldhash != 0)
406 *iters = NULL;
407 else
408 { oldhash = hash;
409 hash = REFHASH(oldref);
410 goto check_depth;
411 }
412 }
413 set->ref = ref;
414 }
415
416 void ir_data_assign_path
417 ( union ir_setdata_t* setdata,
418 const uint8_t* path
419 )
420 { if (path == NULL)
421 eprintf("Null path in data %s\n", setdata->header.data_name);
422 if (setdata->header.src_filename != NULL)
423 wprintf("Path override: %s -> %s for setdata %s\n",
424 setdata->header.src_filename, path, setdata->header.data_name);
425 setdata->header.src_filename = name_alloc(path);
426 }
427
428 union ir_setdata_t* ir_framesheet
429 ( const uint8_t* name,
430 apc_facing d,
431 int width,
432 int height
433 )
434 { return ir_framedata(FSDAT, name, d, width, height); }
435
436 union ir_setdata_t* ir_mapsheet
437 ( const uint8_t* name,
438 apc_facing d,
439 int width,
440 int height
441 )
442 { return ir_framedata(MSDAT, name, d, width, height); }
443
444 static inline
445 union ir_setdata_t* ir_framedata
446 ( enum dtype type,
447 const uint8_t* name,
448 apc_facing d,
449 int width,
450 int height
451 )
452 { struct ir_framedata_t* framedata = struct_alloc(ir_framedata_t);
453 struct_clear(framedata);
454 if (name == NULL)
455 eprintf("Null name in set allocation\n");
456 framedata->header.type = type;
457 framedata->header.data_name = name_alloc(name);
458 framedata->frameinfo.facing = d;
459 framedata->frameinfo.w = width;
460 framedata->frameinfo.h = height;
461 return (union ir_setdata_t*) framedata;
462 }
463
464 union ir_setdata_t* ir_audio
465 ( const uint8_t* name )
466 { struct ir_simplex_t* audio = struct_alloc(ir_simplex_t);
467 struct_clear(audio);
468 if (name == NULL)
469 eprintf("Null audio\n");
470 audio->header.type = ADAT;
471 audio->header.data_name = name_alloc(name);
472 return (union ir_setdata_t*) audio;
473 }
474
475
476 /* Create classld that points to a class */
477 struct ir_classld_t* ir_classld_from_class
478 ( struct ir_class_t* class )
479 { struct ir_classld_t* classld;
480 if (class == NULL)
481 eprintf("Null class in classld\n");
482 classld = struct_alloc(ir_classld_t);
483 struct_clear(classld);
484 classld->root_class = class;
485 return classld;
486 }
487
488 struct ir_setld_t* ir_setld_from_ref
489 ( uint32_t ref )
490 { struct ir_setld_t* setld;
491 setld = struct_alloc(ir_setld_t);
492 struct_clear(setld);
493 setld->ref = ref;
494 return setld;
495 }
496
497 struct ir_setld_t* ir_setld_from_classld
498 ( struct ir_classld_t* classld,
499 const uint8_t* name
500 )
501 { struct ir_setld_t* setld;
502 setld = struct_alloc(ir_setld_t);
503 struct_clear(setld);
504 setld->namelist = struct_alloc(ir_namelist_t);
505 struct_clear(setld->namelist);
506 setld->namelist_head = setld->namelist;
507 setld->namelist_head->name = name_alloc(name);
508 setld->classld = classld;
509 return setld;
510 }
511
512 struct ir_setld_t* ir_setld_addchild
513 ( struct ir_setld_t* setld,
514 const uint8_t* name
515 )
516 { if (setld->namelist == NULL)
517 { setld->namelist = struct_alloc(ir_namelist_t);
518 struct_clear(setld->namelist);
519 setld->namelist_head = setld->namelist;
520 }
521 else
522 { setld->namelist_head->nextsib = struct_alloc(ir_namelist_t);
523 struct_clear(setld->namelist_head->nextsib);
524 setld->namelist_head = setld->namelist_head->nextsib;
525 }
526 setld->namelist_head->name = name_alloc(name);
527 return setld;
528 }
529
530 union ir_setdata_t* ir_link
531 ( enum ltype link_type,
532 struct ir_setld_t* setld,
533 const uint8_t* name
534 )
535 { struct ir_link_t* link;
536 link = struct_alloc(ir_link_t);
537 struct_clear(link);
538 link->header.type = LDAT;
539 link->type = link_type;
540 link->classld = setld->classld;
541 link->setld = setld;
542 if (link_type != OLINK && name != NULL)
543 link->header.data_name = name_alloc(name);
544 return (union ir_setdata_t*) link;
545 }
546
547
548 static
549 uint8_t* name_alloc
550 ( const uint8_t* name_src )
551 { const uint8_t* iter;
552 uint8_t* name;
553 int head_mem;
554 copy:
555 name = (uint8_t*)namepages.head->header.head;
556 iter = name_src;
557 for (head_mem = PL_HEADMEM(namepages); *iter && *iter != '_' && *iter != '.' && head_mem; head_mem--)
558 *(namepages.head->header.head)++ = *iter++;
559 if (head_mem < 1) //not enough room
560 { pagelist_alloc(namepages);
561 goto copy;
562 }
563 *(namepages.head->header.head)++ = '\0';
564 return name;
565 }
566
567 static
568 uint8_t* classname_alloc
569 ( const uint8_t* name_src )
570 { const uint8_t* iter;
571 uint8_t* name;
572 int head_mem;
573 copy:
574 name = (uint8_t*)namepages.head->header.head;
575 iter = name_src;
576 for (head_mem = PL_HEADMEM(namepages); *iter && head_mem; head_mem--)
577 *(namepages.head->header.head)++ = *iter++;
578 if (head_mem < 1) //not enough room
579 { pagelist_alloc(namepages);
580 goto copy;
581 }
582 *(namepages.head->header.head)++ = '\0';
583 return name;
584 }
585
586 static void crawl_class(struct ir_class_t*);
587 static void crawl_set(struct ir_set_t*,int);
588
589 void ir_test(void)
590 { uprintf("IR From Directory: %s\n",getcwd(NULL,255));
591 crawl_class(&root_class);
592 if (root_class.root_set != NULL)
593 crawl_set(root_class.root_set, 0);
594 uprintf("starting binaryout \n");
595 ir_binout_init(&root_class);
596 }
597
598
599 static
600 void crawl_class
601 ( struct ir_class_t* class )
602 { struct ir_class_t* iter;
603 for (iter = class->nextchild; iter != NULL; iter = iter->nextsib)
604 { wprintf("Crawling class %U/\n", iter->name);
605 if(chdir((char*)iter->name))
606 eprintf("CHDIR %U from %s\n",iter->name,getcwd(NULL,255));
607 crawl_class(iter);
608 if (iter->root_set != NULL)
609 crawl_set(iter->root_set, 0);
610 uprintf("%U\\\n",iter->name);
611 if (chdir(".."))
612 eprintf("CHDIR ..\n");
613 wprintf("Finished crawling class %U/\n", iter->name);
614 }
615 }
616
617 #define push_setp(setp) (*(struct ir_set_t**)stack_alloc(&datapages, sizeof(struct ir_set_t*)) = setp)
618 #define pop_setp() (*(struct ir_set_t**)pagelist_pop(&datapages, sizeof(struct ir_set_t*)))
619 static
620 void crawl_set
621 ( struct ir_set_t* set,
622 int depth
623 )
624 { struct ir_set_t* iter;
625 int i;
626 i = depth * 12;
627 while (i--)
628 putchar('.');
629 i = depth;
630
631 for(iter = set; iter != NULL; iter = iter->nextchild)
632 { uprintf("[%10U]", iter->name);
633 push_setp(iter);
634 i++;
635 }
636
637 putchar('\n');
638 while (--i >= depth)
639 if (((iter = pop_setp())->nextsib) != NULL)
640 crawl_set(iter->nextsib,i);
641 }