1 /*
2 * ============================================================================
3 * Title: Configuration Manager
4 * Author: J. Zbiciak
5 * ============================================================================
6 * This module manages the machine configuration. It does commandline
7 * parsing and processes the configuration elements that were read in
8 * via the config-file parser.
9 *
10 * CFG owns the entire machine -- it is encapsulated in a cfg_t.
11 * ============================================================================
12 * CFG_INIT -- Parse command line and get started
13 * CFG_FILE -- Parse a config file and extend the state of the machine.
14 * ============================================================================
15 */
16
17
18 #include "config.h"
19 #include "lzoe/lzoe.h"
20 #include "file/file.h"
21 #include "periph/periph.h"
22 #include "cp1600/cp1600.h"
23 #include "cp1600/emu_link.h"
24 #include "cheat/cheat.h"
25 #include "mem/mem.h"
26 #include "ecs/ecs.h"
27 #include "icart/icart.h"
28 #include "bincfg/bincfg.h"
29 #include "bincfg/legacy.h"
30 #include "pads/pads.h"
31 #include "pads/pads_cgc.h"
32 #include "pads/pads_intv2pc.h"
33 #include "avi/avi.h"
34 #include "gfx/gfx.h"
35 #include "gfx/palette.h"
36 #include "snd/snd.h"
37 #include "ay8910/ay8910.h"
38 #include "demo/demo.h"
39 #include "stic/stic.h"
40 #include "ivoice/ivoice.h"
41 #include "speed/speed.h"
42 #include "debug/debug_.h"
43 #include "event/event.h"
44 #include "joy/joy.h"
45 #include "serializer/serializer.h"
46 #include "jlp/jlp.h"
47 #include "plat/plat.h"
48 #include "plat/plat_lib.h"
49 #include "misc/file_crc32.h"
50 #include "metadata/metadata.h"
51 #include "metadata/print_metadata.h"
52 #include "name/name.h"
53 #include "debug/source.h"
54 #include "file/elfi.h"
55 #include "locutus/locutus_adapt.h"
56 #include "mapping.h"
57 #include "cfg.h"
58
59 #include <errno.h>
60
61 LOCAL path_t *rom_path;
62
63 void cfg_default(event_t *event);
64
65 /* ======================================================================== */
66 /* CFG_GET_EVTACT -- Convert an event action name into an event action */
67 /* index. This is a horrible linear search. :-P */
68 /* Hey, it works for now. */
69 /* ======================================================================== */
cfg_get_evtact(const char * event_action_name)70 int cfg_get_evtact(const char *event_action_name)
71 {
72 int i;
73
74 for (i = 0; i < cfg_event_action_cnt; i++)
75 {
76 if (!strcmp(cfg_event_action[i].name, event_action_name))
77 return i;
78 }
79
80 return -1;
81 }
82
83 /* ======================================================================== */
84 /* CFG_SETBIND -- Set all of the key-bindings for the Intellivision. */
85 /* ======================================================================== */
cfg_setbind(cfg_t * cfg,const char * kbdhackfile)86 int cfg_setbind(cfg_t *cfg, const char *kbdhackfile)
87 {
88 int i, j, map;
89 LZFILE *f = NULL;
90 int action;
91 char buf[256];
92
93 /* -------------------------------------------------------------------- */
94 /* Iterate over the bindings table. */
95 /* -------------------------------------------------------------------- */
96 for (i = 0; cfg->binding[i].key != NULL; i++)
97 {
98 /* ---------------------------------------------------------------- */
99 /* Iterate over the four possible "event spaces" that the user */
100 /* may have configured. For instance, the user may have set up */
101 /* "Normal", "Swapped", "Alpha-numeric", and one other. */
102 /* ---------------------------------------------------------------- */
103 for (j = 0; j < 4; j++)
104 {
105 /* ------------------------------------------------------------ */
106 /* Skip empty event bindings. These keys aren't bound. */
107 /* ------------------------------------------------------------ */
108 if (!cfg->binding[i].event_action[j] ||
109 !cfg->binding[i].event_action[j][0])
110 continue;
111
112 /* ------------------------------------------------------------ */
113 /* Look up the event name, and skip if the name is invalid. */
114 /* ------------------------------------------------------------ */
115 if ((action = cfg_get_evtact(cfg->binding[i].event_action[j])) < 0)
116 {
117 fprintf(stderr, "cfg: Invalid event action '%s'\n",
118 cfg->binding[i].event_action[j]);
119 continue;
120 }
121
122 /* ------------------------------------------------------------ */
123 /* Map the key to the event. */
124 /* ------------------------------------------------------------ */
125 event_map(&cfg->event, cfg->binding[i].key, j,
126 cfg_event_action[action].word,
127 cfg_event_action[action].and_mask,
128 cfg_event_action[action].or_mask);
129 }
130 }
131
132 /* -------------------------------------------------------------------- */
133 /* HACK: If the user specified a keyboard mapping file, read that in. */
134 /* -------------------------------------------------------------------- */
135 if (!kbdhackfile)
136 return 0;
137
138 if (!(f = lzoe_fopen(kbdhackfile, "r")))
139 {
140 fprintf(stderr, "Couldn't open keyboard map file '%s'\n", kbdhackfile);
141 exit(1);
142 }
143
144 map = 0;
145 while (lzoe_fgets(buf, 256, f) != NULL)
146 {
147 char *s1, *s2;
148 char cmd[256], arg[256], arg2[256], arg3[256];
149 int bad, too_many;
150
151 bad = too_many = 0;
152
153 if ((s1 = strchr (buf, ';' ))) *s1 = 0;
154 if ((s1 = strrchr(buf, '\r'))) *s1 = 0;
155 if ((s1 = strrchr(buf, '\n'))) *s1 = 0;
156
157 cmd[0] = 0;
158 arg[0] = 0;
159
160
161 s1 = buf;
162 while (*s1 && isspace(*s1)) s1++;
163
164 s2 = cmd;
165 while (*s1 && !isspace(*s1) && s2 < &cmd[255]) *s2++ = *s1++;
166 if (s2 >= &cmd[255]) bad = 1;
167 *s2 = 0;
168
169 while (*s1 && isspace(*s1)) s1++;
170
171 s2 = arg;
172 while (*s1 && !isspace(*s1) && s2 < &arg[255]) *s2++ = *s1++;
173 if (s2 >= &arg[255]) bad = 2;
174 *s2 = 0;
175
176 while (*s1 && isspace(*s1)) s1++;
177
178 s2 = arg2;
179 while (*s1 && !isspace(*s1) && s2 < &arg2[255]) *s2++ = *s1++;
180 if (s2 >= &arg2[255]) bad = 3;
181 *s2 = 0;
182
183 while (*s1 && isspace(*s1)) s1++;
184
185 s2 = arg3;
186 while (*s1 && !isspace(*s1) && s2 < &arg3[255]) *s2++ = *s1++;
187 if (s2 >= &arg3[255]) bad = 4;
188 *s2 = 0;
189
190 while (*s1 && isspace(*s1)) s1++;
191
192 if (*s1) too_many = 1;
193
194 if (bad)
195 {
196 fprintf(stderr, "cfg: Fatal error (argument too long?) parsing "
197 "kbdhackfile (%d)\n", bad);
198 goto fail;
199 }
200
201 if (!too_many && !stricmp(cmd, "add_combo"))
202 {
203 j = atoi(arg);
204
205 jzp_printf("cfg: Combining %s and %s as COMBO%d\n", arg2, arg3, j);
206
207 if (j > 63 || j < 0)
208 {
209 fprintf(stderr, "cfg: COMBO number out of range\n");
210 goto fail;
211 }
212
213 if (event_combine(&cfg->event, arg2, arg3, j))
214 {
215 fprintf(stderr, "cfg: Error registering combo\n");
216 goto fail;
217 }
218
219 continue;
220 }
221
222 if (arg2[0] != 0 || arg3[0] != 0 || too_many)
223 {
224 fprintf(stderr, "cfg: Too many arguments in kbdhackfile:\n> %s\n",
225 buf);
226 fprintf(stderr, "cmd='%s' arg='%s' arg2='%s' arg3='%s' s1='%s'\n",
227 cmd,arg,arg2,arg3,s1);
228 goto fail;
229 }
230
231 if (!stricmp(cmd, "combo_delay"))
232 {
233 double ms = atof(arg);
234
235 if (ms < 0. || ms > 100.)
236 {
237 fprintf(stderr, "cfg: COMBO_DELAY out of range.\n");
238 goto fail;
239 }
240
241 jzp_printf("cfg: Setting combo event delay to %5.2fms\n", ms);
242
243 event_set_combo_coalesce(&cfg->event, ms / 1000.);
244 continue;
245 }
246
247 if (!stricmp(cmd, "map"))
248 {
249 map = atoi(arg);
250
251 if (map < 0 || map > 3)
252 {
253 fprintf(stderr, "cfg: Map number out of range\n");
254 goto fail;
255 }
256 continue;
257 }
258
259 if (cmd[0] == 0 || arg[0] == 0)
260 {
261 if (cmd[0])
262 {
263 fprintf(stderr, "cfg: Unknown command '%s' in %s\n",
264 cmd, kbdhackfile);
265 goto fail;
266 }
267 continue;
268 }
269
270 jzp_printf("cfg: Binding %s to %s in map %d\n", cmd, arg, map);
271
272 if ((action = cfg_get_evtact(arg)) < 0)
273 {
274 fprintf(stderr, "cfg: Invalid event action '%s'\n", arg);
275 goto fail;
276 }
277
278 event_map(&cfg->event, cmd, map,
279 cfg_event_action[action].word,
280 cfg_event_action[action].and_mask,
281 cfg_event_action[action].or_mask);
282 }
283
284 lzoe_fclose(f);
285 return 0;
286
287 fail:
288 if (f) lzoe_fclose(f);
289 return -1;
290 }
291 /* ======================================================================== */
292 /* Built-in display resolutions. */
293 /* ======================================================================== */
294 LOCAL const int res_x[] = { 320, 640, 320, 1024, 1680, 800, 1600, 3280 };
295 LOCAL const int res_y[] = { 200, 480, 240, 768, 1050, 400, 1200, 1200 };
296 LOCAL const int res_d[] = { 8, 8 , 16, 8, 8, 16 , 32, 32 };
297 #define NUM_RES ((int)(sizeof(res_x) / sizeof(res_x[0])))
298
299 /* ======================================================================== */
300 /* CFG_PARSERES -- Parse a resolution string. Return -1 if invalid. */
301 /* ======================================================================== */
cfg_parseres(const char * const res,int * const rx,int * const ry,int * const rd)302 LOCAL const char *cfg_parseres(const char *const res,
303 int *const rx, int *const ry, int *const rd)
304 {
305 int s;
306
307 if (!rx || !ry || !rd)
308 return "cfg_parseres: internal error, invalid arguments";
309
310 if (!res)
311 {
312 *rx = res_x[0];
313 *ry = res_y[0];
314 *rd = res_d[0];
315 return NULL;
316 }
317
318 s = sscanf(res, "%d%*1c%d%*1c%d", rx, ry, rd);
319
320 if (s < 1 || s > 3)
321 return "Bad resolution string.";
322
323
324 if (s == 1)
325 {
326 if (*rx >= 0 && *rx < NUM_RES)
327 {
328 int i = *rx;
329 *rx = res_x[i];
330 *ry = res_y[i];
331 *rd = res_d[i];
332 return NULL;
333 }
334
335 if (*rx < 0)
336 return ""; /* not really an error, but force resolution listing */
337
338 return "Resolution number out of range.";
339 }
340
341 if (s == 2)
342 *rd = 8;
343
344 if (!(*rd == 8 || *rd == 16 || *rd == 24 || *rd == 32))
345 return "Color depth must be 8, 16, 24 or 32";
346
347 if (*rx < 320)
348 return "X resolution is too small.";
349
350 if (*ry < 200)
351 return "Y resolution is too small.";
352
353 return NULL;
354 }
355
356
357 /* ======================================================================== */
358 /* CFG_LONGOPT -- Long options for getopt_long */
359 /* ======================================================================== */
360 enum
361 {
362 FLAG_CGC0 = 2000, FLAG_CGC1, FLAG_KBDHACKFILE, FLAG_GP2X_CLOCK,
363 FLAG_GFX_SWSURF, FLAG_GFX_DBLBUF, FLAG_GFX_ASYNCB, FLAG_GFX_HWPAL,
364 FLAG_GFX_DIRTYRECT, FLAG_GFX_DR_MERGE, FLAG_GFX_VERBOSE, FLAG_GFX_PALETTE,
365 FLAG_GFX_BORD_X, FLAG_GFX_BORD_Y, FLAG_GUI_MODE, FLAG_RAND_MEM,
366 FLAG_START_DELAY, FLAG_DBG_SCRIPT, FLAG_DBG_SRCMAP, FLAG_FILE_IO,
367 FLAG_ENABLE_MOUSE, FLAG_PRESCALE, FLAG_JLP_SAVEGAME, FLAG_AVI_RATE,
368 FLAG_LOCUTUS, FLAG_ECS_TAPE, FLAG_ECS_PRINTER, FLAG_CHEAT
369 };
370
371 struct option cfg_longopt[] =
372 {
373 { "ecsimg", 1, NULL, 'E' },
374 { "execimg", 1, NULL, 'e' },
375 { "gromimg", 1, NULL, 'g' },
376 { "gramsize", 1, NULL, 'G' },
377 { "ecs", 2, NULL, 's' },
378 { "fullscreen", 2, NULL, 'f' },
379 { "audiofile", 1, NULL, 'F' },
380 { "debugger", 0, NULL, 'd' },
381 { "ratecontrol", 2, NULL, 'r' },
382 { "macho", 2, NULL, 'r' },
383 { "fullscreen", 2, NULL, 'x' },
384 { "displaysize", 1, NULL, 'z' },
385 { "resolution", 1, NULL, 'z' },
386 { "audio", 1, NULL, 'a' },
387 { "audiorate", 1, NULL, 'a' },
388 { "audiowindow", 1, NULL, 'w' },
389 { "audiobufsize", 1, NULL, 'B' },
390 { "audiobufcnt", 1, NULL, 'C' },
391 { "audiomintick", 1, NULL, 'M' },
392 { "voice", 2, NULL, 'v' },
393 { "voicewindow", 2, NULL, 'W' },
394 { "voicefiles", 2, NULL, 'V' },
395 { "i2pc0", 2, NULL, 'i' },
396 { "i2pc1", 2, NULL, 'I' },
397 { "intv2pc0", 2, NULL, 'i' },
398 { "intv2pc1", 2, NULL, 'I' },
399 #ifdef CGC_DLL
400 { "cgc0", 2, NULL, FLAG_CGC0 },
401 { "cgc1", 2, NULL, FLAG_CGC1 },
402 #endif
403 #ifdef CGC_THREAD
404 { "cgc0", 1, NULL, FLAG_CGC0 },
405 { "cgc1", 1, NULL, FLAG_CGC1 },
406 #endif
407 { "icartcache", 2, NULL, 'c' },
408 { "help", 0, NULL, 'h' },
409 { "license", 0, NULL, 'l' },
410 { "nobusywait", 0, NULL, '9' },
411 { "kbdhackfile", 1, NULL, FLAG_KBDHACKFILE },
412 { "kbdmap", 1, NULL, 'm' },
413 { "demofile", 1, NULL, 'D' },
414
415 { "js0", 2, NULL, 1000 },
416 { "js1", 2, NULL, 1010 },
417 { "js2", 2, NULL, 1020 },
418 { "js3", 2, NULL, 1030 },
419
420 #define JS_FLAG(j) \
421 { "js" #j "a", 2, NULL, 1000 + (j)*10 }, \
422 { "js" #j "b", 2, NULL, 1001 + (j)*10 }, \
423 { "js" #j "c", 2, NULL, 1002 + (j)*10 }, \
424 { "js" #j "d", 2, NULL, 1003 + (j)*10 }, \
425 { "js" #j "e", 2, NULL, 1004 + (j)*10 }, \
426 { "js" #j "f", 2, NULL, 1005 + (j)*10 }, \
427 { "js" #j "g", 2, NULL, 1006 + (j)*10 }, \
428 { "js" #j "h", 2, NULL, 1007 + (j)*10 }, \
429 { "js" #j "i", 2, NULL, 1008 + (j)*10 }, \
430 { "js" #j "j", 2, NULL, 1009 + (j)*10 }
431
432 JS_FLAG(0),
433 JS_FLAG(1),
434 JS_FLAG(2),
435 JS_FLAG(3),
436 JS_FLAG(4),
437 JS_FLAG(5),
438 JS_FLAG(6),
439 JS_FLAG(7),
440 JS_FLAG(8),
441 JS_FLAG(9),
442
443 #ifdef GP2X
444 { "gp2xclock", 1, NULL, FLAG_GP2X_CLOCK },
445 #endif
446
447 { "gfx-swsurf", 2, NULL, FLAG_GFX_SWSURF },
448 { "gfx-dblbuf", 2, NULL, FLAG_GFX_DBLBUF },
449 { "gfx-asyncb", 2, NULL, FLAG_GFX_ASYNCB },
450 { "gfx-hwpal", 2, NULL, FLAG_GFX_HWPAL },
451
452 { "gfx-verbose", 0, NULL, FLAG_GFX_VERBOSE },
453
454 { "gfx-dirtyrect",2, NULL, FLAG_GFX_DIRTYRECT },
455 { "gfx-dr-clean-merge",2, NULL, FLAG_GFX_DR_MERGE },
456
457 { "gfx-palette", 1, NULL, FLAG_GFX_PALETTE },
458
459 { "gfx-border-pct", 1, NULL, 'b' },
460 { "gfx-border-x", 1, NULL, FLAG_GFX_BORD_X },
461 { "gfx-border-y", 1, NULL, FLAG_GFX_BORD_Y },
462
463 { "gui-mode", 0, NULL, FLAG_GUI_MODE },
464
465 { "rom-path", 1, NULL, 'p' },
466 { "quiet", 0, NULL, 'q' },
467 { "start-delay", 2, NULL, FLAG_START_DELAY },
468 { "sym-file", 1, NULL, 'S' },
469 { "script", 1, NULL, FLAG_DBG_SCRIPT },
470 { "src-map", 1, NULL, FLAG_DBG_SRCMAP },
471
472 { "rand-mem", 0, NULL, FLAG_RAND_MEM },
473 { "file-io", 1, NULL, FLAG_FILE_IO },
474 { "pal", 0, NULL, 'P' },
475
476 { "enable-mouse", 0, NULL, FLAG_ENABLE_MOUSE },
477 { "prescale", 1, NULL, FLAG_PRESCALE },
478
479 { "jlp", 0, NULL, 'J' },
480 { "jlp-savegame", 1, NULL, FLAG_JLP_SAVEGAME },
481 { "jlp-flash", 1, NULL, 'j' },
482
483 { "avirate", 1, NULL, FLAG_AVI_RATE },
484
485 // --locutus for testing LUIGI files.
486 { "locutus", 0, NULL, FLAG_LOCUTUS },
487
488 { "ecs-tape", 1, NULL, FLAG_ECS_TAPE },
489 { "ecs-printer", 1, NULL, FLAG_ECS_PRINTER },
490 { "cheat", 1, NULL, FLAG_CHEAT },
491
492 { NULL, 0, NULL, 0 }
493 };
494
495 LOCAL const char *optchars= "b:E:e:G:g:s::f::F:?dhlqr:P::x::z:a:w:B:C:M:m:"
496 "v::W::V::i::I::c:D:p:J:j::";
497
498 /* ======================================================================== */
499 /* Supported I/O addresses for INTV2PC. */
500 /* ======================================================================== */
501 const uint32_t i2pc_ports[4] = { 0x0, 0x378, 0x278, 0x3BC };
502
503 LOCAL char *joy_cfg[MAX_JOY][MAX_STICKS];
504
505 /* ======================================================================== */
506 /* CFG_INIT -- Parse command line and get started */
507 /* ======================================================================== */
cfg_init(cfg_t * cfg,int argc,char * argv_orig[])508 void cfg_init(cfg_t *cfg, int argc, char * argv_orig[])
509 {
510 int c, option_idx = 0, rx, ry, rd, bx = -1, by = -1, bpct = -1;
511 int exec_type = 0, legacy_rom = 0;
512 int value = 1, busywaits = 1;
513 uint32_t cache_flags = IC_CACHE_DFLT;
514 char *audiofile = NULL, *tmp;
515 char *kbdhackfile = NULL;
516 char *demofile = NULL;
517 char *jlpsg = NULL;
518 char *elfi_prefix = NULL;
519 char *gfx_palette = NULL;
520 const char *fn_ecs_tape = NULL;
521 const char *fn_ecs_printer = NULL;
522 int jlp_accel = -1;
523 int jlp_flash = -1;
524 LZFILE *f;
525 int silent = 0;
526 char *debug_symtbl = NULL;
527 char *debug_script = NULL;
528 char *debug_srcmap = NULL;
529 int snd_buf_size = 0;
530 int snd_buf_cnt = 0;
531 int gfx_verbose = 0;
532 int rand_mem = 0;
533 int enable_mouse = 0;
534 int ecs_bin_fail_ok = 0;
535 char *disp_res = NULL;
536 const char *err_msg = NULL;
537 int locutus = 0;
538 #ifndef NO_SERIALIZER
539 ser_hier_t *ser_cfg;
540 #endif
541 game_metadata_t *meta = NULL;
542 int meta_needs_free = 0;
543 int initial_event_map = 0;
544 const bool batch_mode = plat_is_batch_mode();
545
546 char **argv_copy = CALLOC(char *, argc);
547 char *argv_data;
548
549 {
550 int i, sz = 0;
551 for (i = 0; i < argc; i++)
552 sz += strlen(argv_orig[i]) + 1;
553
554 argv_data = CALLOC(char, sz);
555
556 sz = 0;
557 for (i = 0; i < argc; i++)
558 {
559 strcpy(argv_data + sz, argv_orig[i]);
560 argv_copy[i] = argv_data + sz;
561 sz += strlen(argv_orig[i]) + 1;
562 }
563 }
564
565 optind = 0;
566 optopt = 0;
567 opterr = 0;
568 optarg = NULL;
569
570 #ifdef GP2X
571 int gp2xclock = 200;
572 #endif
573
574 #ifdef WII
575 silent = 1;
576 #endif
577 /* -------------------------------------------------------------------- */
578 /* Initialize random number generator. Do this before peripherals, */
579 /* as some may use the random number generator. */
580 /* -------------------------------------------------------------------- */
581 #if !defined(__EMSCRIPTEN__)
582 srand_jz(time(0) + (uint32_t)(UINT32_MAX * fmod(get_time(), 0.999)));
583 #else
584 /* For some reason the line above triggered an overflow exception in */
585 /* Emscripten, so go with this simpler random seed init. */
586 /* TODO: Try it again now that I've added fmod. */
587 srand_jz(time(0) & 0xFFFFFFFFu);
588 #endif
589
590 /* -------------------------------------------------------------------- */
591 /* Set up the default state for everything. */
592 /* -------------------------------------------------------------------- */
593 memset((void *)cfg, 0, sizeof(cfg_t));
594
595 cfg->pal_mode = 0; /* Default NTSC */
596 cfg->gram_size = -1; /* Automatic GRAM size */
597 cfg->audio_rate = DEFAULT_AUDIO_HZ; /* see config.h */
598 cfg->psg_window = -1; /* Automatic window setting. */
599 cfg->ecs_enable = -1; /* Automatic (dflt: ECS off) */
600 cfg->ivc_enable = -1; /* Automatic (dflt: Intellivoice off. */
601 cfg->ivc_window = -1; /* Automatic window setting. */
602 cfg->gfx_flags = 0 /* Windowed, single buf, hardware surf */
603 #if 0
604 | GFX_DRECTS /* Dirty rectangle update */
605 | GFX_DRCMRG; /* Allow merging cln rect btwn 2 dirty */
606 #else
607 /* dirty rectangles disabled for now. */
608 ;
609 #endif
610 cfg->i2pc0_port = 0; /* No INTV2PC #0 */
611 cfg->i2pc1_port = 0; /* No INTV2PC #1 */
612 cfg->cgc0_num = -1; /* No CGC #0 */
613 cfg->cgc1_num = -1; /* No CGC #1 */
614 cfg->cgc0_dev = NULL; /* No CGC #0 */
615 cfg->cgc1_dev = NULL; /* No CGC #1 */
616 cfg->debugging = 0; /* No debugger. */
617 cfg->rate_ctl = !batch_mode; /* Enable rate ctl unless batch. */
618 cfg->avi_time_scale = -1.0; /* Default: unspecified. */
619 cfg->accutick = 1; /* fully accurate audio. */
620 cfg->binding = cfg_key_bind; /* default key bindings. */
621 cfg->start_dly = -1; /* No startup delay by default. */
622
623 #define STR_REPLACE(x,y) { CONDFREE(x); (x) = strdup(y); }
624
625 STR_REPLACE(cfg->fn_exec, "exec.bin"); /* Default name to look for */
626 STR_REPLACE(cfg->fn_grom, "grom.bin"); /* ... */
627 STR_REPLACE(cfg->fn_game, "game.rom"); /* ... */
628 STR_REPLACE(cfg->fn_ecs, "ecs.bin"); /* ... */
629 STR_REPLACE(fn_ecs_tape, "ecs_tape#.ecs");
630 STR_REPLACE(fn_ecs_printer, "ecs_printer#.ecs");
631
632 cheat_init(&cfg->cheat, &cfg->cp1600);
633
634 /* -------------------------------------------------------------------- */
635 /* Figure out out our executable's path. If none, assume ".". */
636 /* -------------------------------------------------------------------- */
637 if (!exe_path)
638 {
639 exe_path = get_exe_dir(argv_copy[0]);
640 if (!exe_path)
641 exe_path = strdup(".");
642 }
643
644 #ifndef NO_SERIALIZER
645 /* -------------------------------------------------------------------- */
646 /* Register our config variables for serialization. */
647 /* -------------------------------------------------------------------- */
648 #define SER_REG(x,t,l,f)\
649 ser_register(ser_cfg, #x, &cfg-> x, t, l, f)
650
651 ser_cfg = ser_new_hierarchy(NULL, "cfg");
652 SER_REG(ecs_enable, ser_s32, 1, SER_INIT|SER_MAND);
653 SER_REG(ivc_enable, ser_s32, 1, SER_INIT|SER_MAND);
654 SER_REG(ivc_tname, ser_string, 1, SER_INIT|SER_MAND);
655 #endif
656
657 /* -------------------------------------------------------------------- */
658 /* Parse the commandline flags. */
659 /* -------------------------------------------------------------------- */
660 while ((c = getopt_long(argc, argv_copy, optchars, cfg_longopt,
661 &option_idx)) != EOF)
662 {
663 int noarg = 1;
664 double dvalue;
665
666 value = 1;
667 dvalue = 1.0;
668 if (optarg)
669 {
670 noarg = 0;
671 value = atoi(optarg);
672 sscanf(optarg, "%lf", &dvalue);
673 }
674
675 if (c >= 1000 && c <= 1099) /* joystick flags */
676 {
677 int joy_num = (c - 1000) / 10, stick = (c - 1000) % 10;
678 STR_REPLACE(joy_cfg[joy_num][stick], (optarg ? optarg : ""));
679 } else switch (c)
680 {
681 case '?': case 'h': usage(); break;
682 case 'l': license(); break;
683 case 'q': silent = 1; break;
684 case 'B': snd_buf_size = value; break;
685 case 'C': snd_buf_cnt = value; break;
686 case 'M': cfg->accutick = value; break;
687 case 'E': STR_REPLACE(cfg->fn_ecs , optarg); break;
688 case 'e': STR_REPLACE(cfg->fn_exec , optarg); break;
689 case 'g': STR_REPLACE(cfg->fn_grom , optarg); break;
690 case 'G': cfg->gram_size = value; break;
691 case 'F': STR_REPLACE(audiofile , optarg); break;
692 case 's': cfg->ecs_enable = value; break;
693 case 'z': STR_REPLACE(disp_res , optarg); break;
694 case 'd': cfg->debugging = 1; break;
695 case 'r': cfg->rate_ctl = dvalue; break;
696 case 'a': cfg->audio_rate = value; break;
697 case 'w': cfg->psg_window = value; break;
698 case 'v': cfg->ivc_enable = value; break;
699 case 'W': cfg->ivc_window = value; break;
700 case 'V': STR_REPLACE(cfg->ivc_tname , optarg); break;
701 case 'i': cfg->i2pc0_port = value; break;
702 case 'I': cfg->i2pc1_port = value; break;
703 case 'S': STR_REPLACE(debug_symtbl , optarg); break;
704
705 case FLAG_AVI_RATE:
706 cfg->avi_time_scale = dvalue;
707 break;
708
709 case FLAG_DBG_SCRIPT:
710 STR_REPLACE(debug_script, optarg);
711 break;
712
713 case FLAG_DBG_SRCMAP:
714 STR_REPLACE(debug_srcmap, optarg);
715 break;
716
717 case FLAG_CGC0:
718 cfg->cgc0_num = noarg ? 0 : value;
719 STR_REPLACE(cfg->cgc0_dev , optarg);
720 break;
721
722 case FLAG_CGC1:
723 cfg->cgc1_num = noarg ? 0 : value;
724 STR_REPLACE(cfg->cgc1_dev , optarg);
725 break;
726
727 case FLAG_KBDHACKFILE:
728 STR_REPLACE(kbdhackfile , optarg);
729 break;
730
731 case FLAG_GP2X_CLOCK:
732 #ifdef GP2X
733 gp2xclock = value;
734 #endif
735 break;
736
737 #define CHG_BIT(var, bit, to) (var) = ((var) & ~(bit)) | ((to) ? (bit) : 0)
738
739 case 'f': case 'x':
740 CHG_BIT(cfg->gfx_flags, GFX_FULLSC, value);
741 break;
742
743 case FLAG_GFX_SWSURF:
744 CHG_BIT(cfg->gfx_flags, GFX_SWSURF, value);
745 break;
746
747 case FLAG_GFX_DBLBUF:
748 CHG_BIT(cfg->gfx_flags, GFX_DBLBUF, value);
749 if (value != 0)
750 CHG_BIT(cfg->gfx_flags, GFX_DRECTS, 0);
751 break;
752
753 case FLAG_GFX_ASYNCB:
754 CHG_BIT(cfg->gfx_flags, GFX_ASYNCB, value);
755 break;
756
757 case FLAG_GFX_HWPAL:
758 CHG_BIT(cfg->gfx_flags, GFX_HWPAL, value);
759 break;
760
761 case FLAG_GFX_DIRTYRECT:
762 CHG_BIT(cfg->gfx_flags, GFX_DRECTS, value);
763 if (value != 0)
764 CHG_BIT(cfg->gfx_flags, GFX_DBLBUF, 0);
765 break;
766
767 case FLAG_GFX_DR_MERGE:
768 CHG_BIT(cfg->gfx_flags, GFX_DRCMRG, value);
769 break;
770
771 case FLAG_GFX_VERBOSE:
772 gfx_verbose = 1;
773 break;
774
775 case FLAG_GFX_PALETTE:
776 STR_REPLACE(gfx_palette, optarg);
777 break;
778
779 case 'b':
780 bpct = value;
781 break;
782
783 case FLAG_GFX_BORD_X:
784 bx = value;
785 break;
786
787 case FLAG_GFX_BORD_Y:
788 by = value;
789 break;
790
791 case FLAG_GUI_MODE:
792 cfg->gui_mode = 1;
793 break;
794
795 case FLAG_RAND_MEM:
796 rand_mem = 1;
797 break;
798
799 case 'P':
800 cfg->pal_mode = 1;
801 break;
802
803 case FLAG_FILE_IO:
804 STR_REPLACE(elfi_prefix, optarg);
805 break;
806
807 case 'D':
808 STR_REPLACE(demofile, optarg);
809 break;
810
811 case '9':
812 busywaits = 0;
813 break;
814
815 case FLAG_ENABLE_MOUSE:
816 enable_mouse = 1;
817 break;
818
819 case FLAG_PRESCALE:
820 cfg->prescale = value;
821 break;
822
823 case FLAG_JLP_SAVEGAME:
824 STR_REPLACE(jlpsg, optarg);
825 jlp_accel = 3;
826 break;
827
828 case 'J':
829 jlp_accel = !noarg ? value : 3;
830 break;
831
832 case 'j':
833 jlp_flash = value;
834 break;
835
836 case FLAG_LOCUTUS:
837 locutus = 1;
838 break;
839
840 case FLAG_ECS_TAPE:
841 STR_REPLACE(fn_ecs_tape, optarg);
842 break;
843
844 case FLAG_ECS_PRINTER:
845 STR_REPLACE(fn_ecs_printer, optarg);
846 break;
847
848 case 'c':
849 {
850 const char *name = "Default";
851 switch (value)
852 {
853 default:
854 case 0: cache_flags = IC_CACHE_CABS;
855 name = "Cache bankswitched"; break;
856 case 1: cache_flags = IC_CACHE_NOBS;
857 name = "Don't cache bankswitched"; break;
858 case 2: cache_flags = IC_CACHE_SAFE;
859 name = "Cache read-only, no banksw"; break;
860 case 3: cache_flags = IC_CACHE_NONE;
861 name = "Cache nothing"; break;
862 }
863
864 UNUSED(name);
865 break;
866 }
867
868 case 'p':
869 {
870 rom_path = parse_path_string(rom_path, optarg);
871 break;
872 }
873
874 case FLAG_START_DELAY:
875 {
876 float ftmp = -1.f;
877
878 sscanf(optarg, "%f", &ftmp);
879
880 cfg->start_dly = 1000.f * ftmp;
881 break;
882 }
883
884 case 'm':
885 {
886 if (value >= 0 && value < 4)
887 initial_event_map = value;
888 break;
889 }
890
891 case FLAG_CHEAT:
892 {
893 if (cheat_add(&cfg->cheat, optarg))
894 {
895 fprintf(stderr, "Unable to parse cheat arg.\n");
896 exit(1);
897 }
898 break;
899 }
900
901 default:
902 {
903 fprintf(stderr, "Unrecognized option: '%s'\n"
904 "Try jzintv --help for usage information.\n",
905 argv_copy[optind - 1]);
906 exit(1);
907 }
908 }
909 }
910
911 if (optind < argc)
912 STR_REPLACE(cfg->fn_game, argv_copy[optind]);
913
914 CONDFREE(argv_data);
915 CONDFREE(argv_copy);
916
917 rom_path = parse_path_string(rom_path, getenv("JZINTV_ROM_PATH"));
918
919 if (DEFAULT_ROM_PATH)
920 rom_path = parse_path_string(rom_path, DEFAULT_ROM_PATH);
921
922 /* -------------------------------------------------------------------- */
923 /* Set up jzp_printf. */
924 /* -------------------------------------------------------------------- */
925 if (cfg->gui_mode)
926 {
927 cfg->debugging = 0;
928 jzp_init(1, 0, NULL, NULL);
929 setvbuf(stdin, NULL, _IONBF, 0);
930 #ifndef NO_FCNTL
931 fcntl(STDIN_FILENO, F_SETFL, O_NDELAY);
932 #endif
933 } else
934 jzp_init(silent, stdout, NULL, NULL);
935
936 #ifdef WII
937 /* -------------------------------------------------------------------- */
938 /* On WII, just make sure we're full-screen. */
939 /* -------------------------------------------------------------------- */
940 cfg->gfx_flags |= GFX_FULLSC;
941 #endif
942
943 #ifdef GP2X
944 /* -------------------------------------------------------------------- */
945 /* On GP2X, simply force a few arguments to the only supported vals. */
946 /* Also, adjust the clock if the user requests it. */
947 /* -------------------------------------------------------------------- */
948 cfg->gfx_flags |= GFX_FULLSC;
949 cfg->gfx_flags &= ~GFX_DBLBUF;
950 STR_REPLACE(disp_res, "2");
951
952 if (gp2xclock > 0)
953 {
954 extern int gp2x_speed(int);
955
956 if (gp2x_speed(gp2xclock))
957 {
958 jzp_printf("Clock rate %d unsupported.\n", gp2xclock);
959 exit(1);
960 }
961 }
962 #endif
963
964 /* -------------------------------------------------------------------- */
965 /* If the user specified a palette file, read it in. */
966 /* -------------------------------------------------------------------- */
967 if (gfx_palette)
968 {
969
970 /* The internal names take precedence over external filenames. */
971 if (palette_get_by_name(gfx_palette, &cfg->palette) == 0)
972 {
973 /* continue */
974 } else
975 {
976 LZFILE *palette_file = path_fopen(rom_path, gfx_palette, "r");
977 if (!palette_file)
978 {
979 jzp_printf("Unable to locate palette '%s'\n", gfx_palette);
980 exit(1);
981 } else if (palette_load_file(palette_file, &cfg->palette))
982 {
983 jzp_printf("Unable to parse palette '%s'\n", gfx_palette);
984 exit(1);
985 }
986 lzoe_fclose(palette_file);
987 }
988 } else
989 {
990 int idx = cfg->pal_mode ? PALETTE_DEFAULT_PAL : PALETTE_DEFAULT_NTSC;
991 if (palette_get_by_idx(idx, &cfg->palette))
992 {
993 jzp_printf("Internal error configuring palette\n");
994 exit(1);
995 }
996 }
997
998 /* -------------------------------------------------------------------- */
999 /* Sanity-check some of the flags. Most get checked by peripherals. */
1000 /* -------------------------------------------------------------------- */
1001 if ( (err_msg = cfg_parseres( disp_res, &rx, &ry, &rd )) != NULL )
1002 {
1003 int i;
1004 fprintf(stderr,
1005 "%s\n"
1006 "Resolution string must be of the following forms:\n"
1007 "\n"
1008 " N where N is one of the built in resolutions\n"
1009 " WxH where W is display width and H is display height\n"
1010 " WxH,D where W is display width, H is display height, and D is color depth\n"
1011 "\n"
1012 "Width must be at least 320, and height must be at least 200. Color depth\n"
1013 "defaults to 8bpp. jzIntv supports 8bpp, 16bpp, 24bpp and 32bpp\n"
1014 "\n"
1015 "Valid built-in resolutions:\n\n",
1016 err_msg
1017 );
1018
1019 for (i = 0; i < NUM_RES; i++)
1020 {
1021 fprintf(stderr, " -z%d: %dx%dx%d\n",
1022 i, res_x[i], res_y[i], res_d[i]);
1023 }
1024 exit(1);
1025 }
1026 CONDFREE(disp_res);
1027
1028 /* Establish border based on explicit values or "percentage" */
1029 if (bx < 0) bx = bpct >= 0 ? (bpct * rx + 1) / 100 : 0;
1030 if (by < 0) by = bpct >= 0 ? (bpct * ry + 1) / 100 : 0;
1031
1032 bx = (bx + 7) & ~7; /* Round horizontal border to multiple of 8 */
1033
1034 if ( gfx_check(rx, ry, rd, cfg->prescale) != 0 )
1035 {
1036 exit(1);
1037 }
1038
1039 /* -------------------------------------------------------------------- */
1040 /* Delay starting emulation if full-screen is specified and no other */
1041 /* start delay is specified. */
1042 /* -------------------------------------------------------------------- */
1043 #if FULLSC_START_DLY > 0
1044 if (cfg->start_dly < 0 && (cfg->gfx_flags & GFX_FULLSC) != 0)
1045 cfg->start_dly = FULLSC_START_DLY;
1046 #endif
1047
1048
1049 /* -------------------------------------------------------------------- */
1050 /* He's a macho, macho duck. He's a macho, macho duck! */
1051 /* -------------------------------------------------------------------- */
1052 if (cfg->rate_ctl <= 0.01)
1053 {
1054 cfg->rate_ctl = 0;
1055 cfg->gfx_flags |= GFX_SKIP_EXTRA;
1056 }
1057 if (cfg->rate_ctl > 1.5)
1058 cfg->gfx_flags |= GFX_SKIP_EXTRA;
1059
1060 /* -------------------------------------------------------------------- */
1061 /* Default AVI rate to the same as rate_ctl unless explicitly given. */
1062 /* In batch mode, consider rate_ctl == 0 to mean "1.0." */
1063 /* -------------------------------------------------------------------- */
1064 {
1065 if (cfg->avi_time_scale <= 0.01)
1066 cfg->avi_time_scale = cfg->rate_ctl > 0.0 ? cfg->rate_ctl
1067 : batch_mode ? 1.0
1068 : 10000.0;
1069
1070 double audio_time_scale = cfg->rate_ctl >= 0.0 ? cfg->rate_ctl : 1.0;
1071
1072 if (batch_mode && cfg->rate_ctl == 0.0)
1073 audio_time_scale = 1.0;
1074
1075 avi_set_time_scale(cfg->avi_time_scale, audio_time_scale);
1076 }
1077
1078 #ifdef DIRECT_INTV2PC
1079 /* -------------------------------------------------------------------- */
1080 /* Look up INTV2PC port numbers, if any. */
1081 /* -------------------------------------------------------------------- */
1082 if (cfg->i2pc0_port > 3 || cfg->i2pc1_port > 3)
1083 {
1084 fprintf(stderr, "ERROR: "
1085 "INTV2PC port number out of range. Valid values are 1..3 for\n"
1086 "typical ports for LPT1: through LPT3:, and 0 to disable.\n"
1087 "\n"
1088 "The following port numbers are selected by 1 through 3:\n"
1089 " 1 selects 0x%.3X\n"
1090 " 2 selects 0x%.3X\n"
1091 " 3 selects 0x%.3X\n"
1092 "\n", i2pc_ports[1], i2pc_ports[2], i2pc_ports[3]);
1093 exit(1);
1094 }
1095 if (cfg->i2pc0_port && cfg->i2pc0_port == cfg->i2pc1_port)
1096 {
1097 fprintf(stderr, "ERROR: Cannot enable two INTV2PCs on same port #\n");
1098 exit(1);
1099 }
1100 cfg->i2pc0_port = i2pc_ports[cfg->i2pc0_port];
1101 cfg->i2pc1_port = i2pc_ports[cfg->i2pc1_port];
1102 #endif
1103
1104 /* -------------------------------------------------------------------- */
1105 /* Create a new peripheral bus for the Intellivision main console. */
1106 /* -------------------------------------------------------------------- */
1107 cfg->intv = periph_new(16, 16, 4);
1108 strncpy(cfg->intv->periph.name, "MasterComponent", 16);
1109
1110 /* -------------------------------------------------------------------- */
1111 /* Now, configure the Intellivision according to our flags. Start */
1112 /* off by reading in the EXEC, GROM, and GAME images. */
1113 /* -------------------------------------------------------------------- */
1114 f = path_fopen(rom_path, cfg->fn_exec, "rb");
1115
1116 exec_type = 0;
1117 if (!f || file_read_rom16(f, 4096, cfg->exec_img) != 4096)
1118 {
1119 if (errno) perror("file_read_rom16");
1120 fprintf(stderr, "ERROR: Could not read EXEC image '%s'\n",
1121 cfg->fn_exec);
1122 dump_search_path(rom_path);
1123 exit(1);
1124 }
1125 lzoe_fseek(f, 0, SEEK_END);
1126 if (lzoe_ftell(f) == 2 * (4096 + 256))
1127 {
1128 exec_type = 1;
1129 lzoe_fseek(f, 8192, SEEK_SET);
1130 if (file_read_rom16(f, 256, cfg->exec_img + 4096) != 256)
1131 {
1132 if (errno) perror("file_read_rom16");
1133 fprintf(stderr, "ERROR: Could not read EXEC2 image '%s'\n",
1134 cfg->fn_exec);
1135 exit(1);
1136 }
1137 } else if (lzoe_ftell(f) == 2 * 8192)
1138 {
1139 exec_type = 2; /* INTV88 / TutorVision */
1140 lzoe_fseek(f, 8192, SEEK_SET);
1141 if (file_read_rom16(f, 4096, cfg->exec_img + 4096) != 4096)
1142 {
1143 if (errno) perror("file_read_rom16");
1144 fprintf(stderr, "ERROR: Could not read WBEXEC image '%s'\n",
1145 cfg->fn_exec);
1146 exit(1);
1147 }
1148 }
1149
1150 lzoe_fclose(f);
1151
1152 f = path_fopen(rom_path, cfg->fn_grom, "rb");
1153 if (!f || file_read_rom8 (f, 2048, cfg->grom_img) != 2048)
1154 {
1155 if (errno) perror("file_read_rom8");
1156 fprintf(stderr, "ERROR: Could not read GROM image '%s'\n",
1157 cfg->fn_grom);
1158 dump_search_path(rom_path);
1159 exit(1);
1160 }
1161 lzoe_fclose(f);
1162
1163 /* -------------------------------------------------------------------- */
1164 /* Once we know the EXEC type, adjust the GRAM size if necessary */
1165 /* -------------------------------------------------------------------- */
1166 if (cfg->gram_size < 0)
1167 cfg->gram_size = exec_type == 2 ? 2 : 0;
1168
1169 /* -------------------------------------------------------------------- */
1170 /* XXX: Hack: If locutus == 1, then this is a LUIGI file. Short */
1171 /* circuit everything and just read fn_game as a LUIGI file. */
1172 /* -------------------------------------------------------------------- */
1173 if (locutus)
1174 {
1175 int locutus_ecs, locutus_voice;
1176 if ( make_locutus( &(cfg->locutus), cfg->fn_game, &cfg->cp1600, 0,
1177 jlpsg ) )
1178 {
1179 fprintf(stderr, "ERROR: make_locutus failed\n");
1180 exit(1);
1181 }
1182
1183 // JLP emulation for Locutus is handled entirely inside Locutus, and
1184 // must be specified within the LUIGI flags. The only thing the user
1185 // can provide is the name of the savegame file.
1186 jlp_accel = 0;
1187 jlp_flash = 0;
1188
1189 // If the user didn't specify ECS and/or Intellivoice flags, pick them
1190 // up from the LUIGI file. Only enable ECS/Intellivoice if the game
1191 // is at least "enhanced" by the peripheral.
1192 locutus_ecs = get_locutus_compat_ecs ( &(cfg->locutus) );
1193 locutus_voice = get_locutus_compat_voice( &(cfg->locutus) );
1194
1195 if (cfg->ecs_enable == -1 && locutus_ecs >= CMP_ENHANCED)
1196 cfg->ecs_enable = 1;
1197 else if (cfg->ecs_enable == 0 && locutus_ecs == CMP_REQUIRES)
1198 jzp_printf("\nWARNING: ECS explicitly disabled; "
1199 "however the game says the ECS is required.\n\n");
1200
1201 if (cfg->ivc_enable == -1 && locutus_voice >= CMP_ENHANCED)
1202 cfg->ivc_enable = 1;
1203 else if (cfg->ivc_enable == 0 && locutus_voice == CMP_REQUIRES)
1204 jzp_printf("\nWARNING: Intellivoice explicitly disabled; "
1205 "however the game says the \n"
1206 " Intellivoice is required.\n\n");
1207
1208 meta = get_locutus_metadata(&(cfg->locutus));
1209 meta_needs_free = 1;
1210
1211 goto locutus_loaded;
1212 }
1213
1214 /* -------------------------------------------------------------------- */
1215 /* First try to load it as a legacy ROM. If the legacy code decides */
1216 /* it's not actually a BIN+CFG, it'll hand us back a .ROM filename. */
1217 /* -------------------------------------------------------------------- */
1218 tmp = legacy_bincfg(&(cfg->legacy), rom_path, cfg->fn_game, &legacy_rom,
1219 &(cfg->cp1600), jlp_accel, jlp_flash, rand_mem);
1220
1221 if (legacy_rom && cfg->legacy.bc->metadata)
1222 meta = cfg->legacy.bc->metadata;
1223
1224 if (legacy_rom && cfg->legacy.bc->diags)
1225 {
1226 jzp_printf("\n");
1227 bc_print_diag(jzp_printer(),
1228 cfg->legacy.bc->cfgfile,
1229 cfg->legacy.bc->diags, 0);
1230 jzp_printf("\n");
1231 }
1232
1233 if (tmp == NULL)
1234 {
1235 fprintf(stderr, "ERROR: Failed to initialize game\n");
1236 exit(1);
1237 }
1238 CONDFREE(cfg->fn_game);
1239 cfg->fn_game = tmp;
1240
1241 /* -------------------------------------------------------------------- */
1242 /* If it wasn't a legacy ROM, it must be an Intellicart ROM. */
1243 /* -------------------------------------------------------------------- */
1244 if (!legacy_rom)
1245 {
1246 /* not path_fopen, because legacy_bincfg should do that for us. */
1247 if (!(f = lzoe_fopen(cfg->fn_game, "rb")))
1248 {
1249 perror("fopen()");
1250 fprintf(stderr, "ERROR: Failed to open Intellicart ROM:\n %s\n",
1251 cfg->fn_game);
1252 exit(1);
1253 }
1254
1255 /* ---------------------------------------------------------------- */
1256 /* Process the Intellicart ROM itself. */
1257 /* ---------------------------------------------------------------- */
1258 if (icart_init(&cfg->icart, f, rand_mem))
1259 {
1260 fprintf(stderr, "ERROR: Failed to register Intellicart\n");
1261 exit(1);
1262 }
1263
1264 /* ---------------------------------------------------------------- */
1265 /* Grab a look-see on any metadata that was in there. */
1266 /* ---------------------------------------------------------------- */
1267 if (cfg->icart.rom.metadata)
1268 meta = cfg->icart.rom.metadata;
1269
1270 lzoe_fclose(f);
1271 }
1272
1273 /* -------------------------------------------------------------------- */
1274 /* Now that we've established the ROM path exactly, go see if we */
1275 /* know anything about it, such as its name, what year it was made, */
1276 /* and if it prefers to have voice / ECS turned on. If the user */
1277 /* didn't specify voice on/off or ECS on/off, we'll use this info. */
1278 /* -------------------------------------------------------------------- */
1279 {
1280 uint32_t crc32;
1281 int tentative_metadata = 0;
1282 crc32 = file_crc32(cfg->fn_game);
1283
1284 if (!meta)
1285 {
1286 meta = default_game_metadata();
1287 if (meta)
1288 {
1289 game_metadata_set_compat_to_unspec(meta);
1290 tentative_metadata = 1;
1291 meta_needs_free = 1;
1292 }
1293 }
1294
1295 if (!find_cart_metadata(crc32, meta) && tentative_metadata)
1296 {
1297 free_game_metadata( meta );
1298 meta = NULL;
1299 tentative_metadata = 0;
1300 meta_needs_free = 0;
1301 }
1302 }
1303
1304 locutus_loaded:
1305 /* -------------------------------------------------------------------- */
1306 /* Apply the game metadata to our defaults. */
1307 /* -------------------------------------------------------------------- */
1308 if (meta)
1309 {
1310 game_metadata_set_unspec_compat_to_defaults(meta);
1311
1312 if (cfg->ecs_enable == -1 && meta->ecs_compat >= CMP_ENHANCED)
1313 {
1314 cfg->ecs_enable = 1;
1315 /* Fall back to "no ECS" if game is merely "enhanced" by ECS. */
1316 ecs_bin_fail_ok = meta->ecs_compat <= CMP_ENHANCED;
1317 } else if (cfg->ecs_enable == 0 && meta->ecs_compat == CMP_REQUIRES)
1318 jzp_printf("\nWARNING: ECS explicitly disabled; "
1319 "however the game says the ECS is required.\n\n");
1320
1321 if (cfg->ivc_enable == -1 && meta->voice_compat >= CMP_ENHANCED)
1322 cfg->ivc_enable = 1;
1323 else if (cfg->ivc_enable == 0 && meta->voice_compat == CMP_REQUIRES)
1324 jzp_printf("\nWARNING: Intellivoice explicitly disabled; "
1325 "however the game says the \n"
1326 " Intellivoice is required.\n\n");
1327
1328 if (jlp_accel == -1) jlp_accel = meta->jlp_accel;
1329 if (jlp_flash == -1) jlp_flash = meta->jlp_flash;
1330
1331 print_metadata(meta);
1332
1333 if (meta->name)
1334 cfg->cart_name = strdup(meta->name);
1335
1336 /* If a build date is set, use its year as a default. */
1337 if (meta->build_dates && meta->build_dates[0].year)
1338 cfg->cart_year = meta->build_dates[0].year;
1339
1340 /* If a release date is set, use its year, and let it override the */
1341 /* build date's year. */
1342 if (meta->release_dates && meta->release_dates[0].year)
1343 cfg->cart_year = meta->release_dates[0].year;
1344
1345 /* Free this metadata if we own it. */
1346 if (meta_needs_free)
1347 free_game_metadata( meta );
1348 meta = NULL;
1349 }
1350
1351 /* -------------------------------------------------------------------- */
1352 /* Try to load the ECS ROM image early, in case we need to fall back */
1353 /* to ECS-disabled. That way, subsequent code that tests ecs_enable */
1354 /* sees the correct state. */
1355 /* -------------------------------------------------------------------- */
1356 if (cfg->ecs_enable > 0)
1357 {
1358 f = path_fopen(rom_path, cfg->fn_ecs, "rb");
1359 if (!f || file_read_rom16(f, 12*1024, cfg->ecs_img) != 12*1024)
1360 {
1361 if (errno) perror("\nECS ROM");
1362 if (ecs_bin_fail_ok)
1363 {
1364 cfg->ecs_enable = 0;
1365 jzp_printf(
1366 "\n"
1367 /* 0123456789012345678901234567890123456789 */
1368 "NOTE: Game is 'enhanced by' the ECS, and"
1369 " jzIntv tried to automatically enable\n"
1370 /* 0123456789012345678901234567890123456789 */
1371 " ECS support. However, jzIntv was "
1372 "unable to load the ECS ROM.\n\n"
1373 /* 0123456789012345678901234567890123456789 */
1374 " Disabling ECS support.\n\n");
1375 goto skip_ecs;
1376 }
1377 fprintf(stderr, "ERROR: Could not read ECS ROM image '%s'\n",
1378 cfg->fn_ecs);
1379 dump_search_path(rom_path);
1380 exit(1);
1381 }
1382 lzoe_fclose(f);
1383 }
1384 skip_ecs:;
1385
1386 #ifdef WII
1387 /* -------------------------------------------------------------------- */
1388 /* On the Wii, default to the ECS keyboard bindings if ECS is enabled */
1389 /* since controller input will come from actual Wii controllers. */
1390 /* -------------------------------------------------------------------- */
1391 if (cfg->ecs_enable > 0)
1392 initial_event_map = 2;
1393 #endif
1394
1395 /* -------------------------------------------------------------------- */
1396 /* Initialize the peripherals. */
1397 /* -------------------------------------------------------------------- */
1398 jzp_printf("jzintv: Initializing Master Component and peripherals...\n");
1399
1400 #ifdef DIRECT_INTV2PC
1401 if (cfg->i2pc0_port > 0 &&
1402 pad_intv2pc_init(&cfg->i2pc0, 0x1F0, cfg->i2pc0_port))
1403 {
1404 fprintf(stderr, "ERROR: Failed to initialize INTV2PC #0 at 0x%.3X\n",
1405 cfg->i2pc0_port);
1406 exit(1);
1407 }
1408 if (cfg->ecs_enable > 0 &&
1409 cfg->i2pc1_port &&
1410 pad_intv2pc_init(&cfg->i2pc1, 0x0F0, cfg->i2pc1_port))
1411 {
1412 fprintf(stderr, "ERROR: Failed to initialize INTV2PC #1 at 0x%.3X\n",
1413 cfg->i2pc1_port);
1414 exit(1);
1415 }
1416 #endif
1417
1418 if (cfg->cgc0_num >= 0 &&
1419 pad_cgc_init(&cfg->cgc0, 0x1F0, cfg->cgc0_num, cfg->cgc0_dev))
1420 {
1421 fprintf(stderr, "ERROR: Failed to initialize CGC #%d as pad pair 0\n",
1422 cfg->cgc0_num);
1423 exit(1);
1424 }
1425
1426 if (cfg->ecs_enable > 0 &&
1427 cfg->cgc1_num >= 0 &&
1428 pad_cgc_init(&cfg->cgc1, 0x0F0, cfg->cgc1_num, cfg->cgc0_dev))
1429 {
1430 fprintf(stderr, "ERROR: Failed to initialize CGC #%d as pad pair 1\n",
1431 cfg->cgc1_num);
1432 exit(1);
1433 }
1434
1435 if (emu_link_init())
1436 {
1437 fprintf(stderr, "ERROR: Failed to initialize EMU_LINK\n");
1438 exit(1);
1439 }
1440
1441 /* -------------------------------------------------------------------- */
1442 /* Enable the Emu-Link File I/O if requested. */
1443 /* -------------------------------------------------------------------- */
1444 if (elfi_prefix)
1445 if (elfi_init(elfi_prefix))
1446 {
1447 fprintf(stderr, "ERROR: Failed to initialize Emu-Link File I/O\n");
1448 exit(1);
1449 }
1450
1451 if (demofile &&
1452 demo_init(&cfg->demo, demofile, &cfg->psg0,
1453 cfg->ecs_enable > 0 ? &cfg->psg1 : 0))
1454 {
1455 fprintf(stderr, "ERROR: Failed to initialize demo recorder\n");
1456 exit(1);
1457 }
1458
1459 if (jlp_accel > 0 &&
1460 jlp_init(&cfg->jlp, jlpsg, &(cfg->cp1600.xr[0]), jlp_accel,
1461 jlp_flash, rand_mem))
1462 {
1463 fprintf(stderr, "ERROR: Failed to initialize JLP.\n"
1464 "jlp_accel=%d jlp_flash=%d savegame='%s'\n",
1465 jlp_accel, jlp_flash, jlpsg ? jlpsg : "(none)");
1466 exit(1);
1467 }
1468
1469 if (gfx_init(&cfg->gfx, rx, ry, rd, cfg->gfx_flags, gfx_verbose,
1470 cfg->prescale, bx, by, cfg->pal_mode, &cfg->avi,
1471 cfg->audio_rate, &cfg->palette))
1472 {
1473 fprintf(stderr, "ERROR: Failed to initialize graphics\n");
1474 exit(1);
1475 }
1476
1477 if (cfg->audio_rate && snd_init(&cfg->snd, cfg->audio_rate, audiofile,
1478 snd_buf_size, snd_buf_cnt, &cfg->avi,
1479 cfg->pal_mode,
1480 cfg->rate_ctl))
1481 {
1482 fprintf(stderr, "WARNING: Failed to initialize sound. Disabled.\n");
1483 cfg->audio_rate = 0;
1484 }
1485
1486 if (cp1600_init(&cfg->cp1600, 0x1000, 0x1004, rand_mem))
1487 {
1488 fprintf(stderr, "ERROR: Failed to initialize CP-1610 CPU\n");
1489 exit(1);
1490 }
1491
1492 if (mem_make_ram (&cfg->scr_ram, 8, 0x0100, 8, rand_mem) ||
1493 mem_make_ram (&cfg->sys_ram, 16, 0x0200, 9, rand_mem) /* ||
1494 mem_make_glitch_ram(&cfg->glt_ram, 0xD000, 12) ||
1495 mem_make_ram (&cfg->gram, 8, 0x3800, 9)*/)
1496 {
1497 fprintf(stderr, "ERROR: Failed to initialize RAMs\n");
1498 exit(1);
1499 }
1500 if (exec_type == 1 &&
1501 mem_make_9600a(&cfg->sys_ram2, 0x0300, 8))
1502 {
1503 fprintf(stderr, "ERROR: Failed to initialize RAMs\n");
1504 exit(1);
1505 }
1506 if (exec_type == 2 &&
1507 mem_make_ram(&cfg->sys_ram2, 16, 0x0400, 8, rand_mem))
1508 {
1509 fprintf(stderr, "ERROR: Failed to initialize RAMs\n");
1510 exit(1);
1511 }
1512
1513 if (stic_init(&cfg->stic, cfg->grom_img, &cfg->cp1600.req_q, &cfg->gfx,
1514 demofile ? &cfg->demo : NULL, rand_mem, cfg->pal_mode,
1515 cfg->gram_size, exec_type == 2 ? STIC_STIC1A : STIC_8900))
1516 {
1517 fprintf(stderr, "ERROR: Failed to initialize STIC\n");
1518 exit(1);
1519 }
1520
1521 if (cfg->ecs_enable > 0 &&
1522 ecs_init(&cfg->ecs, cfg->ecs_img, &cfg->cp1600, rand_mem,
1523 fn_ecs_tape, fn_ecs_printer))
1524 {
1525 fprintf(stderr, "ERROR: Failed to initialize ECS\n");
1526 exit(1);
1527 }
1528 CONDFREE(fn_ecs_tape);
1529 CONDFREE(fn_ecs_printer);
1530
1531 if (ay8910_init(&cfg->psg0, 0x1F0, &cfg->snd,
1532 cfg->audio_rate, cfg->psg_window, cfg->accutick,
1533 cfg->rate_ctl > 0.0 ? cfg->rate_ctl : 1.0, cfg->pal_mode,
1534 &cfg->cp1600.periph.now))
1535 {
1536 fprintf(stderr, "ERROR: Failed to initialize PSG#1 (AY8914)\n");
1537 exit(1);
1538 }
1539
1540 if (cfg->ecs_enable > 0 &&
1541 ay8910_init(&cfg->psg1, 0x0F0, &cfg->snd,
1542 cfg->audio_rate, cfg->psg_window, cfg->accutick,
1543 cfg->rate_ctl > 0.0 ? cfg->rate_ctl : 1.0, cfg->pal_mode,
1544 &cfg->cp1600.periph.now))
1545 {
1546 fprintf(stderr, "ERROR: Failed to initialize PSG#2 (AY8914)\n");
1547 exit(1);
1548 }
1549
1550 if (pad_init(&cfg->pad0, 0x1F0, PAD_INPUT_ONLY))
1551 {
1552 fprintf(stderr, "ERROR: Failed to initialize game pads\n");
1553 exit(1);
1554 }
1555
1556 if (cfg->ecs_enable > 0 &&
1557 pad_init(&cfg->pad1, 0x0F0, PAD_BIDIR))
1558 {
1559 fprintf(stderr, "ERROR: Failed to ECS input device\n");
1560 exit(1);
1561 }
1562
1563 if (cfg->rate_ctl > 0.0 &&
1564 speed_init(&cfg->speed, &cfg->gfx, &cfg->stic,
1565 busywaits, cfg->rate_ctl, cfg->pal_mode))
1566 {
1567 fprintf(stderr, "ERROR: Failed to initialize rate control.\n");
1568 exit(1);
1569 }
1570
1571 if (cfg->debugging &&
1572 debug_init(&cfg->debug, &cfg->cp1600,
1573 cfg->rate_ctl > 0.0 ? &cfg->speed : NULL, &cfg->gfx,
1574 &cfg->stic, &cfg->event, debug_symtbl,
1575 &cfg->stic.vid_enable, debug_script, &cfg->do_exit))
1576 {
1577 fprintf(stderr, "ERROR: Failed to initialize debugger\n");
1578 exit(1);
1579 }
1580
1581 if (joy_init(1, joy_cfg))
1582 {
1583 fprintf(stderr, "ERROR: Failed to initialize joystick subsystem.\n");
1584 exit(1);
1585 }
1586
1587 if (event_init(&cfg->event, enable_mouse, initial_event_map))
1588 {
1589 fprintf(stderr, "ERROR: Failed to initialize event subsystem.\n");
1590 exit(1);
1591 }
1592
1593 /* We must configure event bindings after initializing event subsystem. */
1594 if (cfg_setbind(cfg, kbdhackfile))
1595 {
1596 fprintf(stderr, "ERROR: Failed to initialize key bindings\n");
1597 exit(1);
1598 }
1599
1600 if (cfg->ivc_enable > 0 && cfg->audio_rate > 0 &&
1601 ivoice_init(&cfg->ivoice, 0x80, &cfg->snd,
1602 cfg->audio_rate, cfg->ivc_window, cfg->ivc_tname,
1603 cfg->pal_mode, cfg->rate_ctl > 0.0 ? cfg->rate_ctl : 1.0))
1604 {
1605 fprintf(stderr, "ERROR: Failed to initialize Intellivoice\n");
1606 exit(1);
1607 }
1608
1609 /* -------------------------------------------------------------------- */
1610 /* Note: We handle the EXEC ROM specially, since it's weird on */
1611 /* the Intellivision 2. */
1612 /* -------------------------------------------------------------------- */
1613 if (exec_type == 0)
1614 {
1615 if (mem_make_rom(&cfg->exec, 16, 0x1000, 12, cfg->exec_img))
1616 {
1617 fprintf(stderr, "ERROR: Failed to initialize EXEC ROM\n");
1618 exit(1);
1619 }
1620 } else if (exec_type == 1)
1621 {
1622 if (mem_make_rom(&cfg->exec, 16, 0x1000, 12, cfg->exec_img+256) ||
1623 mem_make_rom(&cfg->exec2, 16, 0x0400, 8, cfg->exec_img))
1624 {
1625 fprintf(stderr, "ERROR: Failed to initialize EXEC2 ROM\n");
1626 exit(1);
1627 }
1628 } else if (exec_type == 2)
1629 {
1630 if (mem_make_rom(&cfg->exec, 16, 0x1000, 12, cfg->exec_img) ||
1631 mem_make_rom(&cfg->exec2, 16, 0x2000, 12, cfg->exec_img + 4096))
1632 {
1633 fprintf(stderr, "ERROR: Failed to initialize WBEXEC ROM\n");
1634 exit(1);
1635 }
1636 }
1637
1638 /* -------------------------------------------------------------------- */
1639 /* Now register all the devices on the Intellivision's bus. */
1640 /* -------------------------------------------------------------------- */
1641 #define P(x) cfg->intv, AS_PERIPH(&cfg->x)
1642
1643 periph_register (P(cp1600 ), 0x0000, 0x0000, "CP-1610" );
1644
1645 periph_register (P(psg0 ), 0x01F0, 0x01FF, "PSG0 AY8914" );
1646 if (cfg->ecs_enable > 0)
1647 periph_register(P(psg1 ), 0x00F0, 0x00FF, "PSG1 AY8914" );
1648
1649 if (cfg->ivc_enable > 0 && cfg->audio_rate)
1650 periph_register(P(ivoice ), 0x0080, 0x0081, "Int. Voice" );
1651
1652 periph_register (P(gfx ), 0x0000, 0x0000, "[Graphics]" );
1653 if (cfg->audio_rate)
1654 periph_register(P(snd ), 0x0000, 0x0000, "[Sound]" );
1655
1656 periph_register (P(scr_ram ), 0x0100, 0x01EF, "Scratch RAM" );
1657 /* periph_register (P(glt_ram ), 0xD000, 0xDFFF, "GLITCH RAM" );*/
1658
1659 switch (exec_type)
1660 {
1661 case 0:
1662 {
1663 periph_register(P(sys_ram ), 0x0200, 0x035F, "System RAM" );
1664 periph_register(P(exec ), 0x1000, 0x1FFF, "EXEC ROM" );
1665 break;
1666 }
1667 case 1:
1668 {
1669 periph_register(P(sys_ram ), 0x0200, 0x035F, "System RAM" );
1670 periph_register(P(sys_ram2 ), 0x0360, 0x03FF, "System RAM B");
1671 periph_register(P(exec ), 0x1000, 0x1FFF, "EXEC2 main" );
1672 periph_register(P(exec2 ), 0x0400, 0x04FF, "EXEC2 aux." );
1673 break;
1674 }
1675 case 2:
1676 {
1677 periph_register(P(sys_ram ), 0x0200, 0x03FF, "System RAM" );
1678 periph_register(P(sys_ram2 ), 0x0400, 0x04FF, "System RAM B");
1679 periph_register(P(exec ), 0x1000, 0x1FFF, "EXEC ROM" );
1680 periph_register(P(exec2 ), 0x2000, 0x2FFF, "WBEXEC ROM" );
1681 break;
1682 }
1683 default:
1684 {
1685 jzp_printf("Unknown EXEC type %d\n", exec_type);
1686 exit(1);
1687 }
1688 }
1689
1690 if (cfg->ecs_enable > 0)
1691 ecs_register(&cfg->ecs, cfg->intv);
1692
1693 periph_register (P(pad0 ), 0x01F0, 0x01FF, "Pad Pair 0" );
1694 if (cfg->ecs_enable > 0)
1695 periph_register(P(pad1 ), 0x00F0, 0x00FF, "Pad Pair 1" );
1696 if (cfg->i2pc0_port)
1697 periph_register(P(i2pc0 ), 0x01F0, 0x01FF, "INTV2PC #0" );
1698 if (cfg->i2pc1_port && cfg->ecs_enable > 0)
1699 periph_register(P(i2pc1 ), 0x00F0, 0x00FF, "INTV2PC #1" );
1700 if (cfg->cgc0_num >= 0)
1701 periph_register(P(cgc0 ), 0x01F0, 0x01FF, "CGC #0" );
1702 if (cfg->cgc1_num >= 0 && cfg->ecs_enable > 0)
1703 periph_register(P(cgc1 ), 0x00F0, 0x00FF, "CGC #1" );
1704 periph_register (P(stic.stic_cr ), 0x0000, 0x007F, "STIC" );
1705 if (exec_type != 2)
1706 {
1707 periph_register(P(stic.stic_cr ), 0x4000, 0x403F, "STIC (alias)");
1708 periph_register(P(stic.stic_cr ), 0x8000, 0x803F, "STIC (alias)");
1709 periph_register(P(stic.stic_cr ), 0xC000, 0xC03F, "STIC (alias)");
1710 }
1711 periph_register (P(stic.snoop_btab), 0x0200, 0x02EF, "STIC (BTAB)" );
1712 periph_register (P(stic.snoop_gram), 0x3000, 0x3FFF, "GROM/GRAM" );
1713 if (exec_type != 2 && cfg->ecs_enable < 1)
1714 {
1715 periph_register(P(stic.alias_gram), 0x7800, 0x7FFF, "GRAM (alias)");
1716 periph_register(P(stic.alias_gram), 0xB800, 0xBFFF, "GRAM (alias)");
1717 periph_register(P(stic.alias_gram), 0xF800, 0xFFFF, "GRAM (alias)");
1718 }
1719
1720 periph_register (P(event ), 0x0000, 0x0000, "[Event]" );
1721
1722 if (cfg->rate_ctl > 0.0)
1723 periph_register(P(speed ), 0x0000, 0x0000, "[Rate Ctrl]" );
1724
1725 /* -------------------------------------------------------------------- */
1726 /* Register the game ROMs, or the Intellicart, as the case may be. */
1727 /* -------------------------------------------------------------------- */
1728 if (locutus)
1729 {
1730 periph_register(P(locutus), 0x0000, 0xFFFF, "Locutus");
1731 } else if (legacy_rom)
1732 {
1733 legacy_register(&cfg->legacy, cfg->intv, &cfg->cp1600);
1734 } else
1735 {
1736 icart_register(&cfg->icart, cfg->intv, &cfg->cp1600, cache_flags);
1737 }
1738
1739 /* -------------------------------------------------------------------- */
1740 /* Mark the ROMs cacheable in the CPU. Mark the 16-bit RAM as cache- */
1741 /* able, but in need of bus-snoop support. */
1742 /* -------------------------------------------------------------------- */
1743 cp1600_cacheable(&cfg->cp1600, 0x0200, 0x035F, 1);
1744 cp1600_cacheable(&cfg->cp1600, 0x1000, 0x1FFF, 0);
1745 cp1600_cacheable(&cfg->cp1600, 0x3000, 0x37FF, 0);
1746
1747 /* -------------------------------------------------------------------- */
1748 /* If JLP save-games are enabled, install the JLP neccessary portion */
1749 /* of the JLP RAM window at $9C80 to $9FFF. JLP games that use the */
1750 /* SG support need to NOT declare RAM in this space!!! */
1751 /* -------------------------------------------------------------------- */
1752 if (jlp_accel > 0)
1753 periph_register(P(jlp ), 0x8000, 0x9FFF, "JLP Support" );
1754
1755 /* -------------------------------------------------------------------- */
1756 /* Register the debugger. This _must_ be done last. */
1757 /* -------------------------------------------------------------------- */
1758 if (cfg->debugging)
1759 periph_register(P(debug ), 0x0000, 0xFFFF, "[Debugger]" );
1760
1761 #if 0
1762 {
1763 f = fopen("ser.txt", "w");
1764 if (f)
1765 ser_print_hierarchy(f, NULL, 0, 0);
1766 }
1767 #endif
1768
1769 /* -------------------------------------------------------------------- */
1770 /* Load the source mapping if given one. */
1771 /* -------------------------------------------------------------------- */
1772 if (cfg->debugging && debug_srcmap)
1773 process_source_map(debug_srcmap);
1774
1775 /* -------------------------------------------------------------------- */
1776 /* Register the cheat engine if we have any cheats. */
1777 /* -------------------------------------------------------------------- */
1778 if (cheat_count(&cfg->cheat))
1779 periph_register(P(cheat), 0x0000, 0x0000, "[Cheat]");
1780
1781 /* -------------------------------------------------------------------- */
1782 /* Free up all of our temporary variables. */
1783 /* -------------------------------------------------------------------- */
1784 CONDFREE(audiofile);
1785 CONDFREE(kbdhackfile);
1786 CONDFREE(demofile);
1787 CONDFREE(jlpsg);
1788 CONDFREE(debug_symtbl);
1789 CONDFREE(debug_srcmap);
1790 CONDFREE(elfi_prefix);
1791 return;
1792 }
1793
1794 /* ======================================================================== */
1795 /* CFG_DTOR -- Tear down a configured Intellivision. */
1796 /* ======================================================================== */
cfg_dtor(cfg_t * cfg)1797 void cfg_dtor(cfg_t *cfg)
1798 {
1799 periph_delete(cfg->intv);
1800 CONDFREE(cfg->ivc_tname);
1801 CONDFREE(cfg->cgc0_dev);
1802 CONDFREE(cfg->cgc1_dev);
1803 CONDFREE(cfg->fn_exec);
1804 CONDFREE(cfg->fn_game);
1805 CONDFREE(cfg->fn_grom);
1806 CONDFREE(cfg->fn_ecs);
1807 CONDFREE(cfg->cart_name);
1808
1809 elfi_dtor();
1810 memset(cfg, 0, sizeof(cfg_t));
1811 }
1812
1813 /* ======================================================================== */
1814 /* This program is free software; you can redistribute it and/or modify */
1815 /* it under the terms of the GNU General Public License as published by */
1816 /* the Free Software Foundation; either version 2 of the License, or */
1817 /* (at your option) any later version. */
1818 /* */
1819 /* This program is distributed in the hope that it will be useful, */
1820 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
1821 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
1822 /* General Public License for more details. */
1823 /* */
1824 /* You should have received a copy of the GNU General Public License along */
1825 /* with this program; if not, write to the Free Software Foundation, Inc., */
1826 /* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
1827 /* ======================================================================== */
1828 /* Copyright (c) 1998-2000, Joseph Zbiciak */
1829 /* ======================================================================== */
1830