ir_linkdata_dlink_name
[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 #define eprintf_callback(...) exit(EXIT_FAILURE)
21 #include "print.h"
22 #include "apc.h"
23 #include "ir.h"
24 #include "pagenode.h"
25 #define XXH_PRIVATE_API
26 #include "../xxHash/xxhash.h"
27 /* Public */
28 int ir_init(void);
29 void ir_quit(void);
30 void ir_test(void);
31 int ir_linker(void);
32 int ir_condenser(void);
33 /* Set data mem */
34 enum dtype { FSDAT, MSDAT, ADAT, LDAT, FBDAT };
35 struct ir_namelist_t;
36 struct ir_namelist_t
37 { struct ir_namelist_t* nextsib;
38 uint8_t* name;
39 };
40 struct ir_classld_t
41 { struct ir_class_t* root_class;
42 struct ir_namelist_t* namelist, * namelist_head;
43 };
44 struct ir_setld_t
45 { struct ir_classld_t* classld;
46 uint32_t ref;
47 struct ir_namelist_t* namelist, * namelist_head;
48 };
49 struct ir_setdata_header_t
50 { enum dtype type;
51 uint8_t* src_filename, * data_name;
52 union ir_setdata_t* nextsib;
53 long filepos;
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_setld_t* setld;
68 struct ir_set_t* trg_set;
69 uint8_t* dlink;
70 enum ltype type;
71 };
72 union ir_setdata_t
73 { struct ir_setdata_header_t header;
74 struct ir_framebox_t framebox;
75 struct ir_framedata_t framesheet;
76 struct ir_framedata_t mapsheet;
77 struct ir_simplex_t audio;
78 struct ir_link_t link;
79 };
80 struct ir_class_t
81 { struct ir_class_t* nextchild, * nextsib;
82 struct ir_set_t* root_set;
83 uint8_t* name;
84 long filepos;
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 void ir_linkdata_resolve_set(union ir_setdata_t*);
102 static inline
103 int bytes_identical(const uint8_t*,const uint8_t*);
104 static inline
105 int classnames_identical(const uint8_t*,const uint8_t*);
106 static
107 uint8_t* name_alloc(const uint8_t*);
108 static
109 uint8_t* classname_alloc(const uint8_t*);
110 #define struct_clear(_S) (memset((_S), 0, sizeof(*(_S))))
111 #define REFHASH(ref) (XXH32(&ref, sizeof(uint32_t), 0xCEED) & 0xCFF)
112 #define struct_alloc(_T) ((struct _T*) stack_alloc(&datapages, sizeof(struct _T)))
113 extern //apc.c
114 long sys_pagesize;
115 extern //apc.c
116 char* apc_package_name;
117 static
118 struct pagelist_t datapages, namepages, refhashpages;
119 static
120 struct ir_class_t root_class;
121
122 /* Init */
123 int ir_init
124 ( void )
125 { pagelist_init(datapages, (size_t)SYS_PAGESIZE);
126 pagelist_init(namepages, (size_t)NAME_PAGESIZE);
127 pagelist_init(refhashpages, (size_t)SYS_PAGESIZE);
128 root_class.name = (uint8_t*) apc_package_name;
129 return 0;
130 }
131
132 /* Quit/Cleanup */
133 void ir_quit
134 ( void )
135 { pagenode_free(datapages.root);
136 pagenode_free(namepages.root);
137 pagenode_free(refhashpages.root);
138
139 }
140
141 /* Link */
142 int ir_linker
143 ( void )
144 {
145 return 0;
146 }
147
148 /* Condense */
149 int ir_condenser
150 ( void )
151 { return 0; }
152
153 /* Return the class's name string */
154 uint8_t* ir_class_name
155 ( struct ir_class_t* class )
156 { return class->name; }
157
158 /* Return a pointer to the root class */
159 struct ir_class_t* ir_class_root
160 ( void )
161 { return &root_class; }
162
163 /* Add a subclass to a class
164 Attempts to create a new subclass in the provided class, returning
165 the class if it already exists
166 */
167 struct ir_class_t* ir_class_addchild
168 ( struct ir_class_t* class,
169 const uint8_t* name
170 )
171 { struct ir_class_t* iter;
172 if (class->nextchild == NULL)
173 { class->nextchild = struct_alloc(ir_class_t);
174 struct_clear(class->nextchild);
175 class->nextchild->name = classname_alloc(name);
176 return class->nextchild;
177 }
178 iter = class->nextchild;
179 if (iter->name == NULL)
180 eprintf("Null name pointer in class %p\n", iter);
181 if (name == NULL)
182 eprintf("Null child added to class %s\n", iter->name);
183 check:
184 if (classnames_identical(iter->name, name))
185 return iter;
186 if (iter->nextsib != NULL)
187 { iter = iter->nextsib;
188 goto check;
189 }
190 iter->nextsib = struct_alloc(ir_class_t);
191 struct_clear(iter->nextsib);
192 iter->nextsib->name = classname_alloc(name);
193 return iter->nextsib;
194 }
195
196 /* Add a set to a class
197 Attempts to create a new root set in the specified class, returning
198 the set if it already exists
199 */
200 struct ir_set_t* ir_class_addset
201 ( struct ir_class_t* class,
202 const uint8_t* name
203 )
204 { struct ir_set_t* iter;
205 if (class->root_set == NULL)
206 { class->root_set = struct_alloc(ir_set_t);
207 struct_clear(class->root_set);
208 class->root_set->name = name_alloc(name);
209 return class->root_set;
210 }
211 iter = class->root_set;
212 if (iter->name == NULL)
213 eprintf("Null name pointer in class %p\n", iter);
214 if (name == NULL)
215 eprintf("Null set added to class %U\n", iter->name);
216 check:
217 if (bytes_identical(iter->name, name))
218 return iter;
219 if (iter->nextsib != NULL)
220 { iter = iter->nextsib;
221 goto check;
222 }
223 iter->nextsib = struct_alloc(ir_set_t);
224 struct_clear(iter->nextsib);
225 iter->nextsib->name = name_alloc(name);
226 return iter->nextsib;
227 }
228
229 /* Get the root set of the class */
230 struct ir_set_t* ir_class_rootset
231 ( struct ir_class_t* class )
232 { return class->root_set; }
233
234 struct ir_set_t* ir_set_from_ref
235 ( uint32_t ref )
236 { uint16_t hash;
237 struct ir_set_t** iters;
238 struct pagenode_t* iterp;
239 iterp = refhashpages.root;
240 hash = REFHASH(ref);
241 do
242 iters = ((struct ir_set_t**) iterp->root) + hash;
243 while (*iters != NULL && (*iters)->ref != ref && (iterp = iterp->header.next) != NULL);
244 return *iters;
245 }
246
247
248 /* Add a set to a set
249 Attempts to create a new subset of the specified set, returning the
250 child if it already exists
251 */
252 struct ir_set_t* ir_set_addchild
253 ( struct ir_set_t* set,
254 const uint8_t* name
255 )
256 { struct ir_set_t* iter;
257 if (set->nextchild == NULL)
258 { set->nextchild = struct_alloc(ir_set_t);
259 struct_clear(set->nextchild);
260 set->nextchild->name = name_alloc(name);
261 return set->nextchild;
262 }
263 iter = set->nextchild;
264 if (name == NULL)
265 eprintf("Null child added to set %s\n", iter->name);
266 if (iter->name == NULL)
267 eprintf("Null name pointer in set %p\n", iter);
268 check:
269 if (bytes_identical(iter->name, name))
270 return iter;
271 if (iter->nextsib != NULL)
272 { iter = iter->nextsib;
273 goto check;
274 }
275 iter->nextsib = struct_alloc(ir_set_t);
276 struct_clear(iter->nextsib);
277 iter->nextsib->name = name_alloc(name);
278 return iter->nextsib;
279 }
280
281 /* Add a framebox to a set
282 Attempts to create a new framebox of the specified set, returning
283 the framebox if it already exists
284 Name is not allocated, but assigned, unlike other "XXX_add" functions where
285 name is duplicated into IR's internal array.
286 */
287 static inline
288 struct ir_framebox_t* ir_set_add_framebox
289 ( struct ir_set_t* set,
290 uint8_t* name
291 )
292 { struct ir_framebox_t* iter;
293 if (set->frameboxes == NULL)
294 { set->frameboxes = struct_alloc(ir_framebox_t);
295 struct_clear(set->frameboxes);
296 set->frameboxes->header.data_name = name;
297 return set->frameboxes;
298 }
299 iter = set->frameboxes;
300 check:
301 if (bytes_identical(iter->header.data_name, name))
302 return iter;
303 if (iter->header.nextsib != NULL)
304 { iter = (struct ir_framebox_t*) iter->header.nextsib;
305 goto check;
306 }
307 iter->header.nextsib = (union ir_setdata_t*) struct_alloc(ir_framebox_t);
308 struct_clear(iter->header.nextsib);
309 iter->header.nextsib->header.data_name = name;
310 return (struct ir_framebox_t*) (iter->header.nextsib);
311 }
312
313 /* Match two null-terminated bytestrings
314 Return 1 if the two bytestrings are identical, else 0
315 */
316 static inline
317 int bytes_identical
318 ( const uint8_t* stra,
319 const uint8_t* strb
320 )
321 { int ca, cb;
322 do {
323 ca = *stra++;
324 cb = *strb++;
325 } while (ca && ca != '_' && ca == cb);
326 return (ca == cb);
327 }
328
329 static inline
330 int classnames_identical
331 ( const uint8_t* stra,
332 const uint8_t* strb
333 )
334 { int ca, cb;
335 do {
336 ca = *stra++;
337 cb = *strb++;
338 } while (ca && ca == cb);
339 return (ca == cb);
340 }
341
342 /* Return the name of the set */
343 uint8_t* ir_set_name
344 ( struct ir_set_t* set)
345 { return set->name; }
346
347 /* Return the next sib of the class */
348 struct ir_class_t* ir_class_nextsib
349 ( struct ir_class_t* class )
350 { return class->nextsib; }
351
352 /* Return the next sib of the class */
353 struct ir_class_t* ir_class_nextchild
354 ( struct ir_class_t* class )
355 { return class->nextchild; }
356
357 /* Get the file position of the class */
358 long ir_class_fpos
359 ( struct ir_class_t* class )
360 { return class->filepos; }
361
362 /* Set the file position of the class */
363 void ir_class_assign_fpos
364 ( struct ir_class_t* class,
365 long newpos
366 )
367 { class->filepos = newpos; }
368
369 /* Get the next sibling of the provided set */
370 struct ir_set_t* ir_set_nextsib
371 ( struct ir_set_t* set )
372 { return set->nextsib; }
373
374 /* Get the next child of the provided set */
375 struct ir_set_t* ir_set_nextchild
376 ( struct ir_set_t* set )
377 { return set->nextchild; }
378
379 /* Get the file position of the class */
380 long ir_set_fpos
381 ( struct ir_set_t* set )
382 { return set->filepos; }
383
384 /* Set the file position of the class */
385 void ir_set_assign_fpos
386 ( struct ir_set_t* set,
387 long newpos
388 )
389 { set->filepos = newpos; }
390
391 /* Assign Setdata to Set */
392 void ir_set_assign_data
393 ( struct ir_set_t* set,
394 union ir_setdata_t* setdata
395 )
396 { struct ir_framebox_t* framebox;
397 struct ir_simplex_t* simplex;
398 switch (setdata->header.type)
399 { case FSDAT:
400 framebox = ir_set_add_framebox(set, setdata->header.data_name);
401 if (framebox->framesheets[setdata->framesheet.frameinfo.facing].header.data_name != NULL)
402 wprintf("Duplicate framesheet [%i] %s\n",
403 setdata->framesheet.frameinfo.facing, setdata->header.data_name);
404 framebox->framesheets[setdata->framesheet.frameinfo.facing] = setdata->framesheet;
405 break;
406 case MSDAT:
407 framebox = ir_set_add_framebox(set, setdata->header.data_name);
408 if (framebox->mapsheets[setdata->mapsheet.frameinfo.facing].header.data_name != NULL)
409 wprintf("Duplicate mapsheet [%i] %s\n",
410 setdata->mapsheet.frameinfo.facing, setdata->header.data_name);
411 framebox->mapsheets[setdata->mapsheet.frameinfo.facing] = setdata->mapsheet;
412 break;
413 case ADAT:
414 if (set->audio == NULL)
415 { set->audio = (struct ir_simplex_t*) setdata;
416 return;
417 }
418 simplex = set->audio;
419 while (simplex->header.nextsib != NULL)
420 if (bytes_identical(simplex->header.data_name, setdata->header.data_name))
421 { wprintf("Duplicate audio %s\n", setdata->header.data_name);
422 *simplex = setdata->audio;
423 //setdata is now a pointer to redundant, unused memory.
424 return;
425 }
426 else
427 simplex = (struct ir_simplex_t*) simplex->header.nextsib;
428 setdata->audio.header.nextsib = (union ir_setdata_t*) set->audio;
429 set->audio = (struct ir_simplex_t*) setdata;
430 break;
431 case LDAT:
432 setdata->link.header.nextsib = (union ir_setdata_t*) set->links;
433 set->links = (struct ir_link_t*) setdata;
434 break;
435 default:
436 fprintf(stderr, "Unknown setdata type %x\n", setdata->header.type);
437 exit(-1);
438 }
439 }
440
441 void ir_set_assign_ref
442 ( struct ir_set_t* set,
443 uint32_t ref
444 )
445 { uint16_t hash, oldhash;
446 struct ir_set_t** iters;
447 struct pagenode_t* iterp;
448 uint32_t oldref;
449 oldref = set->ref;
450 oldhash = 0;
451 hash = REFHASH(ref);
452 iterp = refhashpages.root;
453 check_depth:
454 iters = ((struct ir_set_t**) iterp->root) + hash;
455 if (*iters == NULL || *iters == set)
456 *iters = set;
457 else
458 { if (iterp->header.next == NULL)
459 pagelist_alloc(refhashpages);
460 iterp = iterp->header.next;
461 goto check_depth;
462 }
463 if (oldref != 0)
464 { wprintf("Ref override: 0x%x -> 0x%x for set %s\n", oldref, ref, set->name);
465 if (oldhash != 0)
466 *iters = NULL;
467 else
468 { oldhash = hash;
469 hash = REFHASH(oldref);
470 goto check_depth;
471 }
472 }
473 set->ref = ref;
474 }
475
476 void ir_data_assign_path
477 ( union ir_setdata_t* setdata,
478 const uint8_t* path
479 )
480 { if (path == NULL)
481 eprintf("Null path in data %s\n", setdata->header.data_name);
482 if (setdata->header.src_filename != NULL)
483 wprintf("Path override: %s -> %s for setdata %s\n",
484 setdata->header.src_filename, path, setdata->header.data_name);
485 setdata->header.src_filename = name_alloc(path);
486 }
487
488 union ir_setdata_t* ir_framesheet
489 ( const uint8_t* name,
490 apc_facing d,
491 int width,
492 int height
493 )
494 { return ir_framedata(FSDAT, name, d, width, height); }
495
496 union ir_setdata_t* ir_mapsheet
497 ( const uint8_t* name,
498 apc_facing d,
499 int width,
500 int height
501 )
502 { return ir_framedata(MSDAT, name, d, width, height); }
503
504 static inline
505 union ir_setdata_t* ir_framedata
506 ( enum dtype type,
507 const uint8_t* name,
508 apc_facing d,
509 int width,
510 int height
511 )
512 { struct ir_framedata_t* framedata = struct_alloc(ir_framedata_t);
513 struct_clear(framedata);
514 if (name == NULL)
515 eprintf("Null name in set allocation\n");
516 framedata->header.type = type;
517 framedata->header.data_name = name_alloc(name);
518 framedata->frameinfo.facing = d;
519 framedata->frameinfo.w = width;
520 framedata->frameinfo.h = height;
521 return (union ir_setdata_t*) framedata;
522 }
523
524 union ir_setdata_t* ir_audio
525 ( const uint8_t* name )
526 { struct ir_simplex_t* audio = struct_alloc(ir_simplex_t);
527 struct_clear(audio);
528 if (name == NULL)
529 eprintf("Null audio\n");
530 audio->header.type = ADAT;
531 audio->header.data_name = name_alloc(name);
532 return (union ir_setdata_t*) audio;
533 }
534
535
536 /* Create classld that points to a class */
537 struct ir_classld_t* ir_classld_from_class
538 ( struct ir_class_t* class )
539 { struct ir_classld_t* classld;
540 if (class == NULL)
541 eprintf("Null class in classld\n");
542 classld = struct_alloc(ir_classld_t);
543 struct_clear(classld);
544 classld->root_class = class;
545 return classld;
546 }
547
548 struct ir_setld_t* ir_setld_from_ref
549 ( uint32_t ref )
550 { struct ir_setld_t* setld;
551 setld = struct_alloc(ir_setld_t);
552 struct_clear(setld);
553 setld->ref = ref;
554 return setld;
555 }
556
557 struct ir_setld_t* ir_setld_from_classld
558 ( struct ir_classld_t* classld,
559 const uint8_t* name
560 )
561 { struct ir_setld_t* setld;
562 setld = struct_alloc(ir_setld_t);
563 struct_clear(setld);
564 setld->namelist = struct_alloc(ir_namelist_t);
565 struct_clear(setld->namelist);
566 setld->namelist_head = setld->namelist;
567 setld->namelist_head->name = name_alloc(name);
568 setld->classld = classld;
569 return setld;
570 }
571
572 struct ir_setld_t* ir_setld_addchild
573 ( struct ir_setld_t* setld,
574 const uint8_t* name
575 )
576 { if (setld->namelist == NULL)
577 { setld->namelist = struct_alloc(ir_namelist_t);
578 struct_clear(setld->namelist);
579 setld->namelist_head = setld->namelist;
580 }
581 else
582 { setld->namelist_head->nextsib = struct_alloc(ir_namelist_t);
583 struct_clear(setld->namelist_head->nextsib);
584 setld->namelist_head = setld->namelist_head->nextsib;
585 }
586 setld->namelist_head->name = name_alloc(name);
587 return setld;
588 }
589
590 union ir_setdata_t* ir_link
591 ( enum ltype link_type,
592 struct ir_setld_t* setld,
593 const uint8_t* name
594 )
595 { struct ir_link_t* link;
596 link = struct_alloc(ir_link_t);
597 struct_clear(link);
598 link->header.type = LDAT;
599 link->type = link_type;
600 link->setld = setld;
601 if (link_type != OLINK && name != NULL)
602 link->header.data_name = name_alloc(name);
603 return (union ir_setdata_t*) link;
604 }
605
606 /* Return a set's root framebox */
607 union ir_setdata_t* ir_set_framebox
608 ( struct ir_set_t* set )
609 { return (union ir_setdata_t*) set->frameboxes; }
610
611 /* Return a set's root audio data */
612 union ir_setdata_t* ir_set_audio
613 ( struct ir_set_t* set )
614 { return (union ir_setdata_t*) set->audio; }
615
616 /* Return a set's root link data */
617 union ir_setdata_t* ir_set_link
618 ( struct ir_set_t* set )
619 { return (union ir_setdata_t*) set->links; }
620
621 #define assert_link(linkdata) if (DEBUG) { \
622 if (linkdata->header.type != LDAT) \
623 eprintf("Data %s is not a link\n", linkdata->header.data_name); \
624 }
625
626 /* Return the link type */
627 enum ltype ir_linkdata_type
628 ( union ir_setdata_t* linkdata )
629 { assert_link(linkdata);
630 return linkdata->link.type;
631 }
632
633 /* Return the link type */
634 uint32_t ir_linkdata_ref
635 ( union ir_setdata_t* linkdata )
636 { assert_link(linkdata);
637 return linkdata->link.setld->ref;
638 }
639
640 /* Return the current target set, resolving it first if not present */
641 struct ir_set_t* ir_linkdata_set
642 ( union ir_setdata_t* linkdata )
643 { assert_link(linkdata);
644 if (linkdata->link.trg_set == NULL)
645 ir_linkdata_resolve_set(linkdata);
646 return linkdata->link.trg_set;
647 }
648
649 /* Resolve and assign the link's target set */
650 static inline
651 void ir_linkdata_resolve_set
652 ( union ir_setdata_t* linkdata )
653 { struct ir_class_t* class_iter;
654 struct ir_namelist_t* namelist_iter,* namelist_iter_last;
655 struct ir_setld_t* setld;
656 struct ir_classld_t* classld;
657 struct ir_set_t* set;
658 set = NULL;
659 class_iter = NULL;
660 assert_link(linkdata);
661 setld = linkdata->link.setld;
662 if (linkdata->link.setld == NULL)
663 eprintf("Link data is invalid\n");
664 classld = setld->classld;
665 if (classld != NULL)
666 { namelist_iter = classld->namelist;
667 if (classld->root_class == NULL)
668 eprintf("No root class for classld\n");
669 class_iter = classld->root_class->nextchild;
670 namelist_iter_last = NULL;
671 while (class_iter != NULL)
672 { if (classnames_identical(class_iter->name, namelist_iter->name))
673 { if (namelist_iter == classld->namelist_head)
674 break;
675 class_iter = class_iter->nextchild;
676 namelist_iter_last = namelist_iter;
677 namelist_iter = namelist_iter->nextsib;
678 }
679 else
680 class_iter = class_iter->nextsib;
681 }
682 if (class_iter == NULL)
683 { if (namelist_iter_last)
684 eprintf("No such subclass \"%s\" of class \"%s\"\n",
685 namelist_iter->name,
686 namelist_iter_last->name);
687 else
688 { wprintf("No such class \"%s\"\n", namelist_iter->name);
689 return;
690 }
691 }
692 set = class_iter->root_set;
693 }
694 else
695 set = ir_set_from_ref(setld->ref);
696 if (set == NULL)
697 eprintf("Initial set resolution failed\n");
698 namelist_iter = setld->namelist;
699 namelist_iter_last = NULL;
700 if (setld->namelist != NULL)
701 { while (set != NULL)
702 { if (bytes_identical(set->name, namelist_iter->name))
703 { if (namelist_iter == setld->namelist_head)
704 break;
705 set = set->nextchild;
706 namelist_iter_last = namelist_iter;
707 namelist_iter = namelist_iter->nextsib;
708 }
709 else
710 set = set->nextsib;
711 }
712 if (set == NULL)
713 { if (namelist_iter_last)
714 eprintf("No such subset \"%s\" of set \"%s\"\n",
715 namelist_iter->name,
716 namelist_iter_last->name);
717 else
718 eprintf("No such set \"%s\" in class \"%s\"\n",
719 namelist_iter->name,
720 class_iter->name);
721 }
722 }
723 linkdata->link.trg_set = set;
724 }
725
726 /* Assign a linkdatas trg_set */
727 void ir_linkdata_assign_set
728 ( union ir_setdata_t* link, struct ir_set_t* set )
729 { assert_link(link);
730 link->link.trg_set = set;
731 }
732
733 /* Assign a linkdatas type */
734 void ir_linkdata_assign_type
735 ( union ir_setdata_t* link, enum ltype type )
736 { assert_link(link);
737 link->link.type = type;
738 }
739
740 /* Get, or generate, the fully qualified name of the link's target set */
741 uint8_t*
742 ir_linkdata_dlink_name
743 ( union ir_setdata_t* link )
744 { struct ir_namelist_t* namelist_iter;
745 struct ir_setld_t* setld;
746 struct ir_classld_t* classld;
747 uint8_t* bytep;
748 size_t bytes;
749 char setpass;
750 uint8_t delimiter;
751 static const uint8_t dlink_prefix[] = { '/', '.', '.', '/' };
752 # define dlink_prefix_len 4
753 assert_link(link);
754 if (link->link.dlink != NULL)
755 return link->link.dlink;
756 bytes = 0;
757 setld = link->link.setld;
758 if (setld == NULL)
759 eprintf("No setld in dlink\n");
760 classld = setld->classld;
761 if (classld == NULL)
762 eprintf("No classld in dlink\n");
763 if (classld->root_class != NULL)
764 eprintf("Cannot dlink local class \"%s\"\n", classld->root_class->name);
765 namelist_iter = classld->namelist;
766 setpass = 0;
767 count_bytes_in_namelist:
768 while (namelist_iter != NULL)
769 { bytep = namelist_iter->name;
770 while (*bytep++);
771 bytes += (bytep - namelist_iter->name);
772 namelist_iter = namelist_iter->nextsib;
773 }
774 if (setpass == 0)
775 { setpass = 1;
776 namelist_iter = setld->namelist;
777 goto count_bytes_in_namelist;
778 }
779 bytes += dlink_prefix_len;
780 link->link.dlink = stack_alloc(&namepages, bytes);
781 for (bytes = 0; bytes < dlink_prefix_len; bytes++)
782 link->link.dlink[bytes] = dlink_prefix[bytes];
783 namelist_iter = classld->namelist;
784 setpass = 0;
785 delimiter = APC_CLASS_DELIMITER;
786 copy_bytes_in_namelist:
787 while (namelist_iter != NULL)
788 { bytep = namelist_iter->name;
789 while (*bytep)
790 link->link.dlink[bytes++] = *bytep++;
791 link->link.dlink[bytes++] = delimiter;
792 namelist_iter = namelist_iter->nextsib;
793 }
794 if (setpass == 0)
795 { setpass = 1;
796 namelist_iter = setld->namelist;
797 delimiter = APC_SET_DELIMITER;
798 link->link.dlink[bytes - 1] = delimiter; //overwrite last delimiter
799 goto copy_bytes_in_namelist;
800 }
801 link->link.dlink[bytes] = '\0'; //tailing '\0' null termination
802 return link->link.dlink;
803 }
804
805 /* Get a setdata's next sibling */
806 union ir_setdata_t* ir_setdata_nextsib
807 ( union ir_setdata_t* setdata )
808 { return setdata->header.nextsib; }
809
810 /* Get a setdata's name */
811 uint8_t* ir_setdata_name
812 ( union ir_setdata_t* setdata )
813 { return setdata->header.data_name; }
814
815 /* Get a setdata's filename */
816 uint8_t* ir_setdata_filename
817 ( union ir_setdata_t* setdata )
818 { return setdata->header.src_filename; }
819
820 /* Get a setdata's file position */
821 long ir_setdata_fpos
822 ( union ir_setdata_t* setdata )
823 { return setdata->header.filepos; }
824
825 /* Set a setdata's file position */
826 void ir_setdata_assign_fpos
827 ( union ir_setdata_t* setdata,
828 long newpos
829 )
830 { setdata->header.filepos = newpos; }
831
832 /* Assign a setdatas name */
833 void ir_setdata_assign_name
834 ( union ir_setdata_t* setdata, uint8_t* name )
835 { setdata->header.data_name = name;}
836
837 /* Return a framebox's specified framesheet */
838 union ir_setdata_t* ir_framebox_framesheet
839 ( union ir_setdata_t* fbox,
840 apc_facing facing
841 )
842 { if (fbox->header.type != FBDAT)
843 eprintf("Data %s is not a framebox\n", fbox->header.data_name);
844 return (union ir_setdata_t*) &fbox->framebox.framesheets[facing];
845 }
846
847 /* Return a framebox's specified mapsheet */
848 union ir_setdata_t* ir_framebox_mapsheet
849 ( union ir_setdata_t* fbox,
850 apc_facing facing
851 )
852 { if (fbox->header.type != FBDAT)
853 eprintf("Data %s is not a framebox\n", fbox->header.data_name);
854 return (union ir_setdata_t*) &fbox->framebox.mapsheets[facing];
855 }
856
857 /* Return a framedata's frame info */
858 struct ir_frameinfo_t* ir_framedata_frameinfo
859 ( union ir_setdata_t* framedata )
860 { if (framedata->header.type != MSDAT && framedata->header.type != FSDAT)
861 eprintf("Data %s is not a framedata\n", framedata->header.data_name);
862 return &framedata->mapsheet.frameinfo;
863 }
864
865
866 /** Allocators **/
867 static
868 uint8_t* name_alloc
869 ( const uint8_t* name_src )
870 { const uint8_t* iter;
871 uint8_t* name;
872 int head_mem;
873 copy:
874 name = (uint8_t*)namepages.head->header.head;
875 iter = name_src;
876 for (head_mem = PL_HEADMEM(namepages); *iter && *iter != '_' && *iter != '.' && head_mem; head_mem--)
877 *(namepages.head->header.head)++ = *iter++;
878 if (head_mem < 1) //not enough room
879 { pagelist_alloc(namepages);
880 goto copy;
881 }
882 *(namepages.head->header.head)++ = '\0';
883 return name;
884 }
885
886 static
887 uint8_t* classname_alloc
888 ( const uint8_t* name_src )
889 { const uint8_t* iter;
890 uint8_t* name;
891 int head_mem;
892 copy:
893 name = (uint8_t*)namepages.head->header.head;
894 iter = name_src;
895 for (head_mem = PL_HEADMEM(namepages); *iter && head_mem; head_mem--)
896 *(namepages.head->header.head)++ = *iter++;
897 if (head_mem < 1) //not enough room
898 { pagelist_alloc(namepages);
899 goto copy;
900 }
901 *(namepages.head->header.head)++ = '\0';
902 return name;
903 }
904
905 static void crawl_class(struct ir_class_t*);
906 static void crawl_set(struct ir_set_t*,int);
907
908 extern
909 int binout_init(ir_class);
910 void ir_test(void)
911 { uprintf("IR From Directory: %s\n",getcwd(NULL,255));
912 crawl_class(&root_class);
913 if (root_class.root_set != NULL)
914 crawl_set(root_class.root_set, 0);
915 uprintf("starting binaryout \n");
916 binout_init(&root_class);
917 }
918
919
920 static
921 void crawl_class
922 ( struct ir_class_t* class )
923 { struct ir_class_t* iter;
924 for (iter = class->nextchild; iter != NULL; iter = iter->nextsib)
925 { wprintf("Crawling class %U/\n", iter->name);
926 if(chdir((char*)iter->name))
927 eprintf("CHDIR %U from %s\n",iter->name,getcwd(NULL,255));
928 crawl_class(iter);
929 if (iter->root_set != NULL)
930 crawl_set(iter->root_set, 0);
931 uprintf("%U\\\n",iter->name);
932 if (chdir(".."))
933 eprintf("CHDIR ..\n");
934 wprintf("Finished crawling class %U/\n", iter->name);
935 }
936 }
937
938 #define push_setp(setp) (*(struct ir_set_t**)stack_alloc(&datapages, sizeof(struct ir_set_t*)) = setp)
939 #define pop_setp() (*(struct ir_set_t**)pagelist_pop(&datapages, sizeof(struct ir_set_t*)))
940 static
941 void crawl_set
942 ( struct ir_set_t* set,
943 int depth
944 )
945 { struct ir_set_t* iter;
946 int i;
947 i = depth * 12;
948 while (i--)
949 putchar('.');
950 i = depth;
951
952 for(iter = set; iter != NULL; iter = iter->nextchild)
953 { uprintf("[%10U]", iter->name);
954 push_setp(iter);
955 i++;
956 }
957
958 putchar('\n');
959 while (--i >= depth)
960 if (((iter = pop_setp())->nextsib) != NULL)
961 crawl_set(iter->nextsib,i);
962 }