/** * matches string under given index in the argv against all Hatari * short and long options. If match is found, returns ID for that, * otherwise shows help and returns OPT_ERROR. * * Checks also that if option is supposed to have argument, * whether there's one. */ static int Opt_WhichOption(int argc, const char * const argv[], int idx) { const opt_t *opt; const char *str = argv[idx]; int id; for (opt = HatariOptions; opt->id != OPT_ERROR; opt++) { /* exact option name matches? */ if (!((opt->str && !strcmp(str, opt->str)) || (opt->chr && !strcmp(str, opt->chr)))) { /* no, maybe name<digit> matches? */ id = Opt_CheckBracketValue(opt, str); if (id == OPT_CONTINUE) { continue; } if (id == OPT_ERROR) { break; } } /* matched, check args */ if (opt->arg) { if (idx+1 >= argc) { Opt_ShowError(opt->id, NULL, "Missing argument"); return OPT_ERROR; } /* early check for bools */ if (strcmp(opt->arg, "<bool>") == 0) { if (!Opt_Bool(argv[idx+1], opt->id, NULL)) { return OPT_ERROR; } } } return opt->id; } Opt_ShowError(OPT_ERROR, argv[idx], "Unrecognized option"); return OPT_ERROR; }
/** * parse all Hatari command line options and set Hatari state accordingly. * Returns true if everything was OK, false otherwise. */ bool Opt_ParseParameters(int argc, const char * const argv[]) { int ncpu, skips, zoom, planes, cpuclock, threshold, memsize, port, freq, temp; const char *errstr; int i, ok = true; int val; /* Defaults for loading initial memory snap-shots */ bLoadMemorySave = false; bLoadAutoSave = ConfigureParams.Memory.bAutoSave; for(i = 1; i < argc; i++) { /* last argument can be a non-option */ if (argv[i][0] != '-' && i+1 == argc) return Opt_HandleArgument(argv[i]); /* WhichOption() checks also that there is an argument, * so we don't need to check that below */ switch(Opt_WhichOption(argc, argv, i)) { /* general options */ case OPT_HELP: Opt_ShowHelp(); return false; case OPT_VERSION: Opt_ShowVersion(); return false; case OPT_CONFIRMQUIT: ok = Opt_Bool(argv[++i], OPT_CONFIRMQUIT, &ConfigureParams.Log.bConfirmQuit); break; case OPT_FASTFORWARD: ok = Opt_Bool(argv[++i], OPT_FASTFORWARD, &ConfigureParams.System.bFastForward); break; case OPT_CONFIGFILE: i += 1; /* true -> file needs to exist */ ok = Opt_StrCpy(OPT_CONFIGFILE, true, sConfigFileName, argv[i], sizeof(sConfigFileName), NULL); if (ok) { Configuration_Load(NULL); bLoadAutoSave = ConfigureParams.Memory.bAutoSave; } break; /* common display options */ case OPT_MONO: ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_MONO; bLoadAutoSave = false; break; case OPT_MONITOR: i += 1; if (strcasecmp(argv[i], "mono") == 0) { ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_MONO; } else if (strcasecmp(argv[i], "rgb") == 0) { ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_RGB; } else if (strcasecmp(argv[i], "vga") == 0) { ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_VGA; } else if (strcasecmp(argv[i], "tv") == 0) { ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_TV; } else { return Opt_ShowError(OPT_MONITOR, argv[i], "Unknown monitor type"); } bLoadAutoSave = false; break; case OPT_FULLSCREEN: ConfigureParams.Screen.bFullScreen = true; break; case OPT_WINDOW: ConfigureParams.Screen.bFullScreen = false; break; case OPT_GRAB: bGrabMouse = true; break; case OPT_FRAMESKIPS: skips = atoi(argv[++i]); if (skips < 0) { return Opt_ShowError(OPT_FRAMESKIPS, argv[i], "Invalid frame skip value"); } else if (skips > 8) { Log_Printf(LOG_WARN, "Extravagant frame skip value %d!\n", skips); } ConfigureParams.Screen.nFrameSkips = skips; break; case OPT_STATUSBAR: ok = Opt_Bool(argv[++i], OPT_STATUSBAR, &ConfigureParams.Screen.bShowStatusbar); break; case OPT_DRIVE_LED: ok = Opt_Bool(argv[++i], OPT_DRIVE_LED, &ConfigureParams.Screen.bShowDriveLed); break; case OPT_FORCEBPP: planes = atoi(argv[++i]); switch(planes) { case 32: case 16: case 15: case 8: break; /* supported */ case 24: planes = 32; /* We do not support 24 bpp (yet) */ break; default: return Opt_ShowError(OPT_FORCEBPP, argv[i], "Invalid bit depth"); } fprintf(stderr, "Hatari window BPP = %d.\n", planes); ConfigureParams.Screen.nForceBpp = planes; break; /* ST/STE display options */ case OPT_BORDERS: ok = Opt_Bool(argv[++i], OPT_BORDERS, &ConfigureParams.Screen.bAllowOverscan); break; case OPT_RESOLUTION_ST: ok = Opt_Bool(argv[++i], OPT_RESOLUTION_ST, &ConfigureParams.Screen.bKeepResolutionST); break; case OPT_SPEC512: threshold = atoi(argv[++i]); if (threshold < 0 || threshold > 512) { return Opt_ShowError(OPT_SPEC512, argv[i], "Invalid palette writes per line threshold for Spec512"); } fprintf(stderr, "Spec512 threshold = %d palette writes per line.\n", threshold); ConfigureParams.Screen.nSpec512Threshold = threshold; break; case OPT_ZOOM: zoom = atoi(argv[++i]); if (zoom < 1) { return Opt_ShowError(OPT_ZOOM, argv[i], "Invalid zoom value"); } if (zoom > 1) { ConfigureParams.Screen.nMaxWidth = 2*(48+320+48); ConfigureParams.Screen.nMaxHeight = 2*NUM_VISIBLE_LINES+24; } else { ConfigureParams.Screen.nMaxWidth = 1*(48+320+48); ConfigureParams.Screen.nMaxHeight = 1*NUM_VISIBLE_LINES+12; } break; /* Falcon/TT display options */ case OPT_RESOLUTION: ok = Opt_Bool(argv[++i], OPT_RESOLUTION, &ConfigureParams.Screen.bKeepResolution); break; case OPT_MAXWIDTH: ConfigureParams.Screen.nMaxWidth = atoi(argv[++i]); break; case OPT_MAXHEIGHT: ConfigureParams.Screen.nMaxHeight = atoi(argv[++i]); break; case OPT_FORCE_MAX: ok = Opt_Bool(argv[++i], OPT_FORCE_MAX, &ConfigureParams.Screen.bForceMax); break; case OPT_ASPECT: ok = Opt_Bool(argv[++i], OPT_ASPECT, &ConfigureParams.Screen.bAspectCorrect); break; /* screen capture options */ case OPT_SCREEN_CROP: ok = Opt_Bool(argv[++i], OPT_SCREEN_CROP, &ConfigureParams.Screen.bCrop); break; case OPT_AVIRECORD: AviRecordOnStartup = true; break; case OPT_AVIRECORD_VCODEC: i += 1; if (strcasecmp(argv[i], "bmp") == 0) { ConfigureParams.Video.AviRecordVcodec = AVI_RECORD_VIDEO_CODEC_BMP; } else if (strcasecmp(argv[i], "png") == 0) { ConfigureParams.Video.AviRecordVcodec = AVI_RECORD_VIDEO_CODEC_PNG; } else { return Opt_ShowError(OPT_AVIRECORD_VCODEC, argv[i], "Unknown video codec"); } break; case OPT_AVIRECORD_FPS: val = atoi(argv[++i]); if (val < 0 || val > 100) { return Opt_ShowError(OPT_AVIRECORD_FPS, argv[i], "Invalid frame rate for avi recording"); } fprintf(stderr, "AVI recording FPS = %d.\n", val); ConfigureParams.Video.AviRecordFps = val; break; case OPT_AVIRECORD_FILE: i += 1; /* false -> file is created if it doesn't exist */ ok = Opt_StrCpy(OPT_AVIRECORD_FILE, false, ConfigureParams.Video.AviRecordFile, argv[i], sizeof(ConfigureParams.Video.AviRecordFile), NULL); break; /* VDI options */ case OPT_VDI: ok = Opt_Bool(argv[++i], OPT_VDI, &ConfigureParams.Screen.bUseExtVdiResolutions); if (ok) { bLoadAutoSave = false; } break; case OPT_VDI_PLANES: planes = atoi(argv[++i]); switch(planes) { case 1: ConfigureParams.Screen.nVdiColors = GEMCOLOR_2; break; case 2: ConfigureParams.Screen.nVdiColors = GEMCOLOR_4; break; case 4: ConfigureParams.Screen.nVdiColors = GEMCOLOR_16; break; default: return Opt_ShowError(OPT_VDI_PLANES, argv[i], "Unsupported VDI bit-depth"); } ConfigureParams.Screen.bUseExtVdiResolutions = true; bLoadAutoSave = false; break; case OPT_VDI_WIDTH: ConfigureParams.Screen.nVdiWidth = atoi(argv[++i]); ConfigureParams.Screen.bUseExtVdiResolutions = true; bLoadAutoSave = false; break; case OPT_VDI_HEIGHT: ConfigureParams.Screen.nVdiHeight = atoi(argv[++i]); ConfigureParams.Screen.bUseExtVdiResolutions = true; bLoadAutoSave = false; break; /* devices options */ case OPT_JOYSTICK: i++; if (strlen(argv[i]) != 1 || !Joy_SetCursorEmulation(argv[i][0] - '0')) { return Opt_ShowError(OPT_JOYSTICK, argv[i], "Invalid joystick port"); } break; case OPT_JOYSTICK0: case OPT_JOYSTICK1: case OPT_JOYSTICK2: case OPT_JOYSTICK3: case OPT_JOYSTICK4: case OPT_JOYSTICK5: port = argv[i][strlen(argv[i])-1] - '0'; assert(port >= 0 && port < JOYSTICK_COUNT); i += 1; if (strcasecmp(argv[i], "none") == 0) { ConfigureParams.Joysticks.Joy[port].nJoystickMode = JOYSTICK_DISABLED; } else if (strcasecmp(argv[i], "keys") == 0) { ConfigureParams.Joysticks.Joy[port].nJoystickMode = JOYSTICK_KEYBOARD; } else if (strcasecmp(argv[i], "real") == 0) { ConfigureParams.Joysticks.Joy[port].nJoystickMode = JOYSTICK_REALSTICK; } else { return Opt_ShowError(OPT_JOYSTICK0+port, argv[i], "Invalid joystick type"); } break; case OPT_PRINTER: i += 1; /* "none" can be used to disable printer */ ok = Opt_StrCpy(OPT_PRINTER, false, ConfigureParams.Printer.szPrintToFileName, argv[i], sizeof(ConfigureParams.Printer.szPrintToFileName), &ConfigureParams.Printer.bEnablePrinting); break; case OPT_MIDI_IN: i += 1; ok = Opt_StrCpy(OPT_MIDI_IN, true, ConfigureParams.Midi.sMidiInFileName, argv[i], sizeof(ConfigureParams.Midi.sMidiInFileName), &ConfigureParams.Midi.bEnableMidi); break; case OPT_MIDI_OUT: i += 1; ok = Opt_StrCpy(OPT_MIDI_OUT, false, ConfigureParams.Midi.sMidiOutFileName, argv[i], sizeof(ConfigureParams.Midi.sMidiOutFileName), &ConfigureParams.Midi.bEnableMidi); break; case OPT_RS232_IN: i += 1; ok = Opt_StrCpy(OPT_RS232_IN, true, ConfigureParams.RS232.szInFileName, argv[i], sizeof(ConfigureParams.RS232.szInFileName), &ConfigureParams.RS232.bEnableRS232); break; case OPT_RS232_OUT: i += 1; ok = Opt_StrCpy(OPT_RS232_OUT, false, ConfigureParams.RS232.szOutFileName, argv[i], sizeof(ConfigureParams.RS232.szOutFileName), &ConfigureParams.RS232.bEnableRS232); break; /* disk options */ case OPT_DRIVEA: ok = Opt_Bool(argv[++i], OPT_DRIVEA, &ConfigureParams.DiskImage.EnableDriveA); break; case OPT_DRIVEB: ok = Opt_Bool(argv[++i], OPT_DRIVEB, &ConfigureParams.DiskImage.EnableDriveB); break; case OPT_DISKA: i += 1; if (Floppy_SetDiskFileName(0, argv[i], NULL)) { ConfigureParams.HardDisk.bBootFromHardDisk = false; bLoadAutoSave = false; } else return Opt_ShowError(OPT_ERROR, argv[i], "Not a disk image"); break; case OPT_DISKB: i += 1; if (Floppy_SetDiskFileName(1, argv[i], NULL)) bLoadAutoSave = false; else return Opt_ShowError(OPT_ERROR, argv[i], "Not a disk image"); break; case OPT_SLOWFLOPPY: i++; fprintf(stderr, "\nWarning: --slowfdc is not supported anymore, use --fastfdc\n\n"); break; case OPT_FASTFLOPPY: ok = Opt_Bool(argv[++i], OPT_FASTFLOPPY, &ConfigureParams.DiskImage.FastFloppy); break; case OPT_WRITEPROT_FLOPPY: i += 1; if (strcasecmp(argv[i], "off") == 0) ConfigureParams.DiskImage.nWriteProtection = WRITEPROT_OFF; else if (strcasecmp(argv[i], "on") == 0) ConfigureParams.DiskImage.nWriteProtection = WRITEPROT_ON; else if (strcasecmp(argv[i], "auto") == 0) ConfigureParams.DiskImage.nWriteProtection = WRITEPROT_AUTO; else return Opt_ShowError(OPT_WRITEPROT_FLOPPY, argv[i], "Unknown option value"); break; case OPT_WRITEPROT_HD: i += 1; if (strcasecmp(argv[i], "off") == 0) ConfigureParams.HardDisk.nWriteProtection = WRITEPROT_OFF; else if (strcasecmp(argv[i], "on") == 0) ConfigureParams.HardDisk.nWriteProtection = WRITEPROT_ON; else if (strcasecmp(argv[i], "auto") == 0) ConfigureParams.HardDisk.nWriteProtection = WRITEPROT_AUTO; else return Opt_ShowError(OPT_WRITEPROT_HD, argv[i], "Unknown option value"); break; case OPT_GEMDOS_CASE: i += 1; if (strcasecmp(argv[i], "off") == 0) ConfigureParams.HardDisk.nGemdosCase = GEMDOS_NOP; else if (strcasecmp(argv[i], "upper") == 0) ConfigureParams.HardDisk.nGemdosCase = GEMDOS_UPPER; else if (strcasecmp(argv[i], "lower") == 0) ConfigureParams.HardDisk.nGemdosCase = GEMDOS_LOWER; else return Opt_ShowError(OPT_GEMDOS_CASE, argv[i], "Unknown option value"); break; case OPT_HARDDRIVE: i += 1; ok = Opt_StrCpy(OPT_HARDDRIVE, false, ConfigureParams.HardDisk.szHardDiskDirectories[0], argv[i], sizeof(ConfigureParams.HardDisk.szHardDiskDirectories[0]), &ConfigureParams.HardDisk.bUseHardDiskDirectories); if (ok && ConfigureParams.HardDisk.bUseHardDiskDirectories && ConfigureParams.HardDisk.szHardDiskDirectories[0][0]) { ConfigureParams.HardDisk.bBootFromHardDisk = true; } else { ConfigureParams.HardDisk.bUseHardDiskDirectories = false; ConfigureParams.HardDisk.bBootFromHardDisk = false; } bLoadAutoSave = false; break; case OPT_ACSIHDIMAGE: i += 1; ok = Opt_StrCpy(OPT_ACSIHDIMAGE, true, ConfigureParams.Acsi[0].sDeviceFile, argv[i], sizeof(ConfigureParams.Acsi[0].sDeviceFile), &ConfigureParams.Acsi[0].bUseDevice); if (ok) { bLoadAutoSave = false; } break; case OPT_IDEMASTERHDIMAGE: i += 1; ok = Opt_StrCpy(OPT_IDEMASTERHDIMAGE, true, ConfigureParams.HardDisk.szIdeMasterHardDiskImage, argv[i], sizeof(ConfigureParams.HardDisk.szIdeMasterHardDiskImage), &ConfigureParams.HardDisk.bUseIdeMasterHardDiskImage); if (ok) { bLoadAutoSave = false; } break; case OPT_IDESLAVEHDIMAGE: i += 1; ok = Opt_StrCpy(OPT_IDESLAVEHDIMAGE, true, ConfigureParams.HardDisk.szIdeSlaveHardDiskImage, argv[i], sizeof(ConfigureParams.HardDisk.szIdeSlaveHardDiskImage), &ConfigureParams.HardDisk.bUseIdeSlaveHardDiskImage); if (ok) { bLoadAutoSave = false; } break; /* Memory options */ case OPT_MEMSIZE: memsize = atoi(argv[++i]); if (memsize < 0 || memsize > 14) { return Opt_ShowError(OPT_MEMSIZE, argv[i], "Invalid memory size"); } ConfigureParams.Memory.nMemorySize = memsize; bLoadAutoSave = false; break; case OPT_TOS: i += 1; ok = Opt_StrCpy(OPT_TOS, true, ConfigureParams.Rom.szTosImageFileName, argv[i], sizeof(ConfigureParams.Rom.szTosImageFileName), NULL); if (ok) { bLoadAutoSave = false; } break; case OPT_PATCHTOS: ok = Opt_Bool(argv[++i], OPT_PATCHTOS, &ConfigureParams.Rom.bPatchTos); break; case OPT_CARTRIDGE: i += 1; ok = Opt_StrCpy(OPT_CARTRIDGE, true, ConfigureParams.Rom.szCartridgeImageFileName, argv[i], sizeof(ConfigureParams.Rom.szCartridgeImageFileName), NULL); if (ok) { bLoadAutoSave = false; } break; case OPT_MEMSTATE: i += 1; ok = Opt_StrCpy(OPT_MEMSTATE, true, ConfigureParams.Memory.szMemoryCaptureFileName, argv[i], sizeof(ConfigureParams.Memory.szMemoryCaptureFileName), NULL); if (ok) { bLoadMemorySave = true; bLoadAutoSave = false; } break; /* CPU options */ case OPT_CPULEVEL: /* UAE core uses cpu_level variable */ ncpu = atoi(argv[++i]); if(ncpu < 0 || ncpu > 4) { return Opt_ShowError(OPT_CPULEVEL, argv[i], "Invalid CPU level"); } ConfigureParams.System.nCpuLevel = ncpu; bLoadAutoSave = false; break; case OPT_CPUCLOCK: cpuclock = atoi(argv[++i]); if(cpuclock != 8 && cpuclock != 16 && cpuclock != 32) { return Opt_ShowError(OPT_CPUCLOCK, argv[i], "Invalid CPU clock"); } ConfigureParams.System.nCpuFreq = cpuclock; bLoadAutoSave = false; break; case OPT_COMPATIBLE: ok = Opt_Bool(argv[++i], OPT_COMPATIBLE, &ConfigureParams.System.bCompatibleCpu); if (ok) { bLoadAutoSave = false; } break; #if ENABLE_WINUAE_CPU case OPT_CPU_ADDR24: ok = Opt_Bool(argv[++i], OPT_CPU_ADDR24, &ConfigureParams.System.bAddressSpace24); bLoadAutoSave = false; break; case OPT_CPU_CYCLE_EXACT: ok = Opt_Bool(argv[++i], OPT_CPU_CYCLE_EXACT, &ConfigureParams.System.bCycleExactCpu); bLoadAutoSave = false; break; case OPT_FPU_TYPE: i += 1; if (strcasecmp(argv[i], "none") == 0) { ConfigureParams.System.n_FPUType = FPU_NONE; } else if (strcasecmp(argv[i], "68881") == 0) { ConfigureParams.System.n_FPUType = FPU_68881; } else if (strcasecmp(argv[i], "68882") == 0) { ConfigureParams.System.n_FPUType = FPU_68882; } else if (strcasecmp(argv[i], "internal") == 0) { ConfigureParams.System.n_FPUType = FPU_CPU; } else { return Opt_ShowError(OPT_FPU_TYPE, argv[i], "Unknown FPU type"); } bLoadAutoSave = false; break; case OPT_FPU_COMPATIBLE: ok = Opt_Bool(argv[++i], OPT_FPU_COMPATIBLE, &ConfigureParams.System.bCompatibleFPU); break; case OPT_MMU: ok = Opt_Bool(argv[++i], OPT_MMU, &ConfigureParams.System.bMMU); bLoadAutoSave = false; break; #endif /* system options */ case OPT_MACHINE: i += 1; if (strcasecmp(argv[i], "st") == 0) { ConfigureParams.System.nMachineType = MACHINE_ST; ConfigureParams.System.nCpuLevel = 0; ConfigureParams.System.nCpuFreq = 8; } else if (strcasecmp(argv[i], "ste") == 0) { ConfigureParams.System.nMachineType = MACHINE_STE; ConfigureParams.System.nCpuLevel = 0; ConfigureParams.System.nCpuFreq = 8; } else if (strcasecmp(argv[i], "tt") == 0) { ConfigureParams.System.nMachineType = MACHINE_TT; ConfigureParams.System.nCpuLevel = 3; ConfigureParams.System.nCpuFreq = 32; } else if (strcasecmp(argv[i], "falcon") == 0) { #if ENABLE_DSP_EMU ConfigureParams.System.nDSPType = DSP_TYPE_EMU; #endif ConfigureParams.System.nMachineType = MACHINE_FALCON; ConfigureParams.System.nCpuLevel = 3; ConfigureParams.System.nCpuFreq = 16; } else { return Opt_ShowError(OPT_MACHINE, argv[i], "Unknown machine type"); } #if ENABLE_WINUAE_CPU if (ConfigureParams.System.nMachineType == MACHINE_ST || ConfigureParams.System.nMachineType == MACHINE_STE) { ConfigureParams.System.bMMU = false; ConfigureParams.System.bAddressSpace24 = true; } if (ConfigureParams.System.nMachineType == MACHINE_TT) { ConfigureParams.System.bCompatibleFPU = true; ConfigureParams.System.n_FPUType = FPU_68882; } else { ConfigureParams.System.n_FPUType = FPU_NONE; /* TODO: or leave it as-is? */ } #endif bLoadAutoSave = false; break; case OPT_BLITTER: ok = Opt_Bool(argv[++i], OPT_BLITTER, &ConfigureParams.System.bBlitter); if (ok) { bLoadAutoSave = false; } break; case OPT_TIMERD: ok = Opt_Bool(argv[++i], OPT_TIMERD, &ConfigureParams.System.bPatchTimerD); break; case OPT_FASTBOOT: ok = Opt_Bool(argv[++i], OPT_FASTBOOT, &ConfigureParams.System.bFastBoot); break; case OPT_RTC: ok = Opt_Bool(argv[++i], OPT_RTC, &ConfigureParams.System.bRealTimeClock); break; case OPT_DSP: i += 1; if (strcasecmp(argv[i], "none") == 0) { ConfigureParams.System.nDSPType = DSP_TYPE_NONE; } else if (strcasecmp(argv[i], "dummy") == 0) { ConfigureParams.System.nDSPType = DSP_TYPE_DUMMY; } else if (strcasecmp(argv[i], "emu") == 0) { #if ENABLE_DSP_EMU ConfigureParams.System.nDSPType = DSP_TYPE_EMU; #else return Opt_ShowError(OPT_DSP, argv[i], "DSP type 'emu' support not compiled in"); #endif } else { return Opt_ShowError(OPT_DSP, argv[i], "Unknown DSP type"); } bLoadAutoSave = false; break; /* sound options */ case OPT_YM_MIXING: i += 1; if (strcasecmp(argv[i], "linear") == 0) { ConfigureParams.Sound.YmVolumeMixing = YM_LINEAR_MIXING; } else if (strcasecmp(argv[i], "table") == 0) { ConfigureParams.Sound.YmVolumeMixing = YM_TABLE_MIXING; } else if (strcasecmp(argv[i], "model") == 0) { ConfigureParams.Sound.YmVolumeMixing = YM_MODEL_MIXING; } else { return Opt_ShowError(OPT_YM_MIXING, argv[i], "Unknown YM mixing method"); } break; case OPT_SOUND: i += 1; if (strcasecmp(argv[i], "off") == 0) { ConfigureParams.Sound.bEnableSound = false; } else { freq = atoi(argv[i]); if (freq < 6000 || freq > 50066) { return Opt_ShowError(OPT_SOUND, argv[i], "Unsupported sound frequency"); } ConfigureParams.Sound.nPlaybackFreq = freq; ConfigureParams.Sound.bEnableSound = true; } fprintf(stderr, "Sound %s, frequency = %d.\n", ConfigureParams.Sound.bEnableSound ? "ON" : "OFF", ConfigureParams.Sound.nPlaybackFreq); break; case OPT_SOUNDBUFFERSIZE: i += 1; temp = atoi(argv[i]); if ( temp == 0 ) /* use default setting for SDL */ ; else if (temp < 10 || temp > 100) { return Opt_ShowError(OPT_SOUNDBUFFERSIZE, argv[i], "Unsupported sound buffer size"); } fprintf(stderr, "SDL sound buffer size = %d ms.\n", temp); ConfigureParams.Sound.SdlAudioBufferSize = temp; break; case OPT_SOUNDSYNC: ok = Opt_Bool(argv[++i], OPT_SOUNDSYNC, &ConfigureParams.Sound.bEnableSoundSync); break; case OPT_MICROPHONE: ok = Opt_Bool(argv[++i], OPT_MICROPHONE, &ConfigureParams.Sound.bEnableMicrophone); break; case OPT_KEYMAPFILE: i += 1; ok = Opt_StrCpy(OPT_KEYMAPFILE, true, ConfigureParams.Keyboard.szMappingFileName, argv[i], sizeof(ConfigureParams.Keyboard.szMappingFileName), NULL); if (ok) { ConfigureParams.Keyboard.nKeymapType = KEYMAP_LOADED; } break; /* debug options */ #ifdef WIN32 case OPT_WINCON: ConfigureParams.Log.bConsoleWindow = true; break; #endif case OPT_DEBUG: if (ExceptionDebugMask) { fprintf(stderr, "Exception debugging disabled.\n"); ExceptionDebugMask = EXCEPT_NONE; } else { ExceptionDebugMask = ConfigureParams.Log.nExceptionDebugMask; fprintf(stderr, "Exception debugging enabled (0x%x).\n", ExceptionDebugMask); } break; case OPT_EXCEPTIONS: i += 1; /* sets ConfigureParams.Log.nExceptionDebugMask */ errstr = Log_SetExceptionDebugMask(argv[i]); if (errstr) { if (!errstr[0]) { /* silent parsing termination */ return false; } return Opt_ShowError(OPT_EXCEPTIONS, argv[i], errstr); } if (ExceptionDebugMask) { /* already enabled, change run-time config */ int oldmask = ExceptionDebugMask; ExceptionDebugMask = ConfigureParams.Log.nExceptionDebugMask; fprintf(stderr, "Exception debugging changed (0x%x -> 0x%x).\n", oldmask, ExceptionDebugMask); } break; case OPT_BIOSINTERCEPT: if (bBiosIntercept) { fprintf(stderr, "X/Bios interception disabled.\n"); bBiosIntercept = false; } else { fprintf(stderr, "X/Bios interception enabled.\n"); bBiosIntercept = true; } break; case OPT_CONOUT: i += 1; ConOutDevice = atoi(argv[i]); if (ConOutDevice < 0 || ConOutDevice > 7) { return Opt_ShowError(OPT_CONOUT, argv[i], "Invalid console device vector number"); } fprintf(stderr, "Xcounout device %d vector redirection enabled.\n", ConOutDevice); break; case OPT_NATFEATS: ok = Opt_Bool(argv[++i], OPT_NATFEATS, &ConfigureParams.Log.bNatFeats); fprintf(stderr, "Native Features %s.\n", ConfigureParams.Log.bNatFeats ? "enabled" : "disabled"); break; case OPT_PARACHUTE: bNoSDLParachute = true; break; case OPT_DISASM: i += 1; errstr = Disasm_ParseOption(argv[i]); if (errstr) { if (!errstr[0]) { /* silent parsing termination */ return false; } return Opt_ShowError(OPT_DISASM, argv[i], errstr); } break; case OPT_TRACE: i += 1; errstr = Log_SetTraceOptions(argv[i]); if (errstr) { if (!errstr[0]) { /* silent parsing termination */ return false; } return Opt_ShowError(OPT_TRACE, argv[i], errstr); } break; case OPT_TRACEFILE: i += 1; ok = Opt_StrCpy(OPT_TRACEFILE, false, ConfigureParams.Log.sTraceFileName, argv[i], sizeof(ConfigureParams.Log.sTraceFileName), NULL); break; case OPT_CONTROLSOCKET: i += 1; errstr = Control_SetSocket(argv[i]); if (errstr) { return Opt_ShowError(OPT_CONTROLSOCKET, argv[i], errstr); } break; case OPT_LOGFILE: i += 1; ok = Opt_StrCpy(OPT_LOGFILE, false, ConfigureParams.Log.sLogFileName, argv[i], sizeof(ConfigureParams.Log.sLogFileName), NULL); break; case OPT_PARSE: i += 1; ok = DebugUI_SetParseFile(argv[i]); break; case OPT_SAVECONFIG: /* Hatari-UI needs Hatari config to start */ Configuration_Save(); exit(0); break; case OPT_LOGLEVEL: i += 1; ConfigureParams.Log.nTextLogLevel = Log_ParseOptions(argv[i]); if (ConfigureParams.Log.nTextLogLevel == LOG_NONE) { return Opt_ShowError(OPT_LOGLEVEL, argv[i], "Unknown log level!"); } break; case OPT_ALERTLEVEL: i += 1; ConfigureParams.Log.nAlertDlgLogLevel = Log_ParseOptions(argv[i]); if (ConfigureParams.Log.nAlertDlgLogLevel == LOG_NONE) { return Opt_ShowError(OPT_ALERTLEVEL, argv[i], "Unknown alert level!"); } break; case OPT_RUNVBLS: Main_SetRunVBLs(atol(argv[++i])); break; case OPT_ERROR: /* unknown option or missing option parameter */ return false; default: return Opt_ShowError(OPT_ERROR, argv[i], "Internal Hatari error, unhandled option"); } if (!ok) { /* Opt_Bool() or Opt_StrCpy() failed */ return false; } } return true; }
/** * parse all Hatari command line options and set Hatari state accordingly. * Returns TRUE if everything was OK, FALSE otherwise. */ bool Opt_ParseParameters(int argc, const char *argv[]) { int ncpu, skips, zoom, planes, cpuclock, threshold, memsize, port; const char *errstr; int i, ok = TRUE; /* Defaults for loading initial memory snap-shots */ bLoadMemorySave = FALSE; bLoadAutoSave = ConfigureParams.Memory.bAutoSave; for(i = 1; i < argc; i++) { if (argv[i][0] != '-') { if (Floppy_SetDiskFileName(0, argv[i], NULL)) { ConfigureParams.HardDisk.bBootFromHardDisk = FALSE; bLoadAutoSave = FALSE; } else return Opt_ShowError(OPT_ERROR, argv[i], "Not an option nor disk image"); continue; } /* WhichOption() checks also that there is an argument, * so we don't need to check that below */ switch(Opt_WhichOption(argc, argv, i)) { /* general options */ case OPT_HELP: Opt_ShowHelp(); return FALSE; case OPT_VERSION: Opt_ShowVersion(); return FALSE; case OPT_CONFIRMQUIT: ok = Opt_Bool(argv[++i], OPT_CONFIRMQUIT, &ConfigureParams.Log.bConfirmQuit); break; case OPT_FASTFORWARD: ok = Opt_Bool(argv[++i], OPT_FASTFORWARD, &ConfigureParams.System.bFastForward); break; case OPT_CONFIGFILE: i += 1; ok = Opt_StrCpy(OPT_CONFIGFILE, TRUE, sConfigFileName, argv[i], sizeof(sConfigFileName), NULL); if (ok) { Configuration_Load(NULL); bLoadAutoSave = ConfigureParams.Memory.bAutoSave; } break; /* display options */ case OPT_MONO: ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_MONO; bLoadAutoSave = FALSE; break; case OPT_MONITOR: i += 1; if (strcasecmp(argv[i], "mono") == 0) { ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_MONO; } else if (strcasecmp(argv[i], "rgb") == 0) { ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_RGB; } else if (strcasecmp(argv[i], "vga") == 0) { ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_VGA; } else if (strcasecmp(argv[i], "tv") == 0) { ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_TV; } else { return Opt_ShowError(OPT_MONITOR, argv[i], "Unknown monitor type"); } bLoadAutoSave = FALSE; break; case OPT_FULLSCREEN: ConfigureParams.Screen.bFullScreen = TRUE; break; case OPT_WINDOW: ConfigureParams.Screen.bFullScreen = FALSE; break; case OPT_ZOOM: zoom = atoi(argv[++i]); if (zoom < 1) { return Opt_ShowError(OPT_ZOOM, argv[i], "Invalid zoom value"); } if (zoom > 1) { /* TODO: only doubling supported for now */ ConfigureParams.Screen.bZoomLowRes = TRUE; } else { ConfigureParams.Screen.bZoomLowRes = FALSE; } break; case OPT_FRAMESKIPS: skips = atoi(argv[++i]); if (skips < 0) { return Opt_ShowError(OPT_FRAMESKIPS, argv[i], "Invalid frame skip value"); } else if (skips > 8) { Log_Printf(LOG_WARN, "Extravagant frame skip value %d!\n", skips); } ConfigureParams.Screen.nFrameSkips = skips; break; case OPT_BORDERS: ok = Opt_Bool(argv[++i], OPT_BORDERS, &ConfigureParams.Screen.bAllowOverscan); break; case OPT_STATUSBAR: ok = Opt_Bool(argv[++i], OPT_STATUSBAR, &ConfigureParams.Screen.bShowStatusbar); break; case OPT_DRIVE_LED: ok = Opt_Bool(argv[++i], OPT_DRIVE_LED, &ConfigureParams.Screen.bShowDriveLed); break; case OPT_SPEC512: threshold = atoi(argv[++i]); if (threshold < 0 || threshold > 512) { return Opt_ShowError(OPT_SPEC512, argv[i], "Invalid palette writes per line threshold for Spec512"); } ConfigureParams.Screen.nSpec512Threshold = threshold; break; case OPT_FORCEBPP: planes = atoi(argv[++i]); switch(planes) { case 32: case 16: case 15: case 8: break; /* supported */ case 24: planes = 32; /* We do not support 24 bpp (yet) */ break; default: return Opt_ShowError(OPT_FORCEBPP, argv[i], "Invalid bit depth"); } ConfigureParams.Screen.nForceBpp = planes; break; /* VDI options */ case OPT_VDI: ok = Opt_Bool(argv[++i], OPT_VDI, &ConfigureParams.Screen.bUseExtVdiResolutions); if (ok) { bLoadAutoSave = FALSE; } break; case OPT_VDI_PLANES: planes = atoi(argv[++i]); switch(planes) { case 1: ConfigureParams.Screen.nVdiColors = GEMCOLOR_2; break; case 2: ConfigureParams.Screen.nVdiColors = GEMCOLOR_4; break; case 4: ConfigureParams.Screen.nVdiColors = GEMCOLOR_16; break; default: return Opt_ShowError(OPT_VDI_PLANES, argv[i], "Unsupported VDI bit-depth"); } ConfigureParams.Screen.bUseExtVdiResolutions = TRUE; bLoadAutoSave = FALSE; break; case OPT_VDI_WIDTH: ConfigureParams.Screen.nVdiWidth = atoi(argv[++i]); ConfigureParams.Screen.bUseExtVdiResolutions = TRUE; bLoadAutoSave = FALSE; break; case OPT_VDI_HEIGHT: ConfigureParams.Screen.nVdiHeight = atoi(argv[++i]); ConfigureParams.Screen.bUseExtVdiResolutions = TRUE; bLoadAutoSave = FALSE; break; /* devices options */ case OPT_JOYSTICK: i++; if (strlen(argv[i]) != 1 || !Joy_SetCursorEmulation(argv[i][0] - '0')) { return Opt_ShowError(OPT_JOYSTICK, argv[i], "Invalid joystick port"); } break; case OPT_JOYSTICK0: case OPT_JOYSTICK1: case OPT_JOYSTICK2: case OPT_JOYSTICK3: case OPT_JOYSTICK4: case OPT_JOYSTICK5: port = argv[i][strlen(argv[i])-1] - '0'; assert(port >= 0 && port < JOYSTICK_COUNT); i += 1; if (strcasecmp(argv[i], "none") == 0) { ConfigureParams.Joysticks.Joy[port].nJoystickMode = JOYSTICK_DISABLED; } else if (strcasecmp(argv[i], "keys") == 0) { ConfigureParams.Joysticks.Joy[port].nJoystickMode = JOYSTICK_KEYBOARD; } else if (strcasecmp(argv[i], "real") == 0) { ConfigureParams.Joysticks.Joy[port].nJoystickMode = JOYSTICK_REALSTICK; } else { return Opt_ShowError(OPT_JOYSTICK0+port, argv[i], "Invalid joystick type"); } break; case OPT_PRINTER: i += 1; ok = Opt_StrCpy(OPT_PRINTER, FALSE, ConfigureParams.Printer.szPrintToFileName, argv[i], sizeof(ConfigureParams.Printer.szPrintToFileName), &ConfigureParams.Printer.bEnablePrinting); break; case OPT_MIDI_IN: i += 1; /* FALSE: "" can be used to disable midi input */ ok = Opt_StrCpy(OPT_MIDI_IN, FALSE, ConfigureParams.Midi.sMidiInFileName, argv[i], sizeof(ConfigureParams.Midi.sMidiInFileName), &ConfigureParams.Midi.bEnableMidi); break; case OPT_MIDI_OUT: i += 1; ok = Opt_StrCpy(OPT_MIDI_OUT, TRUE, ConfigureParams.Midi.sMidiOutFileName, argv[i], sizeof(ConfigureParams.Midi.sMidiOutFileName), &ConfigureParams.Midi.bEnableMidi); break; case OPT_RS232_IN: i += 1; ok = Opt_StrCpy(OPT_RS232_IN, TRUE, ConfigureParams.RS232.szInFileName, argv[i], sizeof(ConfigureParams.RS232.szInFileName), &ConfigureParams.RS232.bEnableRS232); break; case OPT_RS232_OUT: i += 1; ok = Opt_StrCpy(OPT_RS232_OUT, TRUE, ConfigureParams.RS232.szOutFileName, argv[i], sizeof(ConfigureParams.RS232.szOutFileName), &ConfigureParams.RS232.bEnableRS232); break; /* disk options */ case OPT_DISKA: i += 1; if (Floppy_SetDiskFileName(0, argv[i], NULL)) { ConfigureParams.HardDisk.bBootFromHardDisk = FALSE; bLoadAutoSave = FALSE; } else return Opt_ShowError(OPT_ERROR, argv[i], "Not a disk image"); break; case OPT_DISKB: i += 1; if (Floppy_SetDiskFileName(1, argv[i], NULL)) bLoadAutoSave = FALSE; else return Opt_ShowError(OPT_ERROR, argv[i], "Not a disk image"); break; case OPT_HARDDRIVE: i += 1; ok = Opt_StrCpy(OPT_HARDDRIVE, FALSE, ConfigureParams.HardDisk.szHardDiskDirectories[0], argv[i], sizeof(ConfigureParams.HardDisk.szHardDiskDirectories[0]), &ConfigureParams.HardDisk.bUseHardDiskDirectories); if (ok && ConfigureParams.HardDisk.bUseHardDiskDirectories) { ConfigureParams.HardDisk.bBootFromHardDisk = TRUE; } bLoadAutoSave = FALSE; break; case OPT_ACSIHDIMAGE: i += 1; ok = Opt_StrCpy(OPT_ACSIHDIMAGE, TRUE, ConfigureParams.HardDisk.szHardDiskImage, argv[i], sizeof(ConfigureParams.HardDisk.szHardDiskImage), &ConfigureParams.HardDisk.bUseHardDiskImage); if (ok) { bLoadAutoSave = FALSE; } break; case OPT_IDEHDIMAGE: i += 1; ok = Opt_StrCpy(OPT_IDEHDIMAGE, TRUE, ConfigureParams.HardDisk.szIdeHardDiskImage, argv[i], sizeof(ConfigureParams.HardDisk.szIdeHardDiskImage), &ConfigureParams.HardDisk.bUseIdeHardDiskImage); if (ok) { bLoadAutoSave = FALSE; } break; case OPT_SLOWFLOPPY: ok = Opt_Bool(argv[++i], OPT_SLOWFLOPPY, &ConfigureParams.DiskImage.bSlowFloppy); if (ok) { bLoadAutoSave = FALSE; } break; /* Memory options */ case OPT_MEMSIZE: memsize = atoi(argv[++i]); if (memsize < 0 || memsize > 14) { return Opt_ShowError(OPT_MEMSIZE, argv[i], "Invalid memory size"); } ConfigureParams.Memory.nMemorySize = memsize; bLoadAutoSave = FALSE; break; case OPT_TOS: i += 1; ok = Opt_StrCpy(OPT_TOS, TRUE, ConfigureParams.Rom.szTosImageFileName, argv[i], sizeof(ConfigureParams.Rom.szTosImageFileName), NULL); if (ok) { bLoadAutoSave = FALSE; } break; case OPT_CARTRIDGE: i += 1; ok = Opt_StrCpy(OPT_CARTRIDGE, TRUE, ConfigureParams.Rom.szCartridgeImageFileName, argv[i], sizeof(ConfigureParams.Rom.szCartridgeImageFileName), NULL); if (ok) { bLoadAutoSave = FALSE; } break; case OPT_MEMSTATE: i += 1; ok = Opt_StrCpy(OPT_MEMSTATE, TRUE, ConfigureParams.Memory.szMemoryCaptureFileName, argv[i], sizeof(ConfigureParams.Memory.szMemoryCaptureFileName), NULL); if (ok) { bLoadMemorySave = TRUE; bLoadAutoSave = FALSE; } break; /* CPU options */ case OPT_CPULEVEL: /* UAE core uses cpu_level variable */ ncpu = atoi(argv[++i]); if(ncpu < 0 || ncpu > 4) { return Opt_ShowError(OPT_CPULEVEL, argv[i], "Invalid CPU level"); } ConfigureParams.System.nCpuLevel = ncpu; bLoadAutoSave = FALSE; break; case OPT_CPUCLOCK: cpuclock = atoi(argv[++i]); if(cpuclock != 8 && cpuclock != 16 && cpuclock != 32) { return Opt_ShowError(OPT_CPUCLOCK, argv[i], "Invalid CPU clock"); } ConfigureParams.System.nCpuFreq = cpuclock; bLoadAutoSave = FALSE; break; case OPT_COMPATIBLE: ok = Opt_Bool(argv[++i], OPT_COMPATIBLE, &ConfigureParams.System.bCompatibleCpu); if (ok) { bLoadAutoSave = FALSE; } break; /* system options */ case OPT_MACHINE: i += 1; if (strcasecmp(argv[i], "st") == 0) { ConfigureParams.System.nMachineType = MACHINE_ST; ConfigureParams.System.nCpuLevel = 0; ConfigureParams.System.nCpuFreq = 8; } else if (strcasecmp(argv[i], "ste") == 0) { ConfigureParams.System.nMachineType = MACHINE_STE; ConfigureParams.System.nCpuLevel = 0; ConfigureParams.System.nCpuFreq = 8; } else if (strcasecmp(argv[i], "tt") == 0) { ConfigureParams.System.nMachineType = MACHINE_TT; ConfigureParams.System.nCpuLevel = 3; ConfigureParams.System.nCpuFreq = 32; } else if (strcasecmp(argv[i], "falcon") == 0) { ConfigureParams.System.nMachineType = MACHINE_FALCON; ConfigureParams.System.nCpuLevel = 3; ConfigureParams.System.nCpuFreq = 16; } else { return Opt_ShowError(OPT_MACHINE, argv[i], "Unknown machine type"); } bLoadAutoSave = FALSE; break; case OPT_BLITTER: ok = Opt_Bool(argv[++i], OPT_BLITTER, &ConfigureParams.System.bBlitter); if (ok) { bLoadAutoSave = FALSE; } break; case OPT_DSP: i += 1; if (strcasecmp(argv[i], "none") == 0) { ConfigureParams.System.nDSPType = DSP_TYPE_NONE; } else if (strcasecmp(argv[i], "dummy") == 0) { ConfigureParams.System.nDSPType = DSP_TYPE_DUMMY; } else if (strcasecmp(argv[i], "emu") == 0) { #if ENABLE_DSP_EMU ConfigureParams.System.nDSPType = DSP_TYPE_EMU; #else return Opt_ShowError(OPT_DSP, argv[i], "DSP type 'emu' support not compiled in"); #endif } else { return Opt_ShowError(OPT_DSP, argv[i], "Unknown DSP type"); } bLoadAutoSave = FALSE; break; case OPT_SOUND: i += 1; if (strcasecmp(argv[i], "off") == 0) { ConfigureParams.Sound.bEnableSound = FALSE; } else if (strcasecmp(argv[i], "low") == 0) { ConfigureParams.Sound.nPlaybackFreq = 11025; ConfigureParams.Sound.bEnableSound = TRUE; } else if (strcasecmp(argv[i], "med") == 0) { ConfigureParams.Sound.nPlaybackFreq = 22050; ConfigureParams.Sound.bEnableSound = TRUE; } else if (strcasecmp(argv[i], "hi") == 0) { ConfigureParams.Sound.nPlaybackFreq = 44100; ConfigureParams.Sound.bEnableSound = TRUE; } else { return Opt_ShowError(OPT_SOUND, argv[i], "Unsupported sound quality"); } break; case OPT_KEYMAPFILE: i += 1; ok = Opt_StrCpy(OPT_KEYMAPFILE, TRUE, ConfigureParams.Keyboard.szMappingFileName, argv[i], sizeof(ConfigureParams.Keyboard.szMappingFileName), NULL); if (ok) { ConfigureParams.Keyboard.nKeymapType = KEYMAP_LOADED; } break; /* debug options */ case OPT_DEBUG: if (bEnableDebug) { /* called at run time (e.g. from debugger) */ fprintf(stderr, "Debug mode disabled.\n"); bEnableDebug = FALSE; } else { bEnableDebug = TRUE; } break; case OPT_BIOSINTERCEPT: bBiosIntercept = TRUE; break; case OPT_TRACE: i += 1; if (Log_SetTraceOptions(argv[i]) == 0) { return Opt_ShowError(OPT_TRACE, argv[i], "Error parsing trace options (use --trace help for available list)!"); } break; case OPT_TRACEFILE: i += 1; ok = Opt_StrCpy(OPT_TRACEFILE, FALSE, ConfigureParams.Log.sTraceFileName, argv[i], sizeof(ConfigureParams.Log.sTraceFileName), NULL); break; case OPT_CONTROLSOCKET: i += 1; errstr = Control_SetSocket(argv[i]); if (errstr) { return Opt_ShowError(OPT_CONTROLSOCKET, argv[i], errstr); } break; case OPT_LOGFILE: i += 1; ok = Opt_StrCpy(OPT_LOGFILE, FALSE, ConfigureParams.Log.sLogFileName, argv[i], sizeof(ConfigureParams.Log.sLogFileName), NULL); break; case OPT_LOGLEVEL: i += 1; ConfigureParams.Log.nTextLogLevel = Log_ParseOptions(argv[i]); if (ConfigureParams.Log.nTextLogLevel == LOG_NONE) { return Opt_ShowError(OPT_LOGLEVEL, argv[i], "Unknown log level!"); } break; case OPT_ALERTLEVEL: i += 1; ConfigureParams.Log.nAlertDlgLogLevel = Log_ParseOptions(argv[i]); if (ConfigureParams.Log.nAlertDlgLogLevel == LOG_NONE) { return Opt_ShowError(OPT_ALERTLEVEL, argv[i], "Unknown alert level!"); } break; case OPT_RUNVBLS: nRunVBLs = atol(argv[++i]); break; case OPT_ERROR: /* unknown option or missing option parameter */ return FALSE; default: return Opt_ShowError(OPT_ERROR, argv[i], "Internal Hatari error, unhandled option"); } if (!ok) { /* Opt_Bool() or Opt_StrCpy() failed */ return FALSE; } } return TRUE; }