|
|
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 corresponding place in HatariOptions[] ! 12: - Add required actions for that ID to switch in Opt_ParseParameters() ! 13: */ ! 14: const char Main_rcsid[] = "Hatari $Id: options.c,v 1.6 2006/08/09 08:10:56 eerot Exp $"; ! 15: ! 16: #include <stdio.h> ! 17: #include <stdlib.h> ! 18: #include <string.h> ! 19: #include <assert.h> ! 20: ! 21: #include "main.h" ! 22: #include "options.h" ! 23: #include "configuration.h" ! 24: #include "file.h" ! 25: #include "screen.h" ! 26: #include "video.h" ! 27: #include "vdi.h" ! 28: #include "joy.h" ! 29: ! 30: #include "uae-cpu/hatari-glue.h" ! 31: ! 32: ! 33: /* List of supported options. */ ! 34: enum { ! 35: OPT_HELP, ! 36: OPT_VERSION, ! 37: OPT_MONO, ! 38: OPT_FULLSCREEN, ! 39: OPT_WINDOW, ! 40: OPT_FRAMESKIP, ! 41: OPT_DEBUG, ! 42: OPT_JOYSTICK, ! 43: OPT_NOSOUND, ! 44: OPT_PRINTER, ! 45: OPT_MIDI, ! 46: OPT_RS232, ! 47: OPT_HDIMAGE, ! 48: OPT_HARDDRIVE, ! 49: OPT_TOS, ! 50: OPT_CARTRIDGE, ! 51: OPT_CPULEVEL, ! 52: OPT_COMPATIBLE, ! 53: OPT_BLITTER, ! 54: OPT_VDI, ! 55: OPT_MEMSIZE, ! 56: OPT_CONFIGFILE, ! 57: OPT_KEYMAPFILE, ! 58: OPT_SLOWFDC, ! 59: OPT_MACHINE, ! 60: OPT_NONE, ! 61: }; ! 62: ! 63: typedef struct { ! 64: unsigned int id; /* option ID */ ! 65: const char *chr; /* short option */ ! 66: const char *str; /* long option */ ! 67: const char *arg; /* name for argument, if any */ ! 68: const char *desc; /* option description */ ! 69: } opt_t; ! 70: ! 71: /* these have(!) to be in the same order as the enums */ ! 72: static const opt_t HatariOptions[] = { ! 73: { OPT_HELP, "-h", "--help", ! 74: NULL, "Print this help text and exit" }, ! 75: { OPT_VERSION, "-v", "--version", ! 76: NULL, "Print version number & help and exit" }, ! 77: { OPT_MONO, "-m", "--mono", ! 78: NULL, "Start in monochrome mode instead of color" }, ! 79: { OPT_FULLSCREEN,"-f", "--fullscreen", ! 80: NULL, "Start emulator in fullscreen mode" }, ! 81: { OPT_WINDOW, "-w", "--window", ! 82: NULL, "Start emulator in window mode" }, ! 83: { OPT_FRAMESKIP, NULL, "--frameskip", ! 84: NULL, "Skip every second frame (speeds up emulation!)" }, ! 85: { OPT_DEBUG, "-D", "--debug", ! 86: NULL, "Allow debug interface" }, ! 87: { OPT_JOYSTICK, "-j", "--joystick", ! 88: "<port>", "Emulate joystick in <port> 0 or 1 with cursor keys" }, ! 89: { OPT_NOSOUND, NULL, "--nosound", ! 90: NULL, "Disable sound (faster!)" }, ! 91: { OPT_PRINTER, NULL, "--printer", ! 92: NULL, "Enable printer support (experimental)" }, ! 93: { OPT_MIDI, NULL, "--midi", ! 94: "<file>", "Enable midi support and write midi data to <file>" }, ! 95: { OPT_RS232, NULL, "--rs232", ! 96: "<file>", "Use <file> as the serial port device" }, ! 97: { OPT_HDIMAGE, NULL, "--hdimage", ! 98: "<file>", "Emulate an ST harddrive with an image <file>" }, ! 99: { OPT_HARDDRIVE, "-d", "--harddrive", ! 100: "<dir>", "Emulate an ST harddrive (<dir> = root directory)" }, ! 101: { OPT_TOS, "-t", "--tos", ! 102: "<file>", "Use TOS image <file>" }, ! 103: { OPT_CARTRIDGE, NULL, "--cartridge", ! 104: "<file>", "Use ROM cartridge image <file>" }, ! 105: { OPT_CPULEVEL, NULL, "--cpulevel", ! 106: "<x>", "Set the CPU type (x => 680x0) (TOS 2.06 only!)" }, ! 107: { OPT_COMPATIBLE,NULL, "--compatible", ! 108: NULL, "Use a more compatible (but slower) 68000 CPU mode" }, ! 109: { OPT_BLITTER, NULL, "--blitter", ! 110: NULL, "Enable blitter emulation (unstable!)" }, ! 111: { OPT_VDI, NULL, "--vdi", ! 112: NULL, "Use extended VDI resolution" }, ! 113: { OPT_MEMSIZE, "-s", "--memsize", ! 114: "<x>", "ST RAM size. x = size in MiB from 0 to 14, 0 for 512KiB" }, ! 115: { OPT_CONFIGFILE,"-c", "--configfile", ! 116: "<file>", "Use <file> instead of the ~/.hatari.cfg config file" }, ! 117: { OPT_KEYMAPFILE,"-k", "--keymap", ! 118: "<file>", "Read (additional) keyboard mappings from <file>" }, ! 119: { OPT_SLOWFDC, NULL, "--slowfdc", ! 120: NULL, "Slow down FDC emulation (very experimental!)" }, ! 121: { OPT_MACHINE, NULL, "--machine", ! 122: "<x>", "Select machine type (x = st/ste/tt)" }, ! 123: { OPT_NONE, NULL, NULL, NULL, NULL } ! 124: }; ! 125: ! 126: /* Show Hatari options and exit(). ! 127: * If 'error' given, show that error message. ! 128: * If 'option' != OPT_NONE, tells for which option the error is, ! 129: * otherwise 'value' is show as the option user gave. ! 130: */ ! 131: static void Opt_ShowExit(int option, const char *value, const char *error) ! 132: { ! 133: unsigned int i, len, maxlen; ! 134: char buf[64]; ! 135: const opt_t *opt; ! 136: ! 137: printf("This is %s.\n", PROG_NAME); ! 138: printf("This program is free software licensed under the GNU GPL.\n\n"); ! 139: printf("Usage:\n hatari [options] [disk image name]\n" ! 140: "Where options are:\n"); ! 141: if (option == OPT_VERSION) { ! 142: exit(0); ! 143: } ! 144: ! 145: /* find largest option name and check option IDs */ ! 146: i = maxlen = 0; ! 147: for (opt = HatariOptions; opt->id != OPT_NONE; opt++) { ! 148: assert(opt->id == i++); ! 149: len = strlen(opt->str); ! 150: if (opt->arg) { ! 151: len += strlen(opt->arg); ! 152: len += 1; ! 153: /* with arg, short options go to another line */ ! 154: } else { ! 155: if (opt->chr) { ! 156: /* ' or -c' */ ! 157: len += 6; ! 158: } ! 159: } ! 160: if (len > maxlen) { ! 161: maxlen = len; ! 162: } ! 163: } ! 164: assert(maxlen < sizeof(buf)); ! 165: ! 166: /* output all options */ ! 167: for (opt = HatariOptions; opt->id != OPT_NONE; opt++) { ! 168: if (opt->arg) { ! 169: sprintf(buf, "%s %s", opt->str, opt->arg); ! 170: printf(" %-*s %s\n", maxlen, buf, opt->desc); ! 171: if (opt->chr) { ! 172: printf(" or %s %s\n", opt->chr, opt->arg); ! 173: } ! 174: } else { ! 175: if (opt->chr) { ! 176: sprintf(buf, "%s or %s", opt->str, opt->chr); ! 177: printf(" %-*s %s\n", maxlen, buf, opt->desc); ! 178: } else { ! 179: printf(" %-*s %s\n", maxlen, opt->str, opt->desc); ! 180: } ! 181: } ! 182: } ! 183: if (error) { ! 184: if (option != OPT_NONE) { ! 185: fprintf(stderr, "\nError (%s): %s\n", HatariOptions[option].str, error); ! 186: } else { ! 187: fprintf(stderr, "\nError: %s (%s)\n", error, value); ! 188: } ! 189: exit(1); ! 190: } ! 191: exit(0); ! 192: } ! 193: ! 194: /* ! 195: * matches string under given index in the argv against all Hatari ! 196: * short and long options. If match is found, returns ID for that, ! 197: * otherwise shows help. ! 198: * ! 199: * Checks also that if option is supposed to have argument, ! 200: * whether there's one. ! 201: */ ! 202: static int Opt_WhichOption(int argc, char *argv[], int idx) ! 203: { ! 204: const opt_t *opt; ! 205: const char *str = argv[idx]; ! 206: ! 207: for (opt = HatariOptions; opt->id != OPT_NONE; opt++) { ! 208: ! 209: if ((!strcmp(str, opt->str)) || ! 210: (opt->chr && !strcmp(str, opt->chr))) { ! 211: ! 212: if (opt->arg && idx+1 >= argc) { ! 213: Opt_ShowExit(opt->id, NULL, "Missing argument"); ! 214: } ! 215: return opt->id; ! 216: } ! 217: } ! 218: Opt_ShowExit(OPT_NONE, argv[idx], "Unrecognized option"); ! 219: return OPT_NONE; ! 220: } ! 221: ! 222: /*-----------------------------------------------------------------------*/ ! 223: /* ! 224: Check for any passed parameters, return boot disk ! 225: */ ! 226: void Opt_ParseParameters(int argc, char *argv[], ! 227: char *bootdisk, size_t bootlen) ! 228: { ! 229: int i; ! 230: ! 231: for(i = 1; i < argc; i++) { ! 232: ! 233: if (argv[i][0] != '-') { ! 234: /* Possible passed disk image filename */ ! 235: if (argv[i][0] && File_Exists(argv[i]) && ! 236: strlen(argv[i]) < bootlen) { ! 237: strcpy(bootdisk, argv[i]); ! 238: File_MakeAbsoluteName(bootdisk); ! 239: } else { ! 240: Opt_ShowExit(OPT_NONE, argv[i], "Not an option nor disk image"); ! 241: } ! 242: continue; ! 243: } ! 244: ! 245: /* WhichOption() checks also that there is an argument, ! 246: * so we don't need to check that below ! 247: */ ! 248: switch(Opt_WhichOption(argc, argv, i)) { ! 249: ! 250: case OPT_HELP: ! 251: Opt_ShowExit(OPT_HELP, NULL, NULL); ! 252: break; ! 253: ! 254: case OPT_VERSION: ! 255: Opt_ShowExit(OPT_VERSION, NULL, NULL); ! 256: break; ! 257: ! 258: case OPT_MONO: ! 259: bUseHighRes = TRUE; ! 260: ConfigureParams.Screen.bUseHighRes = TRUE; ! 261: STRes = PrevSTRes = ST_HIGH_RES; ! 262: break; ! 263: ! 264: case OPT_FULLSCREEN: ! 265: ConfigureParams.Screen.bFullScreen = TRUE; ! 266: break; ! 267: ! 268: case OPT_WINDOW: ! 269: ConfigureParams.Screen.bFullScreen = FALSE; ! 270: break; ! 271: ! 272: case OPT_JOYSTICK: ! 273: i++; ! 274: if (!Joy_SetCursorEmulation(argv[i][0] - '0')) { ! 275: /* TODO: replace this with an error message ! 276: * for the next version. For now assume ! 277: * that -j was used without an argument ! 278: * which earlier defaulted to port 1 ! 279: */ ! 280: fprintf(stderr, "WARNING: assuming -j <port> argument is missing and defaulting to port 1.\n"); ! 281: Joy_SetCursorEmulation(1); ! 282: i--; ! 283: } ! 284: break; ! 285: ! 286: case OPT_NOSOUND: ! 287: ConfigureParams.Sound.bEnableSound = FALSE; ! 288: break; ! 289: ! 290: case OPT_FRAMESKIP: ! 291: ConfigureParams.Screen.bFrameSkip = TRUE; ! 292: break; ! 293: ! 294: case OPT_DEBUG: ! 295: bEnableDebug = TRUE; ! 296: break; ! 297: ! 298: case OPT_PRINTER: ! 299: /* FIXME: add more commandline configuration for printing */ ! 300: ConfigureParams.Printer.bEnablePrinting = TRUE; ! 301: break; ! 302: ! 303: case OPT_MIDI: ! 304: i += 1; ! 305: if (strlen(argv[i]) < sizeof(ConfigureParams.Midi.szMidiOutFileName)) { ! 306: ConfigureParams.Midi.bEnableMidi = TRUE; ! 307: strcpy(ConfigureParams.Midi.szMidiOutFileName, argv[i]); ! 308: } else { ! 309: Opt_ShowExit(OPT_NONE, argv[i], "Midi file name too long!\n"); ! 310: } ! 311: break; ! 312: ! 313: case OPT_RS232: ! 314: i += 1; ! 315: if (strlen(argv[i]) < sizeof(ConfigureParams.RS232.szOutFileName)) { ! 316: ConfigureParams.RS232.bEnableRS232 = TRUE; ! 317: strcpy(ConfigureParams.RS232.szOutFileName, argv[i]); ! 318: strcpy(ConfigureParams.RS232.szInFileName, argv[i]); ! 319: } else { ! 320: Opt_ShowExit(OPT_NONE, argv[i], "RS232 file name too long!\n"); ! 321: } ! 322: break; ! 323: ! 324: case OPT_HDIMAGE: ! 325: i += 1; ! 326: if (!File_Exists(argv[i])) { ! 327: Opt_ShowExit(OPT_NONE, argv[i], "Given HD image file doesn't exist!\n"); ! 328: } ! 329: if (strlen(argv[i]) < sizeof(ConfigureParams.HardDisk.szHardDiskImage)) { ! 330: ConfigureParams.HardDisk.bUseHardDiskImage = TRUE; ! 331: strcpy(ConfigureParams.HardDisk.szHardDiskImage, argv[i]); ! 332: } else { ! 333: Opt_ShowExit(OPT_NONE, argv[i], "HD image file name too long!\n"); ! 334: } ! 335: break; ! 336: ! 337: case OPT_HARDDRIVE: ! 338: i += 1; ! 339: if(strlen(argv[i]) < sizeof(ConfigureParams.HardDisk.szHardDiskDirectories[0])) { ! 340: ConfigureParams.HardDisk.bUseHardDiskDirectories = TRUE; ! 341: ConfigureParams.HardDisk.bBootFromHardDisk = TRUE; ! 342: strcpy(ConfigureParams.HardDisk.szHardDiskDirectories[0], argv[i]); ! 343: } else { ! 344: Opt_ShowExit(OPT_NONE, argv[i], "HD directory name too long!\n"); ! 345: } ! 346: break; ! 347: ! 348: case OPT_TOS: ! 349: i += 1; ! 350: if (!File_Exists(argv[i])) { ! 351: Opt_ShowExit(OPT_NONE, argv[i], "Given TOS image file doesn't exist!\n"); ! 352: } ! 353: if (strlen(argv[i]) < sizeof(ConfigureParams.Rom.szTosImageFileName)) { ! 354: strcpy(ConfigureParams.Rom.szTosImageFileName, argv[i]); ! 355: } else { ! 356: Opt_ShowExit(OPT_NONE, argv[i], "TOS image file name too long!\n"); ! 357: } ! 358: break; ! 359: ! 360: case OPT_CARTRIDGE: ! 361: i += 1; ! 362: if (!File_Exists(argv[i])) { ! 363: Opt_ShowExit(OPT_NONE, argv[i], "Given Cartridge image file doesn't exist!\n"); ! 364: } ! 365: if (strlen(argv[i]) < sizeof(ConfigureParams.Rom.szCartridgeImageFileName)) { ! 366: strcpy(ConfigureParams.Rom.szCartridgeImageFileName, argv[i]); ! 367: } else { ! 368: Opt_ShowExit(OPT_NONE, argv[i], "Cartridge image file name too long!\n"); ! 369: } ! 370: break; ! 371: ! 372: case OPT_CPULEVEL: ! 373: /* UAE core uses cpu_level variable */ ! 374: cpu_level = atoi(argv[++i]); ! 375: if(cpu_level < 0 || cpu_level > 4) { ! 376: fprintf(stderr, "CPU level %d is invalid (valid: 0-4), set to 0.\n", cpu_level); ! 377: cpu_level = 0; ! 378: } ! 379: ConfigureParams.System.nCpuLevel = cpu_level; ! 380: break; ! 381: ! 382: case OPT_COMPATIBLE: ! 383: cpu_compatible = TRUE; ! 384: ConfigureParams.System.bCompatibleCpu = TRUE; ! 385: break; ! 386: ! 387: case OPT_BLITTER: ! 388: ConfigureParams.System.bBlitter = TRUE; ! 389: break; ! 390: ! 391: case OPT_VDI: ! 392: bUseVDIRes = ConfigureParams.Screen.bUseExtVdiResolutions = TRUE; ! 393: break; ! 394: ! 395: case OPT_SLOWFDC: ! 396: ConfigureParams.System.bSlowFDC = TRUE; ! 397: break; ! 398: ! 399: case OPT_MEMSIZE: ! 400: ConfigureParams.Memory.nMemorySize = atoi(argv[++i]); ! 401: if (ConfigureParams.Memory.nMemorySize < 0 || ! 402: ConfigureParams.Memory.nMemorySize > 14) { ! 403: fprintf(stderr, "Memory size %d is invalid (valid: 0-14MB), set to 1.\n", ! 404: ConfigureParams.Memory.nMemorySize); ! 405: ConfigureParams.Memory.nMemorySize = 1; ! 406: } ! 407: break; ! 408: ! 409: case OPT_CONFIGFILE: ! 410: i += 1; ! 411: if (!File_Exists(argv[i])) { ! 412: Opt_ShowExit(OPT_NONE, argv[i], "Given config file doesn't exist!\n"); ! 413: } ! 414: if (strlen(argv[i]) < sizeof(sConfigFileName)) { ! 415: strcpy(sConfigFileName, argv[i]); ! 416: Configuration_Load(NULL); ! 417: } else { ! 418: Opt_ShowExit(OPT_NONE, argv[i], "Config file name too long!\n"); ! 419: } ! 420: break; ! 421: ! 422: case OPT_KEYMAPFILE: ! 423: i += 1; ! 424: if (File_Exists(argv[i])) { ! 425: strcpy(ConfigureParams.Keyboard.szMappingFileName, argv[i]); ! 426: ConfigureParams.Keyboard.nKeymapType = KEYMAP_LOADED; ! 427: } else { ! 428: Opt_ShowExit(OPT_NONE, argv[i], "Given keymap file doesn't exist!\n"); ! 429: } ! 430: break; ! 431: ! 432: case OPT_MACHINE: ! 433: i += 1; ! 434: if (strcasecmp(argv[i], "st") == 0) { ! 435: ConfigureParams.System.nMachineType = MACHINE_ST; ! 436: } else if (strcasecmp(argv[i], "ste") == 0) { ! 437: ConfigureParams.System.nMachineType = MACHINE_STE; ! 438: } else if (strcasecmp(argv[i], "tt") == 0) { ! 439: ConfigureParams.System.nMachineType = MACHINE_TT; ! 440: ConfigureParams.System.nCpuLevel = cpu_level = 3; ! 441: ConfigureParams.System.nCpuFreq = 32; ! 442: } else { ! 443: Opt_ShowExit(OPT_NONE, argv[i], "Unknown machine type"); ! 444: } ! 445: break; ! 446: ! 447: default: ! 448: Opt_ShowExit(OPT_NONE, argv[i], "Program didn't handle documented option"); ! 449: } ! 450: } ! 451: ! 452: Configuration_WorkOnDetails(FALSE); ! 453: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.