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