1 /* ======================================================================== */
2 /* BINCFG -- Routines for reading a configuration file for the BIN+CFG */
3 /* file format. Includes debug functions which can generate */
4 /* a new configuration file from the parsed config file. */
5 /* */
6 /* Parser interface functions, intended to be called for reading a .CFG: */
7 /* */
8 /* BC_PARSE_CFG -- Reads a configuration file using the lexer/grammar. */
9 /* BC_READ_DATA -- Reads ROM segments and attaches them to bc_cfgfile_t. */
10 /* BC_DO_MACROS -- Applies macros that can be safely applied statically. */
11 /* BC_FREE_CFG -- Frees all memory associated with a bc_cfgfile_t. */
12 /* */
13 /* Structure printing functions for generating a .CFG from a parsed CFG. */
14 /* The following functions are compiled out if BC_NOPRINT is defined. */
15 /* */
16 /* BC_PRINT_CFG -- Chase through a bc_cfgfile_t structure and print out */
17 /* what we find therein. It calls the following helpers: */
18 /* */
19 /* BC_PRINT_DIAG -- Print all the collected diagnostics attached to cfg */
20 /* BC_PRINT_MACRO -- Print the [macro] section */
21 /* BC_PRINT_MACRO_T -- Print a single bc_macro_t */
22 /* BC_PRINT_VARLIKE -- Print [var],[keys],[joystick] sections */
23 /* BC_PRINT_VAR_T -- Print a single <name>,<value> tuple */
24 /* BC_PRINT_MEMSPAN -- Print out all the memory span information. */
25 /* ======================================================================== */
26
27 #include "config.h"
28 #include "lzoe/lzoe.h"
29 #include "file/file.h"
30 #ifndef BC_NOMETADATA
31 # include "metadata/metadata.h"
32 # include "metadata/cfgvar_metadata.h"
33 #endif
34 #include "bincfg/bincfg.h"
35 #include "bincfg/bincfg_lex.h"
36 #include "bincfg/bincfg_grmr.tab.h"
37
38 bc_cfgfile_t *bc_parsed_cfg = NULL;
39
40 extern int bc_parse(void); /* grrr... bison doesn't do this for us?! */
41
42 /* ======================================================================== */
43 /* BC_PARSE_CFG -- Invokes the lexer and grammar to parse the config. */
44 /* ======================================================================== */
bc_parse_cfg(LZFILE * f,const char * const binfile,const char * const cfgfile)45 bc_cfgfile_t *bc_parse_cfg
46 (
47 LZFILE *f,
48 const char *const binfile,
49 const char *const cfgfile
50 )
51 {
52 bc_memspan_t *span, **prev;
53 int num_preload = 0, num_memattr = 0, need_default = 0, ma, pl;
54 bc_memspan_t **preloads, **memattrs;
55
56 bc_parsed_cfg = NULL;
57
58 /* -------------------------------------------------------------------- */
59 /* Scan in the file, ignoring errors returned directly from bc_parse. */
60 /* All the diagnostics will be attached to whatever cfg we generate. */
61 /* -------------------------------------------------------------------- */
62 if (f)
63 {
64 bc_restart( (FILE*)f ); /* register the file with the lexer. */
65 bc_parse(); /* run the grammar. It calls the bc_lex(). */
66 }
67
68 /* -------------------------------------------------------------------- */
69 /* If not parsing a configuration file, or the file was empty, just */
70 /* make an empty config as a starting point. */
71 /* -------------------------------------------------------------------- */
72 if (!bc_parsed_cfg)
73 {
74 bc_parsed_cfg = CALLOC(bc_cfgfile_t, 1);
75 }
76
77 /* -------------------------------------------------------------------- */
78 /* Leave if we get here without a valid config. */
79 /* -------------------------------------------------------------------- */
80 if (!bc_parsed_cfg)
81 return NULL;
82
83 if (binfile) bc_parsed_cfg->binfile = strdup(binfile);
84 if (cfgfile) bc_parsed_cfg->cfgfile = strdup(cfgfile);
85
86 /* -------------------------------------------------------------------- */
87 /* Scan the memory spans counting up preload sections and non-preload */
88 /* (ie. memattr) sections. We need to apply memattr spans to any */
89 /* preload spans they overlap, but before we do so, we need to */
90 /* allocate some storage. */
91 /* -------------------------------------------------------------------- */
92 for (span = bc_parsed_cfg->span; span;
93 span = (bc_memspan_t*)(span->l.next))
94 {
95 if (span->flags & BC_SPAN_PL) num_preload++;
96 else num_memattr++;
97 }
98
99 /* -------------------------------------------------------------------- */
100 /* If there were no preload sections, we'll need a default config. */
101 /* The default config gets instantiated after we allocate arrays. */
102 /* -------------------------------------------------------------------- */
103 if (num_preload == 0)
104 {
105 num_preload = 3;
106 need_default = 1;
107 }
108
109 /* -------------------------------------------------------------------- */
110 /* Allocate storage for the preload and memattr lists and fill them. */
111 /* -------------------------------------------------------------------- */
112 preloads = CALLOC(bc_memspan_t*, num_preload);
113 memattrs = CALLOC(bc_memspan_t*, num_memattr);
114 assert((preloads && memattrs) || "Out of memory");
115 for (span = bc_parsed_cfg->span, ma = pl = 0; span;
116 span = (bc_memspan_t*)(span->l.next))
117 {
118 if (span->flags & BC_SPAN_PL) preloads[pl++] = span;
119 else memattrs[ma++] = span;
120 }
121 assert( pl == num_preload || (need_default && pl == 0));
122 assert( ma == num_memattr );
123
124 /* -------------------------------------------------------------------- */
125 /* If there were no preload sections, create a default mapping. */
126 /* -------------------------------------------------------------------- */
127 if (need_default)
128 {
129 bc_memspan_t *s0, *s1, *s2;
130
131 if (!(s0 = CALLOC(bc_memspan_t, 1)) ||
132 !(s1 = CALLOC(bc_memspan_t, 1)) ||
133 !(s2 = CALLOC(bc_memspan_t, 1)))
134 {
135 fprintf(stderr, "out of memory\n");
136 exit(1);
137 }
138
139 s0->s_fofs = 0x0000;
140 s0->e_fofs = 0x1FFF;
141 s0->s_addr = 0x5000;
142 s0->e_addr = 0x6FFF;
143 s0->flags = BC_SPAN_R | BC_SPAN_PL;
144 s0->width = 16;
145 s0->epage = BC_SPAN_NOPAGE;
146 s0->f_name = NULL;
147 s0->l.next = NULL;
148
149 s1->s_fofs = 0x2000;
150 s1->e_fofs = 0x2FFF;
151 s1->s_addr = 0xD000;
152 s1->e_addr = 0xDFFF;
153 s1->flags = BC_SPAN_R | BC_SPAN_PL;
154 s1->width = 16;
155 s1->epage = BC_SPAN_NOPAGE;
156 s1->f_name = NULL;
157 s1->l.next = NULL;
158
159 s2->s_fofs = 0x3000;
160 s2->e_fofs = 0x3FFF;
161 s2->s_addr = 0xF000;
162 s2->e_addr = 0xFFFF;
163 s2->flags = BC_SPAN_R | BC_SPAN_PL;
164 s2->width = 16;
165 s2->epage = BC_SPAN_NOPAGE;
166 s2->f_name = NULL;
167 s2->l.next = NULL;
168
169 assert( preloads );
170 assert( num_preload == 3 );
171 preloads[0] = s0;
172 preloads[1] = s1;
173 preloads[2] = s2;
174 }
175
176 /* -------------------------------------------------------------------- */
177 /* Step through all of the memattr sections, applying their attribute */
178 /* flags to overlapping preload sections. This is O(N^2), but who */
179 /* cares, as the total number of spans is at most dozens. (Worse */
180 /* than O(N^2) if we have to split a span.) */
181 /* -------------------------------------------------------------------- */
182 for ( ma = 0 ; ma < num_memattr ; ma++ )
183 {
184 bc_memspan_t *m = memattrs[ma];
185
186 for ( pl = 0 ; pl < num_preload ; pl++ )
187 {
188 bc_memspan_t *p = preloads[pl];
189
190 /* Skip if spans don't overlap */
191 if (m->e_addr < p->s_addr) continue;
192 if (m->s_addr > p->e_addr) continue;
193 if (m->epage != p->epage) continue;
194
195 /* Is p completely inside m? No: split p. Fragments go to end. */
196 if (p->s_addr < m->s_addr)
197 {
198 int np = num_preload++;
199 bc_memspan_t *n;
200 preloads = (bc_memspan_t**)realloc((void*)preloads,
201 num_preload * sizeof(bc_memspan_t*));
202 assert(preloads || "Out of memory");
203
204 n = preloads[np] = CALLOC(bc_memspan_t, 1);
205 assert(preloads[np] || "Out of memory");
206
207 *n = *p;
208
209 n->e_addr = m->s_addr - 1;
210 p->s_addr = m->s_addr;
211 p->s_fofs = p->e_fofs - p->e_addr + p->s_addr;
212 n->e_fofs = n->s_fofs + n->e_addr - n->s_addr;
213 }
214
215 if (p->e_addr > m->e_addr)
216 {
217 int np = num_preload++;
218 bc_memspan_t *n;
219 preloads = (bc_memspan_t**)realloc((void*)preloads,
220 num_preload * sizeof(bc_memspan_t*));
221 assert(preloads || "Out of memory");
222
223 n = preloads[np] = CALLOC(bc_memspan_t, 1);
224 assert(preloads[np] || "Out of memory");
225
226 *n = *p;
227
228 n->s_addr = m->e_addr + 1;
229 p->e_addr = m->e_addr;
230 n->s_fofs = n->e_fofs - n->e_addr + n->s_addr;
231 p->e_fofs = p->s_fofs + p->e_addr - p->s_addr;
232 }
233
234 /* Is m completely inside p? No: split m. Fragments go to end. */
235 if (m->s_addr < p->s_addr)
236 {
237 int nm = num_memattr++;
238 bc_memspan_t *n;
239 memattrs = (bc_memspan_t**)realloc((void*)memattrs,
240 num_memattr * sizeof(bc_memspan_t*));
241 assert(memattrs || "Out of memory");
242
243 n = memattrs[nm] = CALLOC(bc_memspan_t, 1);
244 assert(memattrs[nm] || "Out of memory");
245
246 *n = *m;
247
248 n->e_addr = p->s_addr - 1;
249 m->s_addr = p->s_addr;
250 }
251
252 if (m->e_addr > p->e_addr)
253 {
254 int nm = num_memattr++;
255 bc_memspan_t *n;
256 memattrs = (bc_memspan_t**)realloc((void*)memattrs,
257 num_memattr * sizeof(bc_memspan_t*));
258 assert(memattrs || "Out of memory");
259
260 n = memattrs[nm] = CALLOC(bc_memspan_t, 1);
261 assert(memattrs[nm] || "Out of memory");
262
263 *n = *m;
264
265 n->s_addr = p->e_addr + 1;
266 m->e_addr = p->e_addr;
267 }
268
269 assert(m->s_addr == p->s_addr);
270 assert(m->e_addr == p->e_addr);
271
272 /* Apply the memattr to the preload */
273 p->width = m->width;
274 p->flags = (m->flags | BC_SPAN_PL) & ~BC_SPAN_DEL;
275 m->flags |= BC_SPAN_DEL;
276 }
277 }
278
279 /* -------------------------------------------------------------------- */
280 /* Now reassemble the span list. For memattr spans, only keep the */
281 /* ones not marked BC_SPAN_DEL, as those didn't overlap any preload. */
282 /* -------------------------------------------------------------------- */
283 prev = &(bc_parsed_cfg->span);
284
285 for (pl = 0; pl < num_preload; pl++)
286 {
287 *prev = preloads[pl];
288 prev = (bc_memspan_t**)&(preloads[pl]->l.next);
289 assert( (preloads[pl]->flags & BC_SPAN_DEL) == 0 );
290 }
291
292 for (ma = 0; ma < num_memattr; ma++)
293 {
294 if (memattrs[ma]->flags & BC_SPAN_DEL)
295 {
296 free(memattrs[ma]);
297 continue;
298 }
299 *prev = memattrs[ma];
300 prev = (bc_memspan_t**)&(memattrs[ma]->l.next);
301 }
302 *prev = NULL;
303
304 free(preloads);
305 free(memattrs);
306
307 /* -------------------------------------------------------------------- */
308 /* By default, assume no decoded metadata. */
309 /* -------------------------------------------------------------------- */
310 bc_parsed_cfg->metadata = NULL;
311
312 #ifndef BC_NOMETADATA
313 /* -------------------------------------------------------------------- */
314 /* Parse config variables into a metadata structure. */
315 /* -------------------------------------------------------------------- */
316 bc_parsed_cfg->metadata =
317 bc_parsed_cfg->vars ? game_metadata_from_cfgvars(bc_parsed_cfg->vars)
318 : default_game_metadata();
319 #endif
320 return bc_parsed_cfg;
321 }
322
323 /* ======================================================================== */
324 /* BC_READ_HELPER -- helper function for bc_read_data. */
325 /* ======================================================================== */
bc_read_helper(char * f_name,uint16_t * buf,int width)326 LOCAL int bc_read_helper(char *f_name, uint16_t *buf, int width)
327 {
328 LZFILE *f;
329 int len;
330
331 /* -------------------------------------------------------------------- */
332 /* Open and read up to 64K words from a file. Return how much we */
333 /* actually read from the file to the caller. */
334 /* -------------------------------------------------------------------- */
335 if ((f = lzoe_fopen(f_name, "rb")) == NULL)
336 {
337
338 perror("fopen()");
339 fprintf(stderr, "Could not open binary file '%s' for reading.\n",
340 f_name);
341 return -1;
342 }
343
344 len = width > 8 ? file_read_rom16(f, BC_MAXBIN, buf)
345 : file_read_rom8 (f, BC_MAXBIN, buf);
346
347 if (len < 1)
348 {
349 fprintf(stderr, "Unable to read binary file '%s'\n", f_name);
350 return -1;
351 }
352
353 lzoe_fclose(f);
354
355 return len;
356 }
357
358 /* ======================================================================== */
359 /* BC_READ_DATA -- Reads ROM segments and attaches them to bc_cfgfile_t. */
360 /* */
361 /* This pass will adjust, or remove and free memspans that are partially */
362 /* or completely outside the bounds of the associated binfile. */
363 /* ======================================================================== */
bc_read_data(bc_cfgfile_t * bc)364 int bc_read_data(bc_cfgfile_t *bc)
365 {
366 bc_memspan_t *span, *prev;
367 uint16_t *pbuf, *lbuf, *buf = NULL;
368 size_t plen, llen, len = 0;
369 int slen, i;
370
371 /* -------------------------------------------------------------------- */
372 /* Allocate a temporary buffer for the primary BIN file. Note that */
373 /* we can't just parcel our BIN segments out of this buffer with */
374 /* pointer manipulation unless there is only 1 such segment. This */
375 /* is due to the 'free()' semantics for the ->data field in each */
376 /* memspan. */
377 /* -------------------------------------------------------------------- */
378 if ((pbuf = CALLOC(uint16_t, BC_MAXBIN*2)) == NULL)
379 {
380 fprintf(stderr, "out of memory\n");
381 exit(1);
382 }
383 lbuf = pbuf + BC_MAXBIN;
384
385 for (i = 0; i < BC_MAXBIN; i += 2)
386 {
387 pbuf[i + 0] = 0xDEAD;
388 pbuf[i + 1] = 0xBEEF;
389 lbuf[i + 0] = 0xDEAD;
390 lbuf[i + 1] = 0xBEEF;
391 }
392
393 /* -------------------------------------------------------------------- */
394 /* Load the primary file up front. */
395 /* -------------------------------------------------------------------- */
396 if (!bc->binfile || !file_exists(bc->binfile))
397 {
398 plen = 0;
399 } else
400 {
401 int tmp;
402
403 /* Assume primary binfile is width >= 9. */
404 tmp = bc_read_helper(bc->binfile, pbuf, 16);
405
406 if (tmp < 0) { free(pbuf); return -1; }
407
408 plen = (size_t)tmp;
409 }
410
411 /* -------------------------------------------------------------------- */
412 /* Chase down the spans, attaching ->data to each span. */
413 /* -------------------------------------------------------------------- */
414 for (prev = NULL, span = bc->span; span;
415 prev = span, span = (bc_memspan_t *)(span->l.next))
416 {
417 bc_memspan_t dummy;
418
419 /* ---------------------------------------------------------------- */
420 /* Skip spans that already have data attached -- assume they are */
421 /* correct. These are usually POKE spans. */
422 /* ---------------------------------------------------------------- */
423 if (span->data)
424 continue;
425
426 assert((span->flags & BC_SPAN_PK) == 0);
427
428 /* ---------------------------------------------------------------- */
429 /* Skip spans that dopn't preload a data segment. These would be */
430 /* banksw/memattr spans. */
431 /* ---------------------------------------------------------------- */
432 if ((span->flags & BC_SPAN_PL) == 0)
433 continue;
434
435 /* ---------------------------------------------------------------- */
436 /* Load any file that might be associated with this span. */
437 /* ---------------------------------------------------------------- */
438 if (span->f_name != NULL)
439 {
440 int tmp;
441
442 tmp = bc_read_helper(span->f_name, lbuf, 16);
443
444 if (tmp < 0) { free(pbuf); return -1; }
445
446 llen = (size_t)tmp;
447 len = llen;
448 buf = lbuf;
449 } else if (span->f_name == NULL) /* true if primary-file span. */
450 {
451 len = plen;
452 buf = pbuf;
453 }
454
455 /* ---------------------------------------------------------------- */
456 /* Now attach data from the file to the memspan. We handle spans */
457 /* that go outside the file specially, and differently depending */
458 /* on whether they're writeable. */
459 /* -- Non-writeable, entirely beyond EOF: delete span */
460 /* -- Non-writeable, partially beyond EOF: trim span */
461 /* -- Writeable, entirely beyond EOF: drop preload flag */
462 /* -- Writeable, partially beyond EOF: split and drop preload */
463 /* flag on part beyond EOF. */
464 /* ---------------------------------------------------------------- */
465
466 /* ---------------------------------------------------------------- */
467 /* -- Non-writeable, entirely beyond EOF: delete span */
468 /* ---------------------------------------------------------------- */
469 if (span->s_fofs >= len && (span->flags & BC_SPAN_W) == 0)
470 {
471 ll_t *dead = (ll_t *)span;
472
473 if (!prev)
474 {
475 bc->span = (bc_memspan_t *)span->l.next;
476 dummy.l.next = span->l.next;
477 span = &dummy;
478 } else
479 {
480 prev->l.next = span->l.next;
481 span = prev;
482 }
483 #ifndef BC_NOFREE
484 bc_free_memspan_t(dead, NULL);
485 #endif
486 continue;
487 }
488
489 /* ---------------------------------------------------------------- */
490 /* -- Non-writeable, partially beyond EOF: trim span */
491 /* ---------------------------------------------------------------- */
492 if (span->e_fofs >= len && (span->flags & BC_SPAN_W) == 0)
493 span->e_fofs = len - 1;
494
495 /* ---------------------------------------------------------------- */
496 /* -- Writeable, entirely beyond EOF: drop preload flag */
497 /* ---------------------------------------------------------------- */
498 if (span->s_fofs >= len && (span->flags & BC_SPAN_W) != 0)
499 {
500 span->flags &= ~BC_SPAN_PL;
501 continue;
502 }
503
504 /* ---------------------------------------------------------------- */
505 /* -- Writeable, partially beyond EOF: split and drop preload */
506 /* flag on part beyond EOF. */
507 /* ---------------------------------------------------------------- */
508 if (span->e_fofs >= len && (span->flags & BC_SPAN_W) != 0)
509 {
510 bc_memspan_t *part = CALLOC(bc_memspan_t, 1);
511 *part = *span;
512 part->flags &= BC_SPAN_PL;
513 part->s_fofs = 0;
514 part->e_fofs = 0;
515 part->s_addr = span->s_addr + len - span->s_fofs;
516 span->e_fofs = len - 1;
517 span->e_addr = span->s_addr + span->e_fofs - span->s_fofs;
518 part->l.next = (ll_t *)span;
519 prev->l.next = (ll_t *)part;
520 }
521
522 /* ---------------------------------------------------------------- */
523 /* Allocate span->data and copy over the data from the file. */
524 /* ---------------------------------------------------------------- */
525 slen = span->e_fofs - span->s_fofs + 1;
526 span->e_addr = span->s_addr + slen - 1;
527 span->data = CALLOC(uint16_t, slen);
528
529 if (!span->data) { fprintf(stderr, "out of memory\n"); exit(1); }
530
531 assert(buf);
532 memcpy(span->data, buf + span->s_fofs, slen * sizeof(uint16_t));
533 }
534
535 free(pbuf);
536 return 0;
537 }
538
539
540
541 #ifndef BC_NODOMACRO /* BC_NODOMACRO if you don't want to interpret macros */
542 /* ======================================================================== */
543 /* BC_DO_MACROS -- Applies macros that can be safely applied statically. */
544 /* */
545 /* I offer two modes here: */
546 /* */
547 /* 1. Execute up until the first macro we can't do statically, and */
548 /* */
549 /* 2. Scan the macros, and execute them only if they're all safe */
550 /* to execute or ignore. Special case: We'll go ahead and */
551 /* execute a macro set that ends in a "run" command as long as */
552 /* it's the last macro in the list. */
553 /* */
554 /* Macros that are safe to execute statically: */
555 /* */
556 /* L <file> <width> <addr> 'L'oad <file> of <width> at <addr>. */
557 /* P <addr> <data> 'P'oke <data> at <addr>. */
558 /* */
559 /* Macros that are safe to treat as NOPs during this pass: */
560 /* */
561 /* <n/a> Null macro lines */
562 /* A Shows the instructions 'A'head. */
563 /* I <addr> 'I'nspect data/code at <addr>. */
564 /* W <name> <list> 'W'atch a set of values with label <name>. */
565 /* V 'V'iew emulation display */
566 /* */
567 /* Macros that are NOT safe to execute statically: */
568 /* */
569 /* [0-7] <value> Set register <n> to <value> */
570 /* B Run until next vertical 'B'lank. */
571 /* R 'R'un emulation. */
572 /* T <addr> 'T'race to <addr>. */
573 /* O <addr> Run t'O' <addr>. */
574 /* <unk> Any unknown macros that are in the list. */
575 /* */
576 /* We implement L and P by tacking additional ROM segments to the */
577 /* memspan list. Load and Poke macros implicitly set "Preload" and */
578 /* "Read" attributes. Load may also set 'Narrow' if the ROM is <= 8 bits */
579 /* wide. Poke will set the "POKE" attribute. No others are set. */
580 /* ======================================================================== */
bc_do_macros(bc_cfgfile_t * cfg,int partial_ok)581 int bc_do_macros(bc_cfgfile_t *cfg, int partial_ok)
582 {
583 bc_macro_t *macro;
584 bc_memspan_t *newspan = NULL;
585
586 /* -------------------------------------------------------------------- */
587 /* Trivial case: Zero macros. */
588 /* -------------------------------------------------------------------- */
589 if (!cfg->macro)
590 return 0;
591
592 /* -------------------------------------------------------------------- */
593 /* If given an all-or-nothing directive, prescan macro list to make */
594 /* sure it is acceptable. */
595 /* -------------------------------------------------------------------- */
596 if (!partial_ok)
597 {
598 for (macro = bc_parsed_cfg->macro; macro;
599 macro = (bc_macro_t*)macro->l.next)
600 {
601 if (macro->cmd != BC_MAC_LOAD &&
602 macro->cmd != BC_MAC_POKE &&
603 macro->cmd != BC_MAC_NONE &&
604 macro->cmd != BC_MAC_AHEAD &&
605 macro->cmd != BC_MAC_INSPECT &&
606 macro->cmd != BC_MAC_WATCH &&
607 macro->cmd != BC_MAC_VIEW)
608 break;
609 }
610
611 /* ---------------------------------------------------------------- */
612 /* If we exited before end of list, we're at an unsupported macro. */
613 /* If it's not a "run" macro at the end of the list, refuse it. */
614 /* ---------------------------------------------------------------- */
615 if (macro != NULL &&
616 (macro->l.next != NULL || macro->cmd != BC_MAC_RUN))
617 return -1;
618 }
619
620 /* -------------------------------------------------------------------- */
621 /* Chase down the macro list looking for LOAD/POKE commands. */
622 /* -------------------------------------------------------------------- */
623 for (macro = bc_parsed_cfg->macro; macro;
624 macro = (bc_macro_t*)macro->l.next)
625 {
626 if (macro->cmd == BC_MAC_LOAD || macro->cmd == BC_MAC_POKE)
627 {
628 newspan = CALLOC(bc_memspan_t, 1);
629 if (!newspan)
630 {
631 fprintf(stderr, "like, out of memory or something\n");
632 exit(1);
633 }
634
635 newspan->l.next = NULL;
636
637 /* Inefficient, but called very rarely. */
638 LL_CONCAT(bc_parsed_cfg->span, newspan, bc_memspan_t);
639 }
640
641 switch (macro->cmd)
642 {
643 case BC_MAC_LOAD :
644 {
645 newspan->s_fofs = 0;
646 newspan->e_fofs = 0xFFFF;
647 newspan->s_addr = macro->arg.load.addr;
648 newspan->e_addr = 0; /* calculated on the fly. */
649 newspan->width = macro->arg.load.width;
650 newspan->flags = BC_SPAN_PL | BC_SPAN_R;
651 newspan->epage = BC_SPAN_NOPAGE;
652 newspan->f_name = strdup(macro->arg.load.name);
653
654 if (newspan->width <= 8)
655 newspan->flags |= BC_SPAN_N;
656
657 break;
658 }
659
660 case BC_MAC_POKE :
661 {
662 if (!(newspan->data = CALLOC(uint16_t, 1)))
663 {
664 fprintf(stderr, "out of memory\n");
665 exit(1);
666 }
667
668 newspan->s_fofs = 0;
669 newspan->e_fofs = 0;
670 newspan->s_addr = macro->arg.poke.addr;
671 newspan->e_addr = macro->arg.poke.addr;
672 newspan->width = 16;
673 newspan->flags = BC_SPAN_PL | BC_SPAN_R | BC_SPAN_PK;
674 newspan->epage = macro->arg.poke.epage;
675 newspan->f_name = NULL;
676 newspan->data[0] = macro->arg.poke.value;
677
678 if (macro->arg.poke.epage != BC_SPAN_NOPAGE)
679 newspan->flags |= BC_SPAN_EP;
680
681 break;
682 }
683
684 case BC_MAC_NONE:
685 case BC_MAC_AHEAD:
686 case BC_MAC_WATCH:
687 case BC_MAC_VIEW:
688 {
689 /* ignore */
690 break;
691 }
692
693 default:
694 {
695 macro = NULL; /* force loop to terminate. */
696 break;
697 }
698 }
699 newspan = NULL;
700 }
701
702
703 return 0;
704 }
705 #endif
706
707
708 #ifndef BC_NOFREE /* BC_NOFREE if you have no intention of freeing a cfg */
709 /* ======================================================================== */
710 /* BC_FREE_CFG -- Release storage held by bc_cfgfile_t. */
711 /* */
712 /* Helper functions for FREE_CFG: */
713 /* */
714 /* BC_FREE_MEMSPAN_T -- Releases storage associated with bc_memspan_t. */
715 /* BC_FREE_MACRO_T -- Releases storage associated with bc_macro_t. */
716 /* BC_FREE_DIAG_T -- Releases storage associated with bc_diag_t */
717 /* ======================================================================== */
718 #ifndef CONDFREE
719 # define CONDFREE(x) do { if (x) free(x); } while (0)
720 #endif
721
722 /* ======================================================================== */
723 /* BC_FREE_MEMSPAN_T -- Releases storage associated with bc_memspan_t. */
724 /* ======================================================================== */
bc_free_memspan_t(ll_t * l_mem,void * unused)725 void bc_free_memspan_t(ll_t *l_mem, void *unused)
726 {
727 bc_memspan_t *mem = (bc_memspan_t*)l_mem;
728 UNUSED(unused);
729
730 CONDFREE(mem->f_name);
731 CONDFREE(mem->data);
732 free(mem);
733 }
734
735 /* ======================================================================== */
736 /* BC_FREE_MACRO_T -- Releases storage associated with bc_macro_t. */
737 /* ======================================================================== */
bc_free_macro_t(ll_t * l_mac,void * unused)738 void bc_free_macro_t(ll_t *l_mac, void *unused)
739 {
740 bc_macro_t *mac = (bc_macro_t *)l_mac;
741
742 UNUSED(unused);
743
744 switch (mac->cmd)
745 {
746 case BC_MAC_LOAD: CONDFREE(mac->arg.load.name); break;
747
748 case BC_MAC_WATCH: CONDFREE(mac->arg.watch.name);
749 CONDFREE(mac->arg.watch.addr); break;
750
751 default: /* nothing */ ;
752 }
753 free(mac);
754 }
755
756 /* ======================================================================== */
757 /* BC_FREE_DIAG_T -- Releases storage associated with bc_diag_t */
758 /* ======================================================================== */
bc_free_diag_t(ll_t * l_diag,void * unused)759 void bc_free_diag_t(ll_t *l_diag, void *unused)
760 {
761 bc_diag_t *diag = (bc_diag_t *)l_diag;
762
763 UNUSED(unused);
764
765 CONDFREE(diag->sect);
766 CONDFREE(diag->msg);
767 free(diag);
768 }
769
770
771 /* ======================================================================== */
772 /* BC_FREE_CFG -- Release storage held by bc_cfgfile_t. */
773 /* ======================================================================== */
bc_free_cfg(bc_cfgfile_t * cfg)774 void bc_free_cfg(bc_cfgfile_t *cfg)
775 {
776 CONDFREE(cfg->cfgfile);
777 CONDFREE(cfg->binfile);
778
779 if (cfg->span ) LL_ACTON(cfg->span, bc_free_memspan_t, NULL);
780 if (cfg->macro ) LL_ACTON(cfg->macro, bc_free_macro_t, NULL);
781 if (cfg->vars ) free_cfg_var_list( cfg->vars );
782 if (cfg->keys[0] ) free_cfg_var_list( cfg->keys[0] );
783 if (cfg->keys[1] ) free_cfg_var_list( cfg->keys[1] );
784 if (cfg->keys[2] ) free_cfg_var_list( cfg->keys[2] );
785 if (cfg->keys[3] ) free_cfg_var_list( cfg->keys[3] );
786 if (cfg->joystick) free_cfg_var_list( cfg->joystick );
787 if (cfg->diags ) LL_ACTON(cfg->diags, bc_free_diag_t, NULL);
788
789 #ifndef BC_NOMETADATA
790 if (cfg->metadata) free_game_metadata( cfg->metadata );
791 #endif
792
793 free(cfg);
794 }
795 #endif
796
797
798 #ifndef BC_NOPRINT
799 /* ======================================================================== */
800 /* BC_PRINT_CFG -- Chase through a bc_cfgfile_t structure and print out */
801 /* what we find therein. */
802 /* */
803 /* Helper functions for PRINT_CFG: */
804 /* */
805 /* BC_PRINT_DIAG -- Print all the collected diagnostics attached to cfg */
806 /* BC_PRINT_MACRO -- Print the [macro] section */
807 /* BC_PRINT_VARLIKE -- Print [var],[keys],[joystick] sections */
808 /* BC_PRINT_MEMSPAN -- Print out all the memory span information. */
809 /* ======================================================================== */
810
811 /* ======================================================================== */
812 /* BC_PRINT_DIAG -- Print all the collected diagnostics attached to cfg */
813 /* ======================================================================== */
bc_print_diag(printer_t * RESTRICT const p,const char * RESTRICT const fname,const bc_diag_t * RESTRICT const diag,const int cmt)814 void bc_print_diag
815 (
816 printer_t *RESTRICT const p,
817 const char *RESTRICT const fname,
818 const bc_diag_t *RESTRICT const diag,
819 const int cmt
820 )
821 {
822 const bc_diag_t *RESTRICT d;
823 int tot_warn = 0, tot_err = 0;
824
825 /* -------------------------------------------------------------------- */
826 /* Step through the list and dump these out. If cmt != 0, put a */
827 /* semicolon before each line. */
828 /* -------------------------------------------------------------------- */
829 for (d = diag; d; d = (const bc_diag_t *)d->l.next)
830 {
831 p->fxn(p->opq, "%s%s:%d:%s %s: %s\015\012",
832 cmt ? "; " : "", fname, d->line,
833 d->sect ? d->sect : "<toplevel?>",
834 d->type == BC_DIAG_WARNING ? "warning" : "error",
835 d->msg ? d->msg : "out of memory?");
836 if (d->type == BC_DIAG_WARNING) tot_warn++; else tot_err++;
837 }
838
839 /* -------------------------------------------------------------------- */
840 /* If we had any warnings or errors, print summary information. */
841 /* -------------------------------------------------------------------- */
842 if (tot_warn || tot_err)
843 {
844 p->fxn(p->opq, "%s%d warnings, %d errors\015\012",
845 cmt ? "; " : "", tot_warn, tot_err);
846 }
847 }
848
849 /* ======================================================================== */
850 /* BC_PRINT_MACRO_T -- Print a single macro_t structure. */
851 /* ======================================================================== */
bc_print_macro_t(ll_t * const l_mac,void * RESTRICT const v_p)852 LOCAL void bc_print_macro_t(ll_t *const l_mac, void *RESTRICT const v_p)
853 {
854 const bc_macro_t *RESTRICT const mac = (bc_macro_t*)l_mac;
855 const printer_t *RESTRICT const p = (printer_t*)v_p;
856
857 if (mac->quiet)
858 p->fxn(p->opq, "@");
859
860 switch (mac->cmd)
861 {
862 case BC_MAC_NONE: { p->fxn(p->opq, ";"); break; }
863 case BC_MAC_AHEAD: { p->fxn(p->opq, "A"); break; }
864 case BC_MAC_BLANK: { p->fxn(p->opq, "B"); break; }
865 case BC_MAC_RUN: { p->fxn(p->opq, "R"); break; }
866 case BC_MAC_VIEW: { p->fxn(p->opq, "V"); break; }
867
868 case BC_MAC_REG:
869 {
870 p->fxn(p->opq, "%d $%.4X", mac->arg.reg.reg, mac->arg.reg.value);
871 break;
872 }
873
874 case BC_MAC_INSPECT:
875 {
876 p->fxn(p->opq, "I $%.4X", mac->arg.inspect.addr);
877 break;
878 }
879
880 case BC_MAC_POKE:
881 {
882 p->fxn(p->opq, "P $%.4X $%.4X",
883 mac->arg.poke.addr, mac->arg.poke.value);
884 break;
885 }
886
887 case BC_MAC_LOAD:
888 {
889 p->fxn(p->opq, "L %s %d $%.4X",
890 cfg_quote_str( mac->arg.load.name ),
891 mac->arg.load.width,
892 mac->arg.load.addr);
893 break;
894 }
895
896 case BC_MAC_RUNTO:
897 {
898 p->fxn(p->opq, "O $%.4X", mac->arg.runto.addr);
899 break;
900 }
901
902 case BC_MAC_TRACE:
903 {
904 p->fxn(p->opq, "T $%.4X", mac->arg.runto.addr);
905 break;
906 }
907
908 case BC_MAC_WATCH:
909 {
910 int i, lo, hi;
911
912 p->fxn(p->opq, "W %s ", mac->arg.watch.name);
913 for (i = 0; i < mac->arg.watch.spans; i++)
914 {
915 if (i)
916 p->fxn(p->opq, ",");
917
918 lo = mac->arg.watch.addr[2*i + 0];
919 hi = mac->arg.watch.addr[2*i + 1];
920
921 if (lo == hi) p->fxn(p->opq, "$%.4X", lo);
922 else p->fxn(p->opq, "$%.4X-$%.4X", lo, hi);
923 }
924 break;
925 }
926
927 case BC_MAC_ERROR:
928 default:
929 {
930 p->fxn(p->opq, "; unknown macro\015\012");
931 break;
932 }
933 }
934
935 p->fxn(p->opq, "\015\012");
936 }
937
938 /* ======================================================================== */
939 /* BC_PRINT_MACRO -- Print the [macro] section */
940 /* ======================================================================== */
bc_print_macro(printer_t * RESTRICT const p,bc_macro_t * RESTRICT const mac)941 void bc_print_macro(printer_t *RESTRICT const p,
942 bc_macro_t *RESTRICT const mac)
943 {
944 /* -------------------------------------------------------------------- */
945 /* Step through the macro list, regenerating each macro. */
946 /* -------------------------------------------------------------------- */
947 p->fxn(p->opq, "\015\012[macro]\015\012");
948 LL_ACTON(mac, bc_print_macro_t, (void *)p);
949 }
950
951 /* ======================================================================== */
952 /* BC_PRINT_VARLIKE -- Print [var],[keys],[joystick] sections */
953 /* ======================================================================== */
bc_print_varlike(printer_t * RESTRICT const p,cfg_var_t * RESTRICT const varlike,const char * RESTRICT const sectname)954 void bc_print_varlike
955 (
956 printer_t *RESTRICT const p,
957 cfg_var_t *RESTRICT const varlike,
958 const char *RESTRICT const sectname
959 )
960 {
961 /* -------------------------------------------------------------------- */
962 /* Real easy: Just step thru the list and print all the tuples. */
963 /* -------------------------------------------------------------------- */
964 p->fxn(p->opq, "\015\012%s\015\012", sectname);
965 print_cfg_var_list( varlike, p );
966 }
967
968 /* ======================================================================== */
969 /* BC_PRINT_MEMSPAN -- Print out all the memory span information. */
970 /* ======================================================================== */
bc_print_memspan(printer_t * RESTRICT const p,const bc_memspan_t * RESTRICT const mem)971 void bc_print_memspan
972 (
973 printer_t *RESTRICT const p,
974 const bc_memspan_t *RESTRICT const mem
975 )
976 {
977 const bc_memspan_t *RESTRICT m;
978 int need_hdr;
979
980 /* -------------------------------------------------------------------- */
981 /* First print out a 'raw' list as a comment. */
982 /* -------------------------------------------------------------------- */
983 m = mem;
984 while (m)
985 {
986 p->fxn(p->opq,
987 "; $%.4X - $%.4X => $%.4X - $%.4X PAGE %X "
988 "FLAGS %c%c%c%c%c%c%c from \"%s\"\015\012",
989 m->s_fofs, m->e_fofs, m->s_addr, m->e_addr, m->epage,
990 m->flags & BC_SPAN_R ? 'R' : '-',
991 m->flags & BC_SPAN_W ? 'W' : '-',
992 m->flags & BC_SPAN_N ? 'N' : '-',
993 m->flags & BC_SPAN_B ? 'B' : '-',
994 m->flags & BC_SPAN_PL ? 'L' : '-',
995 m->flags & BC_SPAN_PK ? 'K' : '-',
996 m->flags & BC_SPAN_EP ? 'E' : '-',
997 m->f_name ? m->f_name : "(primary)"
998 );
999
1000 m = (bc_memspan_t *)m->l.next;
1001 }
1002
1003 /* -------------------------------------------------------------------- */
1004 /* Next, try to print it out as CFG sections. The CFG format is */
1005 /* kinda odd, but since we just parsed the config, it should be easy. */
1006 /* */
1007 /* The following truth table indicates how the attributes map back */
1008 /* to different sections. */
1009 /* */
1010 /* R W N B PL PK EP Section Format */
1011 /* R - x x PL - - [mapping] $xxxx - $xxxx = $xxxx */
1012 /* - W x x PL - - [mapping] $xxxx - $xxxx = $xxxx WOM w */
1013 /* R W x x PL - - [mapping] $xxxx - $xxxx = $xxxx RAM w */
1014 /* R - x x PL - EP [mapping] $xxxx - $xxxx = $xxxx PAGE p */
1015 /* - W x x PL - EP [mapping] $xxxx - $xxxx = $xxxx PAGE p WOM w */
1016 /* R W x x PL - EP [mapping] $xxxx - $xxxx = $xxxx PAGE p RAM w */
1017 /* - - x x PL - - [preload] $xxxx - $xxxx = $xxxx */
1018 /* x x x B x - x [bankswitch] $xxxx - $xxxx */
1019 /* R - x x - - - [memattr] $xxxx - $xxxx = ROM d */
1020 /* - W x x - - - [memattr] $xxxx - $xxxx = WOM d */
1021 /* R W x x - - - [memattr] $xxxx - $xxxx = RAM d */
1022 /* R - x x - - EP [memattr] $xxxx - $xxxx = PAGE p ROM d */
1023 /* - W x x - - EP [memattr] $xxxx - $xxxx = PAGE p WOM d */
1024 /* R W x x - - EP [memattr] $xxxx - $xxxx = PAGE p RAM d */
1025 /* -------------------------------------------------------------------- */
1026
1027
1028 /* -------------------------------------------------------------------- */
1029 /* Get all the [mapping] sections. */
1030 /* -------------------------------------------------------------------- */
1031 need_hdr = 1;
1032 for (m = mem; m; m = (bc_memspan_t *)m->l.next)
1033 {
1034 if (
1035 !(
1036 (m->flags & BC_SPAN_PL) &&
1037 (m->flags & (BC_SPAN_R | BC_SPAN_W))
1038 ) ||
1039 (m->flags & BC_SPAN_PK) ||
1040 (m->f_name != NULL))
1041 continue;
1042
1043 if (need_hdr)
1044 {
1045 p->fxn(p->opq, "\015\012[mapping]\015\012");
1046 need_hdr = 0;
1047 }
1048
1049 p->fxn(p->opq, "$%.4X - $%.4X = $%.4X",
1050 m->s_fofs, m->e_fofs, m->s_addr);
1051
1052 if (m->flags & BC_SPAN_EP)
1053 p->fxn(p->opq, " PAGE %X", m->epage);
1054
1055 switch (m->flags & (BC_SPAN_R | BC_SPAN_W))
1056 {
1057 case BC_SPAN_ROM:
1058 if ( m->width != 16 )
1059 p->fxn(p->opq, " ROM %d", m->width); /* Weird... */
1060 break;
1061 case BC_SPAN_WOM:
1062 p->fxn(p->opq, " WOM %d", m->width);
1063 break;
1064 case BC_SPAN_RAM:
1065 p->fxn(p->opq, " RAM %d", m->width);
1066 break;
1067 default:
1068 p->fxn(p->opq, " ; unknown!");
1069 break;
1070 }
1071 p->fxn(p->opq, "\015\012");
1072 }
1073
1074 /* -------------------------------------------------------------------- */
1075 /* Get all the [preload] sections. */
1076 /* -------------------------------------------------------------------- */
1077 need_hdr = 1;
1078 for (m = mem; m; m = (bc_memspan_t *)m->l.next)
1079 {
1080 if ((m->flags & (BC_SPAN_R|BC_SPAN_W|BC_SPAN_PL)) != (BC_SPAN_PL) ||
1081 (m->flags & BC_SPAN_PK) ||
1082 (m->f_name != NULL))
1083 continue;
1084
1085 if (need_hdr)
1086 {
1087 p->fxn(p->opq, "\015\012[preload]\015\012");
1088 need_hdr = 0;
1089 }
1090
1091 if (m->flags & BC_SPAN_EP)
1092 p->fxn(p->opq, "$%.4X - $%.4X = $%.4X PAGE %X\015\012",
1093 m->s_fofs, m->e_fofs, m->s_addr, m->epage);
1094 else
1095 p->fxn(p->opq, "$%.4X - $%.4X = $%.4X\015\012",
1096 m->s_fofs, m->e_fofs, m->s_addr);
1097 }
1098
1099 /* -------------------------------------------------------------------- */
1100 /* Get all the [bankswitch] sections. */
1101 /* -------------------------------------------------------------------- */
1102 need_hdr = 1;
1103 for (m = mem; m; m = (bc_memspan_t *)m->l.next)
1104 {
1105 if ((m->flags & (BC_SPAN_B)) != (BC_SPAN_B) ||
1106 (m->flags & BC_SPAN_PK))
1107 continue;
1108
1109 if (need_hdr)
1110 {
1111 p->fxn(p->opq, "\015\012[bankswitch]\015\012");
1112 need_hdr = 0;
1113 }
1114
1115 p->fxn(p->opq, "$%.4X - $%.4X\015\012", m->s_addr, m->e_addr);
1116 }
1117
1118
1119 /* -------------------------------------------------------------------- */
1120 /* Get all the [memattr] sections. */
1121 /* -------------------------------------------------------------------- */
1122 need_hdr = 1;
1123 for (m = mem; m; m = (bc_memspan_t *)m->l.next)
1124 {
1125 if ((m->flags & (BC_SPAN_R | BC_SPAN_W)) == 0 ||
1126 (m->flags & BC_SPAN_PL) ||
1127 (m->flags & BC_SPAN_PK))
1128 continue;
1129
1130 if (need_hdr)
1131 {
1132 p->fxn(p->opq, "\015\012[memattr]\015\012");
1133 need_hdr = 0;
1134 }
1135
1136 p->fxn(p->opq, "$%.4X - $%.4X =", m->s_addr, m->e_addr);
1137
1138 if (m->flags & BC_SPAN_EP)
1139 p->fxn(p->opq, " PAGE %X", m->epage);
1140
1141 switch (m->flags & (BC_SPAN_R | BC_SPAN_W))
1142 {
1143 case BC_SPAN_ROM:
1144 p->fxn(p->opq, " ROM %d", m->width);
1145 break;
1146 case BC_SPAN_WOM:
1147 p->fxn(p->opq, " WOM %d", m->width);
1148 break;
1149 case BC_SPAN_RAM:
1150 p->fxn(p->opq, " RAM %d", m->width);
1151 break;
1152 default:
1153 p->fxn(p->opq, " ; unknown!");
1154 break;
1155 }
1156 p->fxn(p->opq, "\015\012");
1157 }
1158 }
1159
1160 /* ======================================================================== */
1161 /* BC_PRINT_CFG -- Chase through a bc_cfgfile_t structure and print out */
1162 /* what we find therein. */
1163 /* ======================================================================== */
bc_print_cfg(printer_t * RESTRICT const p,const bc_cfgfile_t * RESTRICT const bc)1164 void bc_print_cfg
1165 (
1166 printer_t *RESTRICT const p,
1167 const bc_cfgfile_t *RESTRICT const bc
1168 )
1169 {
1170 if (bc->diags) bc_print_diag (p, bc->cfgfile, bc->diags, 1 );
1171 if (bc->span) bc_print_memspan(p, bc->span );
1172 if (bc->macro) bc_print_macro (p, bc->macro );
1173 if (bc->vars) bc_print_varlike(p, bc->vars, "[vars]" );
1174 if (bc->keys[0]) bc_print_varlike(p, bc->keys[0], "[keys]" );
1175 if (bc->keys[1]) bc_print_varlike(p, bc->keys[1], "[capslock]" );
1176 if (bc->keys[2]) bc_print_varlike(p, bc->keys[2], "[numlock]" );
1177 if (bc->keys[3]) bc_print_varlike(p, bc->keys[3], "[scrolllock]" );
1178 if (bc->joystick) bc_print_varlike(p, bc->joystick, "[joystick]" );
1179 }
1180
1181 #endif /* BC_NOPRINT */
1182
1183
1184 /* ======================================================================== */
1185 /* This program is free software; you can redistribute it and/or modify */
1186 /* it under the terms of the GNU General Public License as published by */
1187 /* the Free Software Foundation; either version 2 of the License, or */
1188 /* (at your option) any later version. */
1189 /* */
1190 /* This program is distributed in the hope that it will be useful, */
1191 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
1192 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
1193 /* General Public License for more details. */
1194 /* */
1195 /* You should have received a copy of the GNU General Public License along */
1196 /* with this program; if not, write to the Free Software Foundation, Inc., */
1197 /* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
1198 /* ======================================================================== */
1199 /* Copyright (c) 2003-+Inf, Joseph Zbiciak */
1200 /* ======================================================================== */
1201