|
|
1.1 root 1: /*
2: Hatari - options.c
3:
4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
6:
7: Functions for showing and parsing all of Hatari's command line options.
8:
9: To add a new option:
10: - Add option ID to the enum
11: - Add the option information to HatariOptions[]
12: - Add required actions for that ID to switch in Opt_ParseParameters()
13: */
14: const char Options_fileid[] = "Hatari options.c : " __DATE__ " " __TIME__;
15:
16: #include <ctype.h>
17: #include <stdio.h>
18: #include <stdlib.h>
19: #include <string.h>
20: #include <assert.h>
21: #include <SDL.h>
22:
23: #include "main.h"
24: #include "options.h"
25: #include "configuration.h"
26: #include "control.h"
27: #include "debugui.h"
28: #include "file.h"
29: #include "screen.h"
30: #include "video.h"
31: #include "log.h"
1.1.1.2 root 32: #include "paths.h"
1.1 root 33: #include "avi_record.h"
34:
35: #include "hatari-glue.h"
36:
37:
38: bool bLoadAutoSave; /* Load autosave memory snapshot at startup */
39: bool bLoadMemorySave; /* Load memory snapshot provided via option at startup */
40: bool bBiosIntercept; /* whether UAE should intercept Bios & XBios calls */
41: bool AviRecordOnStartup; /* Start avi recording at startup */
42:
43: static bool bNoSDLParachute;
44:
45: /* List of supported options. */
46: enum {
47: OPT_HEADER, /* options section header */
48: OPT_HELP, /* general options */
49: OPT_VERSION,
50: OPT_CONFIRMQUIT,
51: OPT_CONFIGFILE,
1.1.1.2 root 52: OPT_KEYMAPFILE,
1.1 root 53: OPT_FASTFORWARD,
1.1.1.2 root 54: OPT_MONO, /* common display options */
1.1 root 55: OPT_MONITOR,
56: OPT_FULLSCREEN,
57: OPT_WINDOW,
58: OPT_GRAB,
59: OPT_FRAMESKIPS,
60: OPT_STATUSBAR,
61: OPT_DRIVE_LED,
62: OPT_FORCEBPP,
1.1.1.2 root 63: OPT_BORDERS, /* ST/STE display options */
64: OPT_SPEC512,
65: OPT_ZOOM,
66: OPT_RESOLUTION, /* Falcon/TT display options */
67: OPT_MAXWIDTH,
68: OPT_MAXHEIGHT,
69: OPT_ASPECT,
1.1 root 70: OPT_VDI, /* VDI options */
71: OPT_VDI_PLANES,
72: OPT_VDI_WIDTH,
73: OPT_VDI_HEIGHT,
1.1.1.2 root 74: OPT_SCREEN_CROP, /* screen capture options */
75: OPT_AVIRECORD,
1.1 root 76: OPT_AVIRECORD_VCODEC,
77: OPT_AVIRECORD_FPS,
78: OPT_AVIRECORD_FILE,
79: OPT_JOYSTICK, /* device options */
80: OPT_JOYSTICK0,
81: OPT_JOYSTICK1,
82: OPT_JOYSTICK2,
83: OPT_JOYSTICK3,
84: OPT_JOYSTICK4,
85: OPT_JOYSTICK5,
86: OPT_PRINTER,
87: OPT_MIDI_IN,
88: OPT_MIDI_OUT,
89: OPT_RS232_IN,
90: OPT_RS232_OUT,
91: OPT_DISKA, /* disk options */
92: OPT_DISKB,
93: OPT_SLOWFLOPPY,
94: OPT_WRITEPROT_FLOPPY,
95: OPT_WRITEPROT_HD,
96: OPT_HARDDRIVE,
97: OPT_ACSIHDIMAGE,
98: OPT_IDEMASTERHDIMAGE,
99: OPT_IDESLAVEHDIMAGE,
100: OPT_MEMSIZE, /* memory options */
101: OPT_TOS,
102: OPT_CARTRIDGE,
103: OPT_MEMSTATE,
104: OPT_CPULEVEL, /* CPU options */
105: OPT_CPUCLOCK,
106: OPT_COMPATIBLE,
1.1.1.4 ! root 107:
1.1.1.2 root 108: OPT_CPU_CYCLE_EXACT, /* WinUAE CPU/FPU/bus options */
109: OPT_CPU_ADDR24,
110: OPT_FPU_TYPE,
111: OPT_FPU_COMPATIBLE,
112: OPT_MMU,
1.1.1.4 ! root 113:
1.1 root 114: OPT_MACHINE, /* system options */
115: OPT_BLITTER,
116: OPT_DSP,
1.1.1.2 root 117: OPT_MICROPHONE,
1.1 root 118: OPT_SOUND,
119: OPT_SOUNDBUFFERSIZE,
1.1.1.2 root 120: OPT_YM_MIXING,
121: OPT_TIMERD,
122: OPT_RTC,
1.1 root 123: OPT_DEBUG, /* debug options */
124: OPT_BIOSINTERCEPT,
125: OPT_TRACE,
126: OPT_TRACEFILE,
127: OPT_PARSE,
128: OPT_SAVECONFIG,
129: OPT_PARACHUTE,
130: OPT_CONTROLSOCKET,
131: OPT_LOGFILE,
132: OPT_LOGLEVEL,
133: OPT_ALERTLEVEL,
134: OPT_RUNVBLS,
135: OPT_ERROR,
136: OPT_CONTINUE
137: };
138:
139: typedef struct {
140: unsigned int id; /* option ID */
141: const char *chr; /* short option */
142: const char *str; /* long option */
143: const char *arg; /* type name for argument, if any */
144: const char *desc; /* option description */
145: } opt_t;
146:
147: /* it's easier to edit these if they are kept in the same order as the enums */
148: static const opt_t HatariOptions[] = {
149:
150: { OPT_HEADER, NULL, NULL, NULL, "General" },
151: { OPT_HELP, "-h", "--help",
152: NULL, "Print this help text and exit" },
153: { OPT_VERSION, "-v", "--version",
154: NULL, "Print version number and exit" },
155: { OPT_CONFIRMQUIT, NULL, "--confirm-quit",
156: "<bool>", "Whether Hatari confirms quit" },
157: { OPT_CONFIGFILE, "-c", "--configfile",
158: "<file>", "Use <file> instead of the default hatari config file" },
1.1.1.2 root 159: { OPT_KEYMAPFILE, "-k", "--keymap",
160: "<file>", "Read (additional) keyboard mappings from <file>" },
1.1 root 161: { OPT_FASTFORWARD, NULL, "--fast-forward",
162: "<bool>", "Help skipping stuff on fast machine" },
163:
1.1.1.2 root 164: { OPT_HEADER, NULL, NULL, NULL, "Common display" },
1.1 root 165: { OPT_MONO, "-m", "--mono",
166: NULL, "Start in monochrome mode instead of color" },
167: { OPT_MONITOR, NULL, "--monitor",
168: "<x>", "Select monitor type (x = mono/rgb/vga/tv)" },
169: { OPT_FULLSCREEN,"-f", "--fullscreen",
170: NULL, "Start emulator in fullscreen mode" },
171: { OPT_WINDOW, "-w", "--window",
172: NULL, "Start emulator in window mode" },
173: { OPT_GRAB, NULL, "--grab",
174: NULL, "Grab mouse (also) in window mode" },
175: { OPT_FRAMESKIPS, NULL, "--frameskips",
176: "<x>", "Skip <x> frames after each shown frame (0=off, >4=auto/max)" },
177: { OPT_STATUSBAR, NULL, "--statusbar",
178: "<bool>", "Show statusbar (floppy leds etc)" },
179: { OPT_DRIVE_LED, NULL, "--drive-led",
180: "<bool>", "Show overlay drive led when statusbar isn't shown" },
181: { OPT_FORCEBPP, NULL, "--bpp",
182: "<x>", "Force internal bitdepth (x = 8/15/16/32, 0=disable)" },
183:
1.1.1.2 root 184: { OPT_HEADER, NULL, NULL, NULL, "ST/STE specific display" },
185: { OPT_BORDERS, NULL, "--borders",
186: "<bool>", "Show screen borders (for overscan demos etc)" },
187: { OPT_SPEC512, NULL, "--spec512",
188: "<x>", "Spec512 palette threshold (0 <= x <= 512, 0=disable)" },
189: { OPT_ZOOM, "-z", "--zoom",
190: "<x>", "Double small resolutions (1=no, 2=yes)" },
191:
192: { OPT_HEADER, NULL, NULL, NULL, "Falcon/TT specific display" },
193: { OPT_RESOLUTION, NULL, "--desktop",
194: "<bool>", "Keep desktop resolution on fullscreen" },
195: { OPT_MAXWIDTH, NULL, "--max-width",
196: "<x>", "Maximum window width for zooming" },
197: { OPT_MAXHEIGHT, NULL, "--max-height",
198: "<x>", "Maximum window height for zooming" },
199: { OPT_ASPECT, NULL, "--aspect",
200: "<bool>", "Monitor aspect ratio correction" },
201:
1.1 root 202: { OPT_HEADER, NULL, NULL, NULL, "VDI" },
203: { OPT_VDI, NULL, "--vdi",
204: "<bool>", "Whether to use VDI screen mode" },
205: { OPT_VDI_PLANES,NULL, "--vdi-planes",
206: "<x>", "VDI mode bit-depth (x = 1/2/4)" },
207: { OPT_VDI_WIDTH, NULL, "--vdi-width",
208: "<w>", "VDI mode width (320 < w <= 1280)" },
209: { OPT_VDI_HEIGHT, NULL, "--vdi-height",
210: "<h>", "VDI mode height (200 < h <= 960)" },
211:
1.1.1.2 root 212: { OPT_HEADER, NULL, NULL, NULL, "Screen capture" },
213: { OPT_SCREEN_CROP, NULL, "--crop",
214: "<bool>", "Remove statusbar from screen capture" },
1.1 root 215: { OPT_AVIRECORD, NULL, "--avirecord",
216: NULL, "Start AVI recording" },
217: { OPT_AVIRECORD_VCODEC, NULL, "--avi-vcodec",
218: "<x>", "Select avi video codec (x = bmp/png)" },
219: { OPT_AVIRECORD_FPS, NULL, "--avi-fps",
220: "<x>", "Force avi frame rate (x = 50/60/71/...)" },
221: { OPT_AVIRECORD_FILE, NULL, "--avi-file",
222: "<file>", "Use <file> to record avi" },
223:
224: { OPT_HEADER, NULL, NULL, NULL, "Devices" },
225: { OPT_JOYSTICK, "-j", "--joystick",
226: "<port>", "Emulate joystick with cursor keys in given port (0-5)" },
227: /* these have to be exactly the same as I'm relying compiler giving
228: * them the same same string pointer when strings are identical
229: * (Opt_ShowHelpSection() skips successive options with same help
230: * pointer).
231: */
232: { OPT_JOYSTICK0, NULL, "--joy<port>",
233: "<type>", "Set joystick type (none/keys/real) for given port" },
234: { OPT_JOYSTICK1, NULL, "--joy<port>",
235: "<type>", "Set joystick type (none/keys/real) for given port" },
236: { OPT_JOYSTICK2, NULL, "--joy<port>",
237: "<type>", "Set joystick type (none/keys/real) for given port" },
238: { OPT_JOYSTICK3, NULL, "--joy<port>",
239: "<type>", "Set joystick type (none/keys/real) for given port" },
240: { OPT_JOYSTICK4, NULL, "--joy<port>",
241: "<type>", "Set joystick type (none/keys/real) for given port" },
242: { OPT_JOYSTICK5, NULL, "--joy<port>",
243: "<type>", "Set joystick type (none/keys/real) for given port" },
244: { OPT_PRINTER, NULL, "--printer",
245: "<file>", "Enable printer support and write data to <file>" },
246: { OPT_MIDI_IN, NULL, "--midi-in",
247: "<file>", "Enable MIDI and use <file> as the input device" },
248: { OPT_MIDI_OUT, NULL, "--midi-out",
249: "<file>", "Enable MIDI and use <file> as the output device" },
250: { OPT_RS232_IN, NULL, "--rs232-in",
251: "<file>", "Enable serial port and use <file> as the input device" },
252: { OPT_RS232_OUT, NULL, "--rs232-out",
253: "<file>", "Enable serial port and use <file> as the output device" },
254:
255: { OPT_HEADER, NULL, NULL, NULL, "Disk" },
256: { OPT_DISKA, NULL, "--disk-a",
257: "<file>", "Set disk image for floppy drive A" },
258: { OPT_DISKB, NULL, "--disk-b",
259: "<file>", "Set disk image for floppy drive B" },
260: { OPT_SLOWFLOPPY, NULL, "--slowfdc",
261: "<bool>", "Slow down floppy disk access emulation" },
262: { OPT_WRITEPROT_FLOPPY, NULL, "--protect-floppy",
263: "<x>", "Write protect floppy image contents (on/off/auto)" },
264: { OPT_WRITEPROT_HD, NULL, "--protect-hd",
265: "<x>", "Write protect harddrive <dir> contents (on/off/auto)" },
266: { OPT_HARDDRIVE, "-d", "--harddrive",
267: "<dir>", "Emulate harddrive partition(s) with <dir> contents" },
268: { OPT_ACSIHDIMAGE, NULL, "--acsi",
269: "<file>", "Emulate an ACSI harddrive with an image <file>" },
270: { OPT_IDEMASTERHDIMAGE, NULL, "--ide-master",
271: "<file>", "Emulate an IDE master harddrive with an image <file>" },
272: { OPT_IDESLAVEHDIMAGE, NULL, "--ide-slave",
273: "<file>", "Emulate an IDE slave harddrive with an image <file>" },
274:
275: { OPT_HEADER, NULL, NULL, NULL, "Memory" },
276: { OPT_MEMSIZE, "-s", "--memsize",
277: "<x>", "ST RAM size (x = size in MiB from 0 to 14, 0 = 512KiB)" },
278: { OPT_TOS, "-t", "--tos",
279: "<file>", "Use TOS image <file>" },
280: { OPT_CARTRIDGE, NULL, "--cartridge",
281: "<file>", "Use ROM cartridge image <file>" },
282: { OPT_MEMSTATE, NULL, "--memstate",
283: "<file>", "Load memory snap-shot <file>" },
284:
285: { OPT_HEADER, NULL, NULL, NULL, "CPU" },
286: { OPT_CPULEVEL, NULL, "--cpulevel",
287: "<x>", "Set the CPU type (x => 680x0) (EmuTOS/TOS 2.06 only!)" },
288: { OPT_CPUCLOCK, NULL, "--cpuclock",
289: "<x>", "Set the CPU clock (x = 8/16/32)" },
290: { OPT_COMPATIBLE, NULL, "--compatible",
291: "<bool>", "Use a more compatible (but slower) 68000 CPU mode" },
1.1.1.2 root 292:
293: { OPT_HEADER, NULL, NULL, NULL, "WinUAE CPU/FPU/bus" },
294: { OPT_CPU_CYCLE_EXACT, NULL, "--cpu-exact",
295: "<bool>", "Use cycle exact CPU emulation" },
296: { OPT_CPU_ADDR24, NULL, "--addr24",
297: "<bool>", "Use 24-bit instead of 32-bit addressing mode" },
298: { OPT_FPU_TYPE, NULL, "--fpu-type",
299: "<x>", "FPU type (x=none/68881/68882/internal)" },
300: { OPT_FPU_COMPATIBLE, NULL, "--fpu-compatible",
301: "<bool>", "Use more compatible, but slower FPU emulation" },
302: { OPT_MMU, NULL, "--mmu",
303: "<bool>", "Use MMU emulation" },
304:
1.1 root 305: { OPT_HEADER, NULL, NULL, NULL, "Misc system" },
306: { OPT_MACHINE, NULL, "--machine",
307: "<x>", "Select machine type (x = st/ste/tt/falcon)" },
308: { OPT_BLITTER, NULL, "--blitter",
309: "<bool>", "Use blitter emulation (ST only)" },
310: { OPT_DSP, NULL, "--dsp",
311: "<x>", "DSP emulation (x = none/dummy/emu, Falcon only)" },
1.1.1.2 root 312: { OPT_MICROPHONE, NULL, "--mic",
313: "<bool>", "Enable/disable (Falcon only) microphone" },
1.1 root 314: { OPT_SOUND, NULL, "--sound",
315: "<x>", "Sound frequency (x=off/6000-50066, off=fastest)" },
316: { OPT_SOUNDBUFFERSIZE, NULL, "--sound-buffer-size",
1.1.1.2 root 317: "<x>", "Sound buffer size for SDL in ms (x=0/10-100, 0=default)" },
318: { OPT_YM_MIXING, NULL, "--ym-mixing",
319: "<x>", "YM sound mixing method (x=linear/table)" },
320: { OPT_TIMERD, NULL, "--timer-d",
321: "<bool>", "Patch Timer-D (about doubles ST emulation speed)" },
322: { OPT_RTC, NULL, "--rtc",
323: "<bool>", "Enable real-time clock" },
324:
1.1 root 325: { OPT_HEADER, NULL, NULL, NULL, "Debug" },
326: { OPT_DEBUG, "-D", "--debug",
327: NULL, "Toggle whether CPU exceptions invoke debugger" },
328: { OPT_BIOSINTERCEPT, NULL, "--bios-intercept",
1.1.1.2 root 329: NULL, "Toggle X/Bios interception & CON: redirection" },
1.1 root 330: { OPT_TRACE, NULL, "--trace",
331: "<trace1,...>", "Activate emulation tracing, see '--trace help'" },
332: { OPT_TRACEFILE, NULL, "--trace-file",
333: "<file>", "Save trace output to <file> (default=stderr)" },
334: { OPT_PARSE, NULL, "--parse",
335: "<file>", "Parse/execute debugger commands from <file>" },
336: { OPT_SAVECONFIG, NULL, "--saveconfig",
337: NULL, "Save current Hatari configuration and exit" },
338: { OPT_PARACHUTE, NULL, "--no-parachute",
339: NULL, "Disable SDL parachute to get Hatari core dumps" },
340: #if HAVE_UNIX_DOMAIN_SOCKETS
341: { OPT_CONTROLSOCKET, NULL, "--control-socket",
342: "<file>", "Hatari reads options from given socket at run-time" },
343: #endif
344: { OPT_LOGFILE, NULL, "--log-file",
345: "<file>", "Save log output to <file> (default=stderr)" },
346: { OPT_LOGLEVEL, NULL, "--log-level",
347: "<x>", "Log output level (x=debug/todo/info/warn/error/fatal)" },
348: { OPT_ALERTLEVEL, NULL, "--alert-level",
349: "<x>", "Show dialog for log messages above given level" },
350: { OPT_RUNVBLS, NULL, "--run-vbls",
351: "<x>", "Exit after x VBLs" },
352:
353: { OPT_ERROR, NULL, NULL, NULL, NULL }
354: };
355:
356:
357: /**
358: * Show version string and license.
359: */
360: static void Opt_ShowVersion(void)
361: {
362: printf("\n" PROG_NAME
363: " - the Atari ST, STE, TT and Falcon emulator.\n\n");
364: printf("Hatari is free software licensed under the GNU General"
365: " Public License.\n\n");
366: }
367:
368:
369: /**
370: * Calculate option + value len
371: */
372: static unsigned int Opt_OptionLen(const opt_t *opt)
373: {
374: unsigned int len;
375: len = strlen(opt->str);
376: if (opt->arg)
377: {
378: len += strlen(opt->arg);
379: len += 1;
380: /* with arg, short options go to another line */
381: }
382: else
383: {
384: if (opt->chr)
385: {
386: /* ' or -c' */
387: len += 6;
388: }
389: }
390: return len;
391: }
392:
393:
394: /**
395: * Show single option
396: */
397: static void Opt_ShowOption(const opt_t *opt, unsigned int maxlen)
398: {
399: char buf[64];
400: if (!maxlen)
401: {
402: maxlen = Opt_OptionLen(opt);
403: }
404: assert(maxlen < sizeof(buf));
405: if (opt->arg)
406: {
407: sprintf(buf, "%s %s", opt->str, opt->arg);
408: printf(" %-*s %s\n", maxlen, buf, opt->desc);
409: if (opt->chr)
410: {
411: printf(" or %s %s\n", opt->chr, opt->arg);
412: }
413: }
414: else
415: {
416: if (opt->chr)
417: {
418: sprintf(buf, "%s or %s", opt->str, opt->chr);
419: printf(" %-*s %s\n", maxlen, buf, opt->desc);
420: }
421: else
422: {
423: printf(" %-*s %s\n", maxlen, opt->str, opt->desc);
424: }
425: }
426: }
427:
428: /**
429: * Show options for section starting from 'start_opt',
430: * return next option after this section.
431: */
432: static const opt_t *Opt_ShowHelpSection(const opt_t *start_opt)
433: {
434: const opt_t *opt, *last;
435: unsigned int len, maxlen = 0;
436: const char *previous = NULL;
437:
438: /* find longest option name and check option IDs */
439: for (opt = start_opt; opt->id != OPT_HEADER && opt->id != OPT_ERROR; opt++)
440: {
441: len = Opt_OptionLen(opt);
442: if (len > maxlen)
443: {
444: maxlen = len;
445: }
446: }
447: last = opt;
448:
449: /* output all options */
450: for (opt = start_opt; opt != last; opt++)
451: {
452: if (previous != opt->str)
453: {
454: Opt_ShowOption(opt, maxlen);
455: }
456: previous = opt->str;
457: }
458: return last;
459: }
460:
461:
462: /**
463: * Show help text.
464: */
465: static void Opt_ShowHelp(void)
466: {
467: const opt_t *opt = HatariOptions;
468:
469: Opt_ShowVersion();
1.1.1.2 root 470: printf("Usage:\n hatari [options] [directory|disk image|Atari program]\n");
1.1 root 471:
472: while(opt->id != OPT_ERROR)
473: {
474: if (opt->id == OPT_HEADER)
475: {
476: assert(opt->desc);
477: printf("\n%s options:\n", opt->desc);
478: opt++;
479: }
480: opt = Opt_ShowHelpSection(opt);
481: }
482: printf("\nSpecial option values:\n");
483: printf("<bool>\tDisable by using 'n', 'no', 'off', 'false', or '0'\n");
484: printf("\tEnable by using 'y', 'yes', 'on', 'true' or '1'\n");
485: printf("<file>\tDevices accept also special 'stdout' and 'stderr' file names\n");
486: printf("\t(if you use stdout for midi or printer, set log to stderr).\n");
487: printf("\tSetting the file to 'none', disables given device or disk\n");
488: }
489:
490:
491: /**
492: * Show Hatari version and usage.
493: * If 'error' given, show that error message.
494: * If 'optid' != OPT_ERROR, tells for which option the error is,
495: * otherwise 'value' is show as the option user gave.
496: * Return false if error string was given, otherwise true
497: */
498: static bool Opt_ShowError(unsigned int optid, const char *value, const char *error)
499: {
500: const opt_t *opt;
501:
502: Opt_ShowVersion();
503: printf("Usage:\n hatari [options] [disk image name]\n\n"
504: "Try option \"-h\" or \"--help\" to display more information.\n");
505:
506: if (error)
507: {
508: if (optid == OPT_ERROR)
509: {
510: fprintf(stderr, "\nError: %s (%s)\n", error, value);
511: }
512: else
513: {
514: for (opt = HatariOptions; opt->id != OPT_ERROR; opt++)
515: {
516: if (optid == opt->id)
517: break;
518: }
519: if (value != NULL)
520: {
521: fprintf(stderr,
522: "\nError while parsing argument \"%s\" for option \"%s\":\n"
523: " %s\n", value, opt->str, error);
524: }
525: else
526: {
527: fprintf(stderr, "\nError (%s): %s\n", opt->str, error);
528: }
529: fprintf(stderr, "\nOption usage:\n");
530: Opt_ShowOption(opt, 0);
531: }
532: return false;
533: }
534: return true;
535: }
536:
537:
538: /**
539: * If 'conf' given, set it:
540: * - true if given option 'arg' is y/yes/on/true/1
541: * - false if given option 'arg' is n/no/off/false/0
542: * Return false for any other value, otherwise true
543: */
544: static bool Opt_Bool(const char *arg, int optid, bool *conf)
545: {
546: const char *enablers[] = { "y", "yes", "on", "true", "1", NULL };
547: const char *disablers[] = { "n", "no", "off", "false", "0", NULL };
548: const char **bool_str, *orig = arg;
549: char *input, *str;
550:
551: input = strdup(arg);
552: str = input;
553: while (*str)
554: {
555: *str++ = tolower(*arg++);
556: }
557: for (bool_str = enablers; *bool_str; bool_str++)
558: {
559: if (strcmp(input, *bool_str) == 0)
560: {
561: free(input);
562: if (conf)
563: {
564: *conf = true;
565: }
566: return true;
567: }
568: }
569: for (bool_str = disablers; *bool_str; bool_str++)
570: {
571: if (strcmp(input, *bool_str) == 0)
572: {
573: free(input);
574: if (conf)
575: {
576: *conf = false;
577: }
578: return true;
579: }
580: }
581: free(input);
582: return Opt_ShowError(optid, orig, "Not a <bool> value");
583: }
584:
585:
586: /**
587: * checks str argument agaist options of type "--option<digit>".
588: * If match is found, returns ID for that, otherwise OPT_CONTINUE
589: * and OPT_ERROR for errors.
590: */
591: static int Opt_CheckBracketValue(const opt_t *opt, const char *str)
592: {
593: const char *bracket, *optstr;
594: size_t offset;
595: int digit, i;
596:
597: if (!opt->str)
598: {
599: return OPT_CONTINUE;
600: }
601: bracket = strchr(opt->str, '<');
602: if (!bracket)
603: {
604: return OPT_CONTINUE;
605: }
606: offset = bracket - opt->str;
607: if (strncmp(opt->str, str, offset) != 0)
608: {
609: return OPT_CONTINUE;
610: }
611: digit = str[offset] - '0';
612: if (digit < 0 || digit > 9)
613: {
614: return OPT_CONTINUE;
615: }
616: optstr = opt->str;
617: for (i = 0; opt->str == optstr; opt++, i++)
618: {
619: if (i == digit)
620: {
621: return opt->id;
622: }
623: }
624: /* fprintf(stderr, "opt: %s (%d), str: %s (%d), digit: %d\n",
625: opt->str, offset+1, str, strlen(str), digit);
626: */
627: return OPT_ERROR;
628: }
629:
630:
631: /**
632: * matches string under given index in the argv against all Hatari
633: * short and long options. If match is found, returns ID for that,
634: * otherwise shows help and returns OPT_ERROR.
635: *
636: * Checks also that if option is supposed to have argument,
637: * whether there's one.
638: */
1.1.1.2 root 639: static int Opt_WhichOption(int argc, const char * const argv[], int idx)
1.1 root 640: {
641: const opt_t *opt;
642: const char *str = argv[idx];
643: int id;
644:
645: for (opt = HatariOptions; opt->id != OPT_ERROR; opt++)
646: {
647: /* exact option name matches? */
648: if (!((opt->str && !strcmp(str, opt->str)) ||
649: (opt->chr && !strcmp(str, opt->chr))))
650: {
651: /* no, maybe name<digit> matches? */
652: id = Opt_CheckBracketValue(opt, str);
653: if (id == OPT_CONTINUE)
654: {
655: continue;
656: }
657: if (id == OPT_ERROR)
658: {
659: break;
660: }
661: }
662: /* matched, check args */
663: if (opt->arg)
664: {
665: if (idx+1 >= argc)
666: {
667: Opt_ShowError(opt->id, NULL, "Missing argument");
668: return OPT_ERROR;
669: }
670: /* early check for bools */
671: if (strcmp(opt->arg, "<bool>") == 0)
672: {
673: if (!Opt_Bool(argv[idx+1], opt->id, NULL))
674: {
675: return OPT_ERROR;
676: }
677: }
678: }
679: return opt->id;
680: }
681: Opt_ShowError(OPT_ERROR, argv[idx], "Unrecognized option");
682: return OPT_ERROR;
683: }
684:
685:
686: /**
687: * If 'checkexits' is true, assume 'src' is a file and check whether it
688: * exists before copying 'src' to 'dst'. Otherwise just copy option src
689: * string to dst.
690: * If a pointer to (bool) 'option' is given, set that option to true.
691: * - However, if src is "none", leave dst unmodified & set option to false.
692: * ("none" is used to disable options related to file arguments)
693: * Return false if there were errors, otherwise true
694: */
695: static bool Opt_StrCpy(int optid, bool checkexist, char *dst, const char *src, size_t dstlen, bool *option)
696: {
697: if (option)
698: {
699: *option = false;
700: if(strcasecmp(src, "none") == 0)
701: {
702: return true;
703: }
704: }
705: if (strlen(src) >= dstlen)
706: {
707: return Opt_ShowError(optid, src, "File name too long!");
708: }
709: if (checkexist && !File_Exists(src))
710: {
711: return Opt_ShowError(optid, src, "Given file doesn't exist (or has wrong file permissions)!");
712: }
713: if (option)
714: {
715: *option = true;
716: }
717: strcpy(dst, src);
718: return true;
719: }
720:
721:
722: /**
723: * Return SDL_INIT_NOPARACHUTE flag if user requested SDL parachute
724: * to be disabled to get proper Hatari core dumps. By default returns
725: * zero so that SDL parachute will be used to restore video mode on
726: * unclean Hatari termination.
727: */
728: Uint32 Opt_GetNoParachuteFlag(void)
729: {
730: if (bNoSDLParachute) {
731: return SDL_INIT_NOPARACHUTE;
732: }
733: return 0;
734: }
735:
736:
737: /**
1.1.1.2 root 738: * Handle last (non-option) argument. It can be a path or filename.
739: * Filename can be a disk image or Atari program.
740: * Return false if it's none of these.
741: */
742: static bool Opt_HandleArgument(const char *path)
743: {
744: char *dir = NULL;
745: Uint8 test[2];
746: FILE *fp;
747:
748: /* Atari program? */
749: if (File_Exists(path) && (fp = fopen(path, "rb"))) {
750:
751: /* file starts with GEMDOS magic? */
752: if (fread(test, 1, 2, fp) == 2 &&
753: test[0] == 0x60 && test[1] == 0x1A) {
754:
755: const char *prgname = strrchr(path, PATHSEP);
756: if (prgname) {
757: dir = strdup(path);
758: dir[prgname-path] = '\0';
759: prgname++;
760: } else {
761: dir = strdup(Paths_GetWorkingDir());
762: prgname = path;
763: }
764: /* after above, dir should point to valid dir,
765: * then make sure that given program from that
766: * dir will be started.
767: */
768: // TOS_AutoStart(prgname);
769: }
770: fclose(fp);
771: }
772: if (dir) {
773: path = dir;
774: }
775:
776: /* GEMDOS HDD directory (as argument, or for the Atari program)? */
777: if (File_DirExists(path)) {
1.1.1.3 root 778: // if (Opt_StrCpy(OPT_HARDDRIVE, false, ConfigureParams.HardDisk.szHardDiskDirectories[0],
779: // path, sizeof(ConfigureParams.HardDisk.szHardDiskDirectories[0]),
780: // &ConfigureParams.HardDisk.bUseHardDiskDirectories)
781: // && ConfigureParams.HardDisk.bUseHardDiskDirectories)
1.1.1.2 root 782: {
1.1.1.4 ! root 783: // ConfigureParams.SCSI.bBootFromHardDisk = true;
1.1.1.2 root 784: }
785: bLoadAutoSave = false;
786: if (dir) {
787: free(dir);
788: }
789: return true;
790: } else {
791: if (dir) {
792: /* if dir is set, it should be valid... */
793: Log_Printf(LOG_ERROR, "Given atari program path '%s' doesn't exist (anymore?)!\n", dir);
794: free(dir);
795: exit(1);
796: }
797: }
798:
799: /* disk image? */
800: // if (Floppy_SetDiskFileName(0, path, NULL))
801: // {
802: // ConfigureParams.HardDisk.bBootFromHardDisk = false;
803: // bLoadAutoSave = false;
804: // return true;
805: // }
806:
807: return Opt_ShowError(OPT_ERROR, path, "Not a disk image, Atari program or directory");
808: }
809:
810: /**
1.1 root 811: * parse all Hatari command line options and set Hatari state accordingly.
812: * Returns true if everything was OK, false otherwise.
813: */
1.1.1.2 root 814: bool Opt_ParseParameters(int argc, const char * const argv[])
1.1 root 815: {
816: int ncpu, skips, zoom, planes, cpuclock, threshold, memsize, port, freq, temp;
817: const char *errstr;
818: int i, ok = true;
819: int val;
820:
821: /* Defaults for loading initial memory snap-shots */
822: bLoadMemorySave = false;
823: bLoadAutoSave = ConfigureParams.Memory.bAutoSave;
824:
825: for(i = 1; i < argc; i++)
826: {
1.1.1.2 root 827: /* last argument can be a non-option */
828: if (argv[i][0] != '-' && i+1 == argc)
829: return Opt_HandleArgument(argv[i]);
1.1 root 830:
831: /* WhichOption() checks also that there is an argument,
832: * so we don't need to check that below
833: */
834: switch(Opt_WhichOption(argc, argv, i))
835: {
836:
837: /* general options */
838: case OPT_HELP:
839: Opt_ShowHelp();
840: return false;
841:
842: case OPT_VERSION:
843: Opt_ShowVersion();
844: return false;
845:
846: case OPT_CONFIRMQUIT:
847: ok = Opt_Bool(argv[++i], OPT_CONFIRMQUIT, &ConfigureParams.Log.bConfirmQuit);
848: break;
849:
850: case OPT_FASTFORWARD:
851: ok = Opt_Bool(argv[++i], OPT_FASTFORWARD, &ConfigureParams.System.bFastForward);
852: break;
853:
854: case OPT_CONFIGFILE:
855: i += 1;
856: /* true -> file needs to exist */
857: ok = Opt_StrCpy(OPT_CONFIGFILE, true, sConfigFileName,
858: argv[i], sizeof(sConfigFileName), NULL);
859: if (ok)
860: {
861: Configuration_Load(NULL);
862: bLoadAutoSave = ConfigureParams.Memory.bAutoSave;
863: }
864: break;
865:
1.1.1.2 root 866: /* common display options */
1.1 root 867: case OPT_MONO:
1.1.1.4 ! root 868: // ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_MONO;
1.1 root 869: bLoadAutoSave = false;
870: break;
871:
872: case OPT_MONITOR:
873: i += 1;
874: if (strcasecmp(argv[i], "mono") == 0)
875: {
1.1.1.4 ! root 876: // ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_MONO;
1.1 root 877: }
878: else if (strcasecmp(argv[i], "rgb") == 0)
879: {
1.1.1.4 ! root 880: // ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_RGB;
1.1 root 881: }
882: else if (strcasecmp(argv[i], "vga") == 0)
883: {
1.1.1.4 ! root 884: // ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_VGA;
1.1 root 885: }
886: else if (strcasecmp(argv[i], "tv") == 0)
887: {
1.1.1.4 ! root 888: // ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_TV;
1.1 root 889: }
890: else
891: {
892: return Opt_ShowError(OPT_MONITOR, argv[i], "Unknown monitor type");
893: }
894: bLoadAutoSave = false;
895: break;
896:
897: case OPT_FULLSCREEN:
898: ConfigureParams.Screen.bFullScreen = true;
899: break;
900:
901: case OPT_WINDOW:
902: ConfigureParams.Screen.bFullScreen = false;
903: break;
904:
905: case OPT_GRAB:
906: bGrabMouse = true;
907: break;
908:
909: case OPT_FRAMESKIPS:
910: skips = atoi(argv[++i]);
911: if (skips < 0)
912: {
913: return Opt_ShowError(OPT_FRAMESKIPS, argv[i],
914: "Invalid frame skip value");
915: }
916: else if (skips > 8)
917: {
918: Log_Printf(LOG_WARN, "Extravagant frame skip value %d!\n", skips);
919: }
920: ConfigureParams.Screen.nFrameSkips = skips;
921: break;
922:
923: case OPT_STATUSBAR:
924: ok = Opt_Bool(argv[++i], OPT_STATUSBAR, &ConfigureParams.Screen.bShowStatusbar);
925: break;
926:
927: case OPT_DRIVE_LED:
928: ok = Opt_Bool(argv[++i], OPT_DRIVE_LED, &ConfigureParams.Screen.bShowDriveLed);
929: break;
930:
931: case OPT_FORCEBPP:
932: planes = atoi(argv[++i]);
933: switch(planes)
934: {
935: case 32:
936: case 16:
937: case 15:
938: case 8:
939: break; /* supported */
940: case 24:
941: planes = 32; /* We do not support 24 bpp (yet) */
942: break;
943: default:
944: return Opt_ShowError(OPT_FORCEBPP, argv[i], "Invalid bit depth");
945: }
946: ConfigureParams.Screen.nForceBpp = planes;
947: break;
1.1.1.2 root 948:
949: /* ST/STE display options */
950: case OPT_BORDERS:
951: ok = Opt_Bool(argv[++i], OPT_BORDERS, &ConfigureParams.Screen.bAllowOverscan);
952: break;
953:
954: case OPT_SPEC512:
955: threshold = atoi(argv[++i]);
956: if (threshold < 0 || threshold > 512)
957: {
958: return Opt_ShowError(OPT_SPEC512, argv[i],
959: "Invalid palette writes per line threshold for Spec512");
960: }
961: ConfigureParams.Screen.nSpec512Threshold = threshold;
962: break;
963:
964: case OPT_ZOOM:
965: zoom = atoi(argv[++i]);
966: if (zoom < 1)
967: {
968: return Opt_ShowError(OPT_ZOOM, argv[i], "Invalid zoom value");
969: }
970: if (zoom > 1)
971: {
972: ConfigureParams.Screen.nMaxWidth = 320;
973: ConfigureParams.Screen.nMaxHeight = 200;
974: }
975: else
976: {
977: ConfigureParams.Screen.nMaxWidth = 1024;
978: ConfigureParams.Screen.nMaxHeight = 768;
979: }
980: break;
981:
982: /* Falcon/TT display options */
983: case OPT_RESOLUTION:
984: ok = Opt_Bool(argv[++i], OPT_RESOLUTION, &ConfigureParams.Screen.bKeepResolution);
985: break;
986:
987: case OPT_MAXWIDTH:
988: ConfigureParams.Screen.nMaxWidth = atoi(argv[++i]);
989: break;
990:
991: case OPT_MAXHEIGHT:
992: ConfigureParams.Screen.nMaxHeight = atoi(argv[++i]);
993: break;
994:
995: case OPT_ASPECT:
996: ok = Opt_Bool(argv[++i], OPT_ASPECT, &ConfigureParams.Screen.bAspectCorrect);
997: break;
998:
999: /* screen capture options */
1000: case OPT_SCREEN_CROP:
1001: ok = Opt_Bool(argv[++i], OPT_SCREEN_CROP, &ConfigureParams.Screen.bCrop);
1002: break;
1.1 root 1003:
1004: case OPT_AVIRECORD:
1005: AviRecordOnStartup = true;
1006: break;
1007:
1008: case OPT_AVIRECORD_VCODEC:
1009: i += 1;
1010: if (strcasecmp(argv[i], "bmp") == 0)
1011: {
1.1.1.2 root 1012: ConfigureParams.Video.AviRecordVcodec = AVI_RECORD_VIDEO_CODEC_BMP;
1.1 root 1013: }
1014: else if (strcasecmp(argv[i], "png") == 0)
1015: {
1.1.1.2 root 1016: ConfigureParams.Video.AviRecordVcodec = AVI_RECORD_VIDEO_CODEC_PNG;
1.1 root 1017: }
1018: else
1019: {
1020: return Opt_ShowError(OPT_AVIRECORD_VCODEC, argv[i], "Unknown video codec");
1021: }
1022: break;
1023:
1024: case OPT_AVIRECORD_FPS:
1025: val = atoi(argv[++i]);
1026: if (val < 0 || val > 100)
1027: {
1028: return Opt_ShowError(OPT_AVIRECORD_FPS, argv[i],
1029: "Invalid frame rate for avi recording");
1030: }
1.1.1.2 root 1031: ConfigureParams.Video.AviRecordFps = val;
1.1 root 1032: break;
1033:
1034: case OPT_AVIRECORD_FILE:
1035: i += 1;
1036: /* false -> file is created if it doesn't exist */
1.1.1.2 root 1037: ok = Opt_StrCpy(OPT_AVIRECORD_FILE, false, ConfigureParams.Video.AviRecordFile,
1038: argv[i], sizeof(ConfigureParams.Video.AviRecordFile), NULL);
1039: break;
1040:
1041: /* VDI options */
1042: case OPT_VDI:
1043: ok = Opt_Bool(argv[++i], OPT_VDI, &ConfigureParams.Screen.bUseExtVdiResolutions);
1044: if (ok)
1045: {
1046: bLoadAutoSave = false;
1047: }
1048: break;
1049:
1050: case OPT_VDI_PLANES:
1051: planes = atoi(argv[++i]);
1052: switch(planes)
1053: {
1054: case 1:
1055: // ConfigureParams.Screen.nVdiColors = GEMCOLOR_2;
1056: break;
1057: case 2:
1058: // ConfigureParams.Screen.nVdiColors = GEMCOLOR_4;
1059: break;
1060: case 4:
1061: // ConfigureParams.Screen.nVdiColors = GEMCOLOR_16;
1062: break;
1063: default:
1064: return Opt_ShowError(OPT_VDI_PLANES, argv[i], "Unsupported VDI bit-depth");
1065: }
1066: ConfigureParams.Screen.bUseExtVdiResolutions = true;
1067: bLoadAutoSave = false;
1068: break;
1069:
1070: case OPT_VDI_WIDTH:
1071: ConfigureParams.Screen.nVdiWidth = atoi(argv[++i]);
1072: ConfigureParams.Screen.bUseExtVdiResolutions = true;
1073: bLoadAutoSave = false;
1074: break;
1075:
1076: case OPT_VDI_HEIGHT:
1077: ConfigureParams.Screen.nVdiHeight = atoi(argv[++i]);
1078: ConfigureParams.Screen.bUseExtVdiResolutions = true;
1079: bLoadAutoSave = false;
1080: break;
1081:
1082: /* devices options */
1083: case OPT_JOYSTICK:
1084: i++;
1085: // if (strlen(argv[i]) != 1 ||
1086: // !Joy_SetCursorEmulation(argv[i][0] - '0'))
1087: // {
1088: // return Opt_ShowError(OPT_JOYSTICK, argv[i], "Invalid joystick port");
1089: // }
1090: break;
1091:
1092: case OPT_JOYSTICK0:
1093: case OPT_JOYSTICK1:
1094: case OPT_JOYSTICK2:
1095: case OPT_JOYSTICK3:
1096: case OPT_JOYSTICK4:
1097: case OPT_JOYSTICK5:
1098: port = argv[i][strlen(argv[i])-1] - '0';
1.1.1.3 root 1099: // assert(port >= 0 && port < JOYSTICK_COUNT);
1.1.1.2 root 1100: i += 1;
1101: if (strcasecmp(argv[i], "none") == 0)
1102: {
1.1.1.3 root 1103: // ConfigureParams.Joysticks.Joy[port].nJoystickMode = JOYSTICK_DISABLED;
1.1.1.2 root 1104: }
1105: else if (strcasecmp(argv[i], "keys") == 0)
1106: {
1.1.1.3 root 1107: // ConfigureParams.Joysticks.Joy[port].nJoystickMode = JOYSTICK_KEYBOARD;
1.1.1.2 root 1108: }
1109: else if (strcasecmp(argv[i], "real") == 0)
1110: {
1.1.1.3 root 1111: // ConfigureParams.Joysticks.Joy[port].nJoystickMode = JOYSTICK_REALSTICK;
1.1.1.2 root 1112: }
1113: else
1114: {
1115: return Opt_ShowError(OPT_JOYSTICK0+port, argv[i], "Invalid joystick type");
1116: }
1117: break;
1118:
1119: case OPT_PRINTER:
1120: i += 1;
1121: /* "none" can be used to disable printer */
1122: ok = Opt_StrCpy(OPT_PRINTER, false, ConfigureParams.Printer.szPrintToFileName,
1123: argv[i], sizeof(ConfigureParams.Printer.szPrintToFileName),
1.1.1.4 ! root 1124: &ConfigureParams.Printer.bPrinterConnected);
1.1.1.2 root 1125: break;
1126:
1127: case OPT_MIDI_IN:
1128: i += 1;
1129: ok = Opt_StrCpy(OPT_MIDI_IN, true, ConfigureParams.Midi.sMidiInFileName,
1130: argv[i], sizeof(ConfigureParams.Midi.sMidiInFileName),
1131: &ConfigureParams.Midi.bEnableMidi);
1132: break;
1133:
1134: case OPT_MIDI_OUT:
1135: i += 1;
1136: ok = Opt_StrCpy(OPT_MIDI_OUT, false, ConfigureParams.Midi.sMidiOutFileName,
1137: argv[i], sizeof(ConfigureParams.Midi.sMidiOutFileName),
1138: &ConfigureParams.Midi.bEnableMidi);
1139: break;
1140:
1141: case OPT_RS232_IN:
1142: i += 1;
1143: ok = Opt_StrCpy(OPT_RS232_IN, true, ConfigureParams.RS232.szInFileName,
1144: argv[i], sizeof(ConfigureParams.RS232.szInFileName),
1145: &ConfigureParams.RS232.bEnableRS232);
1146: break;
1147:
1148: case OPT_RS232_OUT:
1149: i += 1;
1150: ok = Opt_StrCpy(OPT_RS232_OUT, false, ConfigureParams.RS232.szOutFileName,
1151: argv[i], sizeof(ConfigureParams.RS232.szOutFileName),
1152: &ConfigureParams.RS232.bEnableRS232);
1153: break;
1154:
1155: /* disk options */
1156: case OPT_DISKA:
1157: i += 1;
1158: // if (Floppy_SetDiskFileName(0, argv[i], NULL))
1159: // {
1160: // ConfigureParams.HardDisk.bBootFromHardDisk = false;
1161: // bLoadAutoSave = false;
1162: // }
1163: // else
1164: // return Opt_ShowError(OPT_ERROR, argv[i], "Not a disk image");
1165: // break;
1166:
1167: case OPT_DISKB:
1168: i += 1;
1169: // if (Floppy_SetDiskFileName(1, argv[i], NULL))
1170: // bLoadAutoSave = false;
1171: // else
1172: // return Opt_ShowError(OPT_ERROR, argv[i], "Not a disk image");
1173: // break;
1174:
1175: case OPT_SLOWFLOPPY:
1.1.1.4 ! root 1176: // ok = Opt_Bool(argv[++i], OPT_SLOWFLOPPY, &ConfigureParams.DiskImage.bSlowFloppy);
1.1.1.2 root 1177: break;
1178:
1179: case OPT_WRITEPROT_FLOPPY:
1180: i += 1;
1181: if (strcasecmp(argv[i], "off") == 0)
1.1.1.4 ! root 1182: // ConfigureParams.DiskImage.nWriteProtection = WRITEPROT_OFF;
! 1183: // else if (strcasecmp(argv[i], "on") == 0)
! 1184: // ConfigureParams.DiskImage.nWriteProtection = WRITEPROT_ON;
! 1185: // else if (strcasecmp(argv[i], "auto") == 0)
! 1186: // ConfigureParams.DiskImage.nWriteProtection = WRITEPROT_AUTO;
! 1187: // else
1.1.1.2 root 1188: return Opt_ShowError(OPT_WRITEPROT_FLOPPY, argv[i], "Unknown option value");
1189: break;
1190:
1191: case OPT_WRITEPROT_HD:
1192: i += 1;
1.1.1.4 ! root 1193: // if (strcasecmp(argv[i], "off") == 0)
! 1194: // ConfigureParams.SCSI.nWriteProtection = WRITEPROT_OFF;
! 1195: // else if (strcasecmp(argv[i], "on") == 0)
! 1196: // ConfigureParams.SCSI.nWriteProtection = WRITEPROT_ON;
! 1197: // else if (strcasecmp(argv[i], "auto") == 0)
! 1198: // ConfigureParams.SCSI.nWriteProtection = WRITEPROT_AUTO;
! 1199: // else
1.1.1.2 root 1200: return Opt_ShowError(OPT_WRITEPROT_HD, argv[i], "Unknown option value");
1201: break;
1202:
1203: case OPT_HARDDRIVE:
1204: i += 1;
1.1.1.3 root 1205: // ok = Opt_StrCpy(OPT_HARDDRIVE, false, ConfigureParams.HardDisk.szHardDiskDirectories[0],
1206: // argv[i], sizeof(ConfigureParams.HardDisk.szHardDiskDirectories[0]),
1207: // &ConfigureParams.HardDisk.bUseHardDiskDirectories);
1208: // if (ok && ConfigureParams.HardDisk.bUseHardDiskDirectories)
1.1.1.2 root 1209: {
1.1.1.4 ! root 1210: // ConfigureParams.SCSI.bBootFromHardDisk = true;
1.1.1.2 root 1211: }
1212: bLoadAutoSave = false;
1213: break;
1214:
1215: case OPT_ACSIHDIMAGE:
1216: i += 1;
1.1.1.3 root 1217: // ok = Opt_StrCpy(OPT_ACSIHDIMAGE, true, ConfigureParams.HardDisk.szHardDiskImage,
1218: // argv[i], sizeof(ConfigureParams.HardDisk.szHardDiskImage),
1219: // &ConfigureParams.HardDisk.bUseHardDiskImage);
1.1.1.2 root 1220: if (ok)
1221: {
1222: bLoadAutoSave = false;
1223: }
1224: break;
1225:
1226: case OPT_IDEMASTERHDIMAGE:
1227: i += 1;
1.1.1.3 root 1228: // ok = Opt_StrCpy(OPT_IDEMASTERHDIMAGE, true, ConfigureParams.HardDisk.szIdeMasterHardDiskImage,
1229: // argv[i], sizeof(ConfigureParams.HardDisk.szIdeMasterHardDiskImage),
1230: // &ConfigureParams.HardDisk.bUseIdeMasterHardDiskImage);
1.1.1.2 root 1231: if (ok)
1232: {
1233: bLoadAutoSave = false;
1234: }
1.1 root 1235: break;
1236:
1.1.1.2 root 1237: case OPT_IDESLAVEHDIMAGE:
1238: i += 1;
1.1.1.3 root 1239: // ok = Opt_StrCpy(OPT_IDESLAVEHDIMAGE, true, ConfigureParams.HardDisk.szIdeSlaveHardDiskImage,
1240: // argv[i], sizeof(ConfigureParams.HardDisk.szIdeSlaveHardDiskImage),
1241: // &ConfigureParams.HardDisk.bUseIdeSlaveHardDiskImage);
1.1.1.2 root 1242: if (ok)
1243: {
1244: bLoadAutoSave = false;
1245: }
1246: break;
1.1 root 1247:
1248: /* Memory options */
1249: case OPT_MEMSIZE:
1250: memsize = atoi(argv[++i]);
1251: if (memsize < 0 || memsize > 14)
1252: {
1253: return Opt_ShowError(OPT_MEMSIZE, argv[i], "Invalid memory size");
1254: }
1.1.1.3 root 1255: // ConfigureParams.Memory.nMemorySize = memsize;
1.1 root 1256: bLoadAutoSave = false;
1257: break;
1258:
1259: case OPT_TOS:
1260: i += 1;
1.1.1.3 root 1261: // ok = Opt_StrCpy(OPT_TOS, true, ConfigureParams.Rom.szTosImageFileName,
1262: // argv[i], sizeof(ConfigureParams.Rom.szTosImageFileName),
1263: // NULL);
1.1 root 1264: if (ok)
1265: {
1266: bLoadAutoSave = false;
1267: }
1268: break;
1269:
1270: case OPT_CARTRIDGE:
1271: i += 1;
1.1.1.3 root 1272: // ok = Opt_StrCpy(OPT_CARTRIDGE, true, ConfigureParams.Rom.szCartridgeImageFileName,
1273: // argv[i], sizeof(ConfigureParams.Rom.szCartridgeImageFileName),
1274: // NULL);
1.1 root 1275: if (ok)
1276: {
1277: bLoadAutoSave = false;
1278: }
1279: break;
1280:
1281: case OPT_MEMSTATE:
1282: i += 1;
1283: ok = Opt_StrCpy(OPT_MEMSTATE, true, ConfigureParams.Memory.szMemoryCaptureFileName,
1284: argv[i], sizeof(ConfigureParams.Memory.szMemoryCaptureFileName),
1285: NULL);
1286: if (ok)
1287: {
1288: bLoadMemorySave = true;
1289: bLoadAutoSave = false;
1290: }
1291: break;
1292:
1293: /* CPU options */
1294: case OPT_CPULEVEL:
1295: /* UAE core uses cpu_level variable */
1296: ncpu = atoi(argv[++i]);
1297: if(ncpu < 0 || ncpu > 4)
1298: {
1299: return Opt_ShowError(OPT_CPULEVEL, argv[i], "Invalid CPU level");
1300: }
1301: ConfigureParams.System.nCpuLevel = ncpu;
1302: bLoadAutoSave = false;
1303: break;
1304:
1305: case OPT_CPUCLOCK:
1306: cpuclock = atoi(argv[++i]);
1307: if(cpuclock != 8 && cpuclock != 16 && cpuclock != 32)
1308: {
1309: return Opt_ShowError(OPT_CPUCLOCK, argv[i], "Invalid CPU clock");
1310: }
1311: ConfigureParams.System.nCpuFreq = cpuclock;
1312: bLoadAutoSave = false;
1313: break;
1314:
1315: case OPT_COMPATIBLE:
1316: ok = Opt_Bool(argv[++i], OPT_COMPATIBLE, &ConfigureParams.System.bCompatibleCpu);
1317: if (ok)
1318: {
1319: bLoadAutoSave = false;
1320: }
1321: break;
1322:
1323: /* system options */
1324: case OPT_MACHINE:
1325: i += 1;
1326: if (strcasecmp(argv[i], "st") == 0)
1327: {
1.1.1.3 root 1328: // ConfigureParams.System.nMachineType = MACHINE_ST;
1.1 root 1329: ConfigureParams.System.nCpuLevel = 0;
1330: ConfigureParams.System.nCpuFreq = 8;
1331: }
1332: else if (strcasecmp(argv[i], "ste") == 0)
1333: {
1.1.1.3 root 1334: // ConfigureParams.System.nMachineType = MACHINE_STE;
1.1 root 1335: ConfigureParams.System.nCpuLevel = 0;
1336: ConfigureParams.System.nCpuFreq = 8;
1337: }
1338: else if (strcasecmp(argv[i], "tt") == 0)
1339: {
1.1.1.3 root 1340: // ConfigureParams.System.nMachineType = MACHINE_TT;
1.1 root 1341: ConfigureParams.System.nCpuLevel = 3;
1342: ConfigureParams.System.nCpuFreq = 32;
1343: }
1344: else if (strcasecmp(argv[i], "falcon") == 0)
1345: {
1.1.1.2 root 1346: #if ENABLE_DSP_EMU
1347: ConfigureParams.System.nDSPType = DSP_TYPE_EMU;
1348: #endif
1.1.1.3 root 1349: // ConfigureParams.System.nMachineType = MACHINE_FALCON;
1.1 root 1350: ConfigureParams.System.nCpuLevel = 3;
1351: ConfigureParams.System.nCpuFreq = 16;
1352: }
1353: else
1354: {
1355: return Opt_ShowError(OPT_MACHINE, argv[i], "Unknown machine type");
1356: }
1357: bLoadAutoSave = false;
1358: break;
1359:
1.1.1.2 root 1360: case OPT_BLITTER:
1361: ok = Opt_Bool(argv[++i], OPT_BLITTER, &ConfigureParams.System.bBlitter);
1362: if (ok)
1363: {
1364: bLoadAutoSave = false;
1365: }
1366: break;
1.1 root 1367:
1368: case OPT_TIMERD:
1369: ok = Opt_Bool(argv[++i], OPT_TIMERD, &ConfigureParams.System.bPatchTimerD);
1370: break;
1.1.1.2 root 1371:
1372: case OPT_RTC:
1373: ok = Opt_Bool(argv[++i], OPT_RTC, &ConfigureParams.System.bRealTimeClock);
1374: break;
1375:
1376: case OPT_DSP:
1377: i += 1;
1378: if (strcasecmp(argv[i], "none") == 0)
1379: {
1380: ConfigureParams.System.nDSPType = DSP_TYPE_NONE;
1381: }
1382: else if (strcasecmp(argv[i], "dummy") == 0)
1383: {
1384: ConfigureParams.System.nDSPType = DSP_TYPE_DUMMY;
1385: }
1386: else if (strcasecmp(argv[i], "emu") == 0)
1387: {
1388: #if ENABLE_DSP_EMU
1389: ConfigureParams.System.nDSPType = DSP_TYPE_EMU;
1390: #else
1391: return Opt_ShowError(OPT_DSP, argv[i], "DSP type 'emu' support not compiled in");
1392: #endif
1393: }
1394: else
1395: {
1396: return Opt_ShowError(OPT_DSP, argv[i], "Unknown DSP type");
1397: }
1398: bLoadAutoSave = false;
1399: break;
1400:
1401: case OPT_CPU_ADDR24:
1402: ok = Opt_Bool(argv[++i], OPT_CPU_ADDR24, &ConfigureParams.System.bAddressSpace24);
1403: bLoadAutoSave = false;
1404: break;
1405:
1406: case OPT_CPU_CYCLE_EXACT:
1407: ok = Opt_Bool(argv[++i], OPT_CPU_CYCLE_EXACT, &ConfigureParams.System.bCycleExactCpu);
1408: bLoadAutoSave = false;
1409: break;
1410:
1411: case OPT_FPU_TYPE:
1412: i += 1;
1413: if (strcasecmp(argv[i], "none") == 0)
1414: {
1415: ConfigureParams.System.n_FPUType = FPU_NONE;
1416: }
1417: else if (strcasecmp(argv[i], "68881") == 0)
1418: {
1419: ConfigureParams.System.n_FPUType = FPU_68881;
1420: }
1421: else if (strcasecmp(argv[i], "68882") == 0)
1422: {
1423: ConfigureParams.System.n_FPUType = FPU_68882;
1424: }
1425: else if (strcasecmp(argv[i], "internal") == 0)
1426: {
1427: ConfigureParams.System.n_FPUType = FPU_CPU;
1428: }
1429: else
1430: {
1431: return Opt_ShowError(OPT_FPU_TYPE, argv[i], "Unknown FPU type");
1432: }
1433: bLoadAutoSave = false;
1434: break;
1435:
1436: case OPT_FPU_COMPATIBLE:
1437: ok = Opt_Bool(argv[++i], OPT_FPU_COMPATIBLE, &ConfigureParams.System.bCompatibleFPU);
1438: break;
1439:
1440: case OPT_MMU:
1441: ok = Opt_Bool(argv[++i], OPT_MMU, &ConfigureParams.System.bMMU);
1442: bLoadAutoSave = false;
1443: break;
1.1.1.4 ! root 1444:
! 1445: case OPT_YM_MIXING:
1.1.1.2 root 1446: i += 1;
1447: if (strcasecmp(argv[i], "linear") == 0)
1448: {
1449: // ConfigureParams.Sound.YmVolumeMixing = YM_LINEAR_MIXING;
1450: }
1451: else if (strcasecmp(argv[i], "table") == 0)
1452: {
1453: // ConfigureParams.Sound.YmVolumeMixing = YM_TABLE_MIXING;
1454: }
1455: else
1456: {
1457: return Opt_ShowError(OPT_YM_MIXING, argv[i], "Unknown YM mixing method");
1458: }
1459: break;
1.1 root 1460:
1.1.1.2 root 1461: case OPT_SOUND:
1462: i += 1;
1463: if (strcasecmp(argv[i], "off") == 0)
1464: {
1465: ConfigureParams.Sound.bEnableSound = false;
1466: }
1467: else
1468: {
1469: freq = atoi(argv[i]);
1470: if (freq < 6000 || freq > 50066)
1471: {
1472: return Opt_ShowError(OPT_SOUND, argv[i], "Unsupported sound frequency");
1473: }
1.1.1.4 ! root 1474: // ConfigureParams.Sound.nPlaybackFreq = freq;
1.1.1.2 root 1475: ConfigureParams.Sound.bEnableSound = true;
1476: }
1477: break;
1.1 root 1478:
1479: case OPT_SOUNDBUFFERSIZE:
1480: i += 1;
1481: temp = atoi(argv[i]);
1482: if ( temp == 0 ) /* use default setting for SDL */
1483: ;
1484: else if (temp < 10 || temp > 100)
1485: {
1486: return Opt_ShowError(OPT_SOUNDBUFFERSIZE, argv[i], "Unsupported sound buffer size");
1487: }
1.1.1.4 ! root 1488: // ConfigureParams.Sound.SdlAudioBufferSize = temp;
1.1 root 1489: break;
1.1.1.2 root 1490:
1491: case OPT_MICROPHONE:
1492: ok = Opt_Bool(argv[++i], OPT_MICROPHONE, &ConfigureParams.Sound.bEnableMicrophone);
1493: break;
1.1 root 1494:
1495: case OPT_KEYMAPFILE:
1496: i += 1;
1497: ok = Opt_StrCpy(OPT_KEYMAPFILE, true, ConfigureParams.Keyboard.szMappingFileName,
1498: argv[i], sizeof(ConfigureParams.Keyboard.szMappingFileName),
1499: NULL);
1500: if (ok)
1501: {
1502: ConfigureParams.Keyboard.nKeymapType = KEYMAP_LOADED;
1503: }
1504: break;
1505:
1506: /* debug options */
1507: case OPT_DEBUG:
1508: if (bExceptionDebugging)
1509: {
1510: fprintf(stderr, "Exception debugging disabled.\n");
1511: bExceptionDebugging = false;
1512: }
1513: else
1514: {
1515: fprintf(stderr, "Exception debugging enabled.\n");
1516: bExceptionDebugging = true;
1517: }
1518: break;
1519:
1.1.1.2 root 1520: case OPT_BIOSINTERCEPT:
1521: if (bBiosIntercept)
1522: {
1523: fprintf(stderr, "X/Bios interception disabled.\n");
1524: bBiosIntercept = false;
1525: }
1526: else
1527: {
1528: fprintf(stderr, "X/Bios interception enabled.\n");
1529: bBiosIntercept = true;
1530: }
1531: break;
1532:
1.1 root 1533: case OPT_PARACHUTE:
1534: bNoSDLParachute = true;
1535: break;
1536:
1537:
1538: case OPT_TRACE:
1539: i += 1;
1540: errstr = Log_SetTraceOptions(argv[i]);
1541: if (errstr)
1542: {
1543: if (!errstr[0]) {
1544: /* silent parsing termination */
1545: return false;
1546: }
1547: return Opt_ShowError(OPT_TRACE, argv[i], errstr);
1548: }
1549: break;
1550:
1551: case OPT_TRACEFILE:
1552: i += 1;
1553: ok = Opt_StrCpy(OPT_TRACEFILE, false, ConfigureParams.Log.sTraceFileName,
1554: argv[i], sizeof(ConfigureParams.Log.sTraceFileName),
1555: NULL);
1556: break;
1557:
1558: case OPT_CONTROLSOCKET:
1559: i += 1;
1560: errstr = Control_SetSocket(argv[i]);
1561: if (errstr)
1562: {
1563: return Opt_ShowError(OPT_CONTROLSOCKET, argv[i], errstr);
1564: }
1565: break;
1566:
1567: case OPT_LOGFILE:
1568: i += 1;
1569: ok = Opt_StrCpy(OPT_LOGFILE, false, ConfigureParams.Log.sLogFileName,
1570: argv[i], sizeof(ConfigureParams.Log.sLogFileName),
1571: NULL);
1572: break;
1573:
1574: case OPT_PARSE:
1575: i += 1;
1576: ok = DebugUI_SetParseFile(argv[i]);
1577: break;
1578:
1579: case OPT_SAVECONFIG:
1580: /* Hatari-UI needs Hatari config to start */
1581: Configuration_Save();
1582: exit(0);
1583: break;
1584:
1585: case OPT_LOGLEVEL:
1586: i += 1;
1587: ConfigureParams.Log.nTextLogLevel = Log_ParseOptions(argv[i]);
1588: if (ConfigureParams.Log.nTextLogLevel == LOG_NONE)
1589: {
1590: return Opt_ShowError(OPT_LOGLEVEL, argv[i], "Unknown log level!");
1591: }
1592: break;
1593:
1594: case OPT_ALERTLEVEL:
1595: i += 1;
1596: ConfigureParams.Log.nAlertDlgLogLevel = Log_ParseOptions(argv[i]);
1597: if (ConfigureParams.Log.nAlertDlgLogLevel == LOG_NONE)
1598: {
1599: return Opt_ShowError(OPT_ALERTLEVEL, argv[i], "Unknown alert level!");
1600: }
1601: break;
1602:
1603: case OPT_RUNVBLS:
1.1.1.2 root 1604: Main_SetRunVBLs(atol(argv[++i]));
1.1 root 1605: break;
1606:
1607: case OPT_ERROR:
1608: /* unknown option or missing option parameter */
1609: return false;
1610:
1611: default:
1612: return Opt_ShowError(OPT_ERROR, argv[i], "Internal Hatari error, unhandled option");
1613: }
1614: if (!ok)
1615: {
1616: /* Opt_Bool() or Opt_StrCpy() failed */
1617: return false;
1618: }
1619: }
1620:
1621: return true;
1622: }
1623:
1624: /**
1625: * Readline match callback for option name completion.
1626: * STATE = 0 -> different text from previous one.
1627: * Return next match or NULL if no matches.
1628: */
1629: char *Opt_MatchOption(const char *text, int state)
1630: {
1631: static int i, len;
1632: const char *name;
1633:
1634: if (!state) {
1635: /* first match */
1636: len = strlen(text);
1637: i = 0;
1638: }
1639: /* next match */
1640: while (i < ARRAYSIZE(HatariOptions)) {
1641: name = HatariOptions[i++].str;
1642: if (name && strncasecmp(name, text, len) == 0)
1643: return (strdup(name));
1644: }
1645: return NULL;
1646: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.