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