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