63fe72bbdfa353ceea2324c3da81779f8d880ef5
[henge/apc.git] / src / ir.c
1 /*!@file
2 \brief IR Memory Implementation
3 \details Intermediary memory management
4 \author Jordan Lavatai
5 \date Aug 2016
6 ----------------------------------------------------------------------------*/
7 /* Standard */
8 #include <stdlib.h> //exit, malloc
9 #include <stdio.h> //print
10 #include <stdarg.h> //va_args
11 #include <stdint.h> //uint64_t
12 #include <string.h> //memset, str*
13 /* Unicode */
14 #include <unistd.h> //u8_* functions
15 #include <unitypes.h> //uint8_t as a char
16 #include <unistr.h> //u32_cpy
17 /* Local */
18 #include "apc.h"
19 #include "ir.h"
20 /* Public */
21 int ir_init(void);
22 void ir_quit(void);
23 int ir_linker(void);
24 int ir_condenser(void);
25 /* Private */
26 struct pagenode_t;
27 extern //apc.c
28 long sys_pagesize;
29 static inline
30 struct ir_framebox_t* ir_set_add_framebox(struct ir_set_t*, uint8_t*);
31 static
32 void ir_free_pages(struct pagenode_t*);
33 static inline
34 int bytes_identical(uint8_t*,uint8_t*);
35 static
36 void* stack_alloc(size_t);
37 /* Memory allocator */
38 struct pagenode_t {
39 struct pagenode_t* next;
40 char* head;
41 char root[];
42 }* pagenode_root, * pagenode_head;
43 #define PN_ALLOCSIZE (sys_pagesize)
44 #define PN_HEADERSIZE() (sizeof(struct pagenode_t*) + sizeof(char*))
45 #define PN_MEMSIZE() (PN_ALLOCSIZE - PN_HEADERSIZE())
46 #define PN_HEADSIZE() (pagenode_head->head - pagenode_head->root)
47 #define PN_HEADSPACE() (PN_MEMSIZE() - PN_HEADSIZE())
48 /* Enumerated types */
49 enum dtype { FSDAT, MSDAT, ADAT, LDAT, FBDAT };
50 enum ltype { OLINK, MLINK, VLINK, ALINK };
51 /* Set data mem */
52 struct ir_setdata_header_t
53 { enum dtype type;
54 uint8_t* src_filename, * data_name;
55 union ir_setdata_t* nextsib;
56 };
57 struct ir_frameinfo_t
58 { int facing, w, h; };
59 struct ir_framedata_t
60 { struct ir_setdata_header_t header;
61 struct ir_frameinfo_t frameinfo;
62 };
63 struct ir_framebox_t
64 { struct ir_setdata_header_t header;
65 struct ir_framedata_t framesheets[FACING_MAX];
66 struct ir_framedata_t mapsheets[FACING_MAX];
67 };
68 struct ir_simplex_t
69 { struct ir_setdata_header_t header; };
70 struct ir_link_t
71 { struct ir_setdata_header_t header;
72 struct ir_set_t* src, * trg;
73 enum ltype type;
74 };
75 union ir_setdata_t
76 { struct ir_setdata_header_t header;
77 struct ir_framebox_t framebox;
78 struct ir_framedata_t framesheet;
79 struct ir_framedata_t mapsheet;
80 struct ir_simplex_t audio;
81 struct ir_link_t link;
82 };
83 struct ir_class_t
84 { struct ir_class_t* nextchild, * nextsib;
85 struct ir_set_t* root_set;
86 uint8_t* name;
87 };
88 struct ir_set_t
89 { struct ir_set_t* nextchild, * nextsib;
90 struct ir_class_t* class;
91 long long ref;
92 uint8_t* name;
93 struct ir_framebox_t* frameboxes;
94 struct ir_simplex_t* audio;
95 struct ir_link_t* links;
96 };
97 /* Function-Like Macros */
98 #define do_warn() do { \
99 } while (0)
100 #define wprint(str) do { \
101 fprintf(stderr, str); \
102 do_warn(); \
103 } while (0)
104 #define wprintf(fmt,...) do { \
105 fprintf(stderr, fmt, __VA_ARGS__); \
106 do_warn(); \
107 } while (0)
108 #define do_error() do { \
109 exit(-1); \
110 } while (0)
111 #define eprint(str) do { \
112 fprintf(stderr, str); \
113 do_error(); \
114 } while (0)
115 #define eprintf(fmt,...) do { \
116 fprintf(stderr, fmt, __VA_ARGS__); \
117 do_error(); \
118 } while (0)
119 #define struct_alloc(_T) ((struct _T*) stack_alloc(sizeof(struct _T)))
120
121 static
122 struct ir_class_t root_class = { .name = (uint8_t*)"." };
123
124 /* Init */
125 int ir_init
126 ( void )
127 { pagenode_root = (struct pagenode_t*) calloc((size_t)PN_ALLOCSIZE,1);
128 if (pagenode_root == NULL)
129 return -1;
130 pagenode_root->head = pagenode_root->root;
131 pagenode_head = pagenode_root;
132 return 0;
133 }
134
135 /* Quit/Cleanup
136 Recursively clean pagenode linked list
137 */
138 void ir_quit
139 ( void )
140 { ir_free_pages(pagenode_root); }
141
142 static
143 void ir_free_pages
144 ( struct pagenode_t* pagenode )
145 { if (pagenode->next != NULL)
146 ir_free_pages(pagenode->next);
147 free(pagenode);
148 }
149
150 /* Link
151 */
152 int ir_linker
153 ( void )
154 { return 0; }
155
156 /* Condense
157 */
158 int ir_condenser
159 ( void )
160 { return 0; }
161
162 /* Return a pointer to the root class */
163 struct ir_class_t* ir_class_root
164 ( void )
165 { return &root_class; }
166
167 /* Add a subclass to a class
168 Attempts to create a new subclass in the provided class, returning
169 the class if it already exists
170 */
171 struct ir_class_t* ir_class_addchild
172 ( struct ir_class_t* class,
173 uint8_t* name
174 )
175 { struct ir_class_t* iter;
176 if (class->nextchild == NULL)
177 return class->nextchild = struct_alloc(ir_class_t);
178 iter = class->nextchild;
179 check:
180 if (bytes_identical(iter->name, name))
181 return iter;
182 if (iter->nextsib != NULL)
183 { iter = iter->nextsib;
184 goto check;
185 }
186 return iter->nextsib = struct_alloc(ir_class_t);
187 }
188
189 /* Add a set to a class
190 Attempts to create a new root set in the specified class, returning
191 the set if it already exists
192 */
193 struct ir_set_t* ir_class_addset
194 ( struct ir_class_t* class,
195 uint8_t* name
196 )
197 { struct ir_set_t* iter;
198 if (class->root_set == NULL)
199 return class->root_set = struct_alloc(ir_set_t);
200 iter = class->root_set;
201 check:
202 if (bytes_identical(iter->name, name))
203 return iter;
204 if (iter->nextsib != NULL)
205 { iter = iter->nextsib;
206 goto check;
207 }
208 return iter->nextsib = struct_alloc(ir_set_t);
209 }
210
211 /* Add a set to a set
212 Attempts to create a new subset of the specified set, returning the
213 child if it already exists
214 */
215 struct ir_set_t* ir_set_addchild
216 ( struct ir_set_t* set,
217 uint8_t* name
218 )
219 { struct ir_set_t* iter;
220 if (set->nextchild == NULL)
221 return set->nextchild = struct_alloc(ir_set_t);
222 iter = set->nextchild;
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 return iter->nextsib = struct_alloc(ir_set_t);
231 }
232
233 /* Add a framebox to a set
234 Attempts to create a new framebox of the specified set, returning
235 the framebox if it already exists
236 */
237 static inline
238 struct ir_framebox_t* ir_set_add_framebox
239 ( struct ir_set_t* set,
240 uint8_t* name
241 )
242 { struct ir_framebox_t* iter;
243 if (set->frameboxes == NULL)
244 return set->frameboxes = struct_alloc(ir_framebox_t);
245 iter = set->frameboxes;
246 check:
247 if (bytes_identical(iter->header.data_name, name))
248 return iter;
249 if (iter->header.nextsib != NULL)
250 { iter = (struct ir_framebox_t*) iter->header.nextsib;
251 goto check;
252 }
253 iter->header.nextsib = (union ir_setdata_t*) struct_alloc(ir_framebox_t);
254 return (struct ir_framebox_t*) iter->header.nextsib;
255 }
256
257 /* Match two null-terminated bytestrings
258 Return 1 if the two bytestrings are identical, else 0
259 */
260 static inline
261 int bytes_identical
262 ( uint8_t* stra,
263 uint8_t* strb
264 )
265 { while (*stra && *strb)
266 if (*stra++ != *strb++)
267 return 0;
268 return *stra == *strb;
269 }
270
271 /* Assign Setdata to Set
272
273 */
274 void ir_set_assign_data
275 ( struct ir_set_t* set,
276 union ir_setdata_t* setdata
277 )
278 { struct ir_framebox_t* framebox;
279 struct ir_simplex_t* simplex;
280 struct ir_link_t* link;
281 switch (setdata->header.type)
282 { case FSDAT:
283 framebox = ir_set_add_framebox(set, setdata->header.data_name);
284 if (framebox->framesheets[setdata->framesheet.frameinfo.facing].header.data_name != NULL)
285 wprintf("Duplicate framesheet [%i] %s\n",
286 setdata->framesheet.frameinfo.facing, setdata->header.data_name);
287 framebox->framesheets[setdata->framesheet.frameinfo.facing] = setdata->framesheet;
288 break;
289 case MSDAT:
290 framebox = ir_set_add_framebox(set, setdata->header.data_name);
291 if (framebox->mapsheets[setdata->mapsheet.frameinfo.facing].header.data_name != NULL)
292 wprintf("Duplicate mapsheet [%i] %s\n",
293 setdata->mapsheet.frameinfo.facing, setdata->header.data_name);
294 framebox->mapsheets[setdata->mapsheet.frameinfo.facing] = setdata->mapsheet;
295 break;
296 case ADAT:
297 if (set->audio == NULL)
298 { set->audio = (struct ir_simplex_t*) setdata;
299 return;
300 }
301 simplex = set->audio;
302 while (simplex->header.nextsib != NULL)
303 if (bytes_identical(simplex->header.data_name, setdata->header.data_name))
304 { wprintf("Duplicate audio %s\n", setdata->header.data_name);
305 *simplex = setdata->audio;
306 //setdata->audio is now a pointer to redundant, unused memory.
307 return;
308 }
309 else
310 simplex = (struct ir_simplex_t*) simplex->header.nextsib;
311 simplex->header.nextsib = setdata;
312 break;
313 case LDAT:
314 if (set->links == NULL)
315 { set->links = (struct ir_link_t*) setdata;
316 return;
317 }
318 link = set->links;
319 while (link->header.nextsib != NULL)
320 link = (struct ir_link_t*) link->header.nextsib;
321 link->header.nextsib = setdata;
322 break;
323 default:
324 fprintf(stderr, "Unknown setdata type %x\n", setdata->header.type);
325 exit(-1);
326 }
327 }
328
329 void ir_set_assign_ref
330 ( struct ir_set_t* set,
331 long long ref
332 )
333 { if (set->ref != 0)
334 wprintf("Ref override: 0x%lx -> 0x%lx for set %s\n",
335 (long unsigned) set->ref, (long unsigned) ref, set->name);
336 set->ref = ref;
337 //TODO: reflist_add(set);
338 }
339
340 void ir_data_assign_path
341 ( union ir_setdata_t* setdata,
342 uint8_t* path
343 )
344 { setdata->header.src_filename = path;
345 //TODO: internal strdup, not assign (= path;)
346 }
347
348
349 //TODO: Macro ir_framsheet and mapsheet?
350 union ir_setdata_t* ir_framesheet
351 ( uint8_t* name,
352 apc_facing d,
353 int width,
354 int height
355 )
356 { struct ir_framedata_t* framesheet = struct_alloc(ir_framedata_t);
357 framesheet->header.type = FSDAT;
358 framesheet->header.data_name = name;
359 framesheet->frameinfo.facing = d;
360 framesheet->frameinfo.w = width;
361 framesheet->frameinfo.h = height;
362 return (union ir_setdata_t*) framesheet;
363 }
364
365 union ir_setdata_t* ir_mapsheet
366 ( uint8_t* name,
367 apc_facing d,
368 int width,
369 int height
370 )
371 { struct ir_framedata_t* mapsheet = struct_alloc(ir_framedata_t);
372 mapsheet->header.type = MSDAT;
373 mapsheet->header.data_name = name;
374 mapsheet->frameinfo.facing = d;
375 mapsheet->frameinfo.w = width;
376 mapsheet->frameinfo.h = height;
377 return (union ir_setdata_t*) mapsheet;
378 }
379
380 union ir_setdata_t* ir_audio
381 ( uint8_t* name )
382 { struct ir_simplex_t* audio = struct_alloc(ir_simplex_t);
383 audio->header.type = ADAT;
384 audio->header.data_name = name;
385 return (union ir_setdata_t*) audio;
386 }
387
388 static
389 void* stack_alloc(size_t bytes)
390 { if (!bytes)
391 { wprint("Attempting to allocate 0 bytes in stack_alloc");
392 return pagenode_head->head;
393 }
394 if (PN_HEADSPACE() < bytes)
395 { pagenode_head->next = (struct pagenode_t*) calloc(PN_ALLOCSIZE,1);
396 pagenode_head = pagenode_head->next;
397 pagenode_head->head = pagenode_head->root;
398 }
399 pagenode_head->head += bytes;
400 return (void*) pagenode_head->head - bytes;
401 }
402