Annotation of previous/src/options.c, revision 1.1.1.5

1.1       root        1: /*
                      2:   Hatari - options.c
                      3: 
                      4:   This file is distributed under the GNU Public License, version 2 or at
                      5:   your option any later version. Read the file gpl.txt for details.
                      6: 
                      7:   Functions for showing and parsing all of Hatari's command line options.
                      8:   
                      9:   To add a new option:
                     10:   - Add option ID to the enum
                     11:   - Add the option information to HatariOptions[]
                     12:   - Add required actions for that ID to switch in Opt_ParseParameters()
                     13: */
                     14: const char Options_fileid[] = "Hatari options.c : " __DATE__ " " __TIME__;
                     15: 
                     16: #include <ctype.h>
                     17: #include <stdio.h>
                     18: #include <stdlib.h>
                     19: #include <string.h>
                     20: #include <assert.h>
                     21: #include <SDL.h>
                     22: 
                     23: #include "main.h"
                     24: #include "options.h"
                     25: #include "configuration.h"
                     26: #include "control.h"
                     27: #include "debugui.h"
                     28: #include "file.h"
                     29: #include "screen.h"
                     30: #include "video.h"
                     31: #include "log.h"
1.1.1.2   root       32: #include "paths.h"
1.1       root       33: 
                     34: #include "hatari-glue.h"
                     35: 
                     36: static bool bNoSDLParachute;
                     37: 
                     38: /*  List of supported options. */
                     39: enum {
                     40:        OPT_HEADER,     /* options section header */
                     41:        OPT_HELP,               /* general options */
                     42:        OPT_VERSION,
                     43:        OPT_CONFIRMQUIT,
                     44:        OPT_CONFIGFILE,
1.1.1.2   root       45:        OPT_KEYMAPFILE,
1.1       root       46:        OPT_MONITOR,
                     47:        OPT_FULLSCREEN,
                     48:        OPT_WINDOW,
                     49:        OPT_GRAB,
                     50:        OPT_STATUSBAR,
                     51:        OPT_DRIVE_LED,
                     52:        OPT_PRINTER,
                     53:        OPT_WRITEPROT_HD,
                     54:        OPT_MEMSIZE,            /* memory options */
                     55:        OPT_MEMSTATE,
                     56:        OPT_CPULEVEL,           /* CPU options */
                     57:        OPT_CPUCLOCK,
                     58:        OPT_COMPATIBLE,
1.1.1.4   root       59: 
1.1.1.2   root       60:        OPT_CPU_CYCLE_EXACT,    /* WinUAE CPU/FPU/bus options */
                     61:        OPT_CPU_ADDR24,
                     62:        OPT_FPU_TYPE,
                     63:        OPT_FPU_COMPATIBLE,
                     64:        OPT_MMU,
1.1.1.4   root       65: 
1.1       root       66:        OPT_MACHINE,            /* system options */
1.1.1.5 ! root       67:        OPT_REALTIME,
1.1       root       68:        OPT_DSP,
1.1.1.2   root       69:        OPT_MICROPHONE,
1.1       root       70:        OPT_SOUND,
                     71:        OPT_SOUNDBUFFERSIZE,
1.1.1.2   root       72:        OPT_RTC,
1.1       root       73:        OPT_DEBUG,              /* debug options */
                     74:        OPT_TRACE,
                     75:        OPT_TRACEFILE,
                     76:        OPT_PARSE,
                     77:        OPT_SAVECONFIG,
                     78:        OPT_PARACHUTE,
                     79:        OPT_CONTROLSOCKET,
                     80:        OPT_LOGFILE,
                     81:        OPT_LOGLEVEL,
                     82:        OPT_ALERTLEVEL,
                     83:        OPT_ERROR,
                     84:        OPT_CONTINUE
                     85: };
                     86: 
                     87: typedef struct {
                     88:        unsigned int id;        /* option ID */
                     89:        const char *chr;        /* short option */
                     90:        const char *str;        /* long option */
                     91:        const char *arg;        /* type name for argument, if any */
                     92:        const char *desc;       /* option description */
                     93: } opt_t;
                     94: 
                     95: /* it's easier to edit these if they are kept in the same order as the enums */
                     96: static const opt_t HatariOptions[] = {
                     97:        
                     98:        { OPT_HEADER, NULL, NULL, NULL, "General" },
                     99:        { OPT_HELP,      "-h", "--help",
                    100:          NULL, "Print this help text and exit" },
                    101:        { OPT_VERSION,   "-v", "--version",
                    102:          NULL, "Print version number and exit" },
                    103:        { OPT_CONFIRMQUIT, NULL, "--confirm-quit",
                    104:          "<bool>", "Whether Hatari confirms quit" },
                    105:        { OPT_CONFIGFILE, "-c", "--configfile",
                    106:          "<file>", "Use <file> instead of the default hatari config file" },
1.1.1.2   root      107:        { OPT_KEYMAPFILE, "-k", "--keymap",
                    108:          "<file>", "Read (additional) keyboard mappings from <file>" },
1.1.1.5 ! root      109:     
1.1.1.2   root      110:        { OPT_HEADER, NULL, NULL, NULL, "Common display" },
1.1       root      111:        { OPT_MONITOR,      NULL, "--monitor",
                    112:          "<x>", "Select monitor type (x = mono/rgb/vga/tv)" },
                    113:        { OPT_FULLSCREEN,"-f", "--fullscreen",
                    114:          NULL, "Start emulator in fullscreen mode" },
                    115:        { OPT_WINDOW,    "-w", "--window",
                    116:          NULL, "Start emulator in window mode" },
                    117:        { OPT_GRAB, NULL, "--grab",
                    118:          NULL, "Grab mouse (also) in window mode" },
                    119:        { OPT_STATUSBAR, NULL, "--statusbar",
                    120:          "<bool>", "Show statusbar (floppy leds etc)" },
                    121:        { OPT_DRIVE_LED,   NULL, "--drive-led",
                    122:          "<bool>", "Show overlay drive led when statusbar isn't shown" },
                    123: 
                    124:        { OPT_HEADER, NULL, NULL, NULL, "Devices" },
                    125:        { OPT_PRINTER,   NULL, "--printer",
                    126:          "<file>", "Enable printer support and write data to <file>" },
                    127:        
                    128:        { OPT_HEADER, NULL, NULL, NULL, "Disk" },
                    129:        { OPT_WRITEPROT_HD, NULL, "--protect-hd",
                    130:          "<x>", "Write protect harddrive <dir> contents (on/off/auto)" },
                    131:        
                    132:        { OPT_HEADER, NULL, NULL, NULL, "Memory" },
                    133:        { OPT_MEMSIZE,   "-s", "--memsize",
                    134:          "<x>", "ST RAM size (x = size in MiB from 0 to 14, 0 = 512KiB)" },
                    135:        { OPT_MEMSTATE,   NULL, "--memstate",
                    136:          "<file>", "Load memory snap-shot <file>" },
                    137:        
                    138:        { OPT_HEADER, NULL, NULL, NULL, "CPU" },
                    139:        { OPT_CPULEVEL,  NULL, "--cpulevel",
                    140:          "<x>", "Set the CPU type (x => 680x0) (EmuTOS/TOS 2.06 only!)" },
                    141:        { OPT_CPUCLOCK,  NULL, "--cpuclock",
                    142:          "<x>", "Set the CPU clock (x = 8/16/32)" },
                    143:        { OPT_COMPATIBLE, NULL, "--compatible",
                    144:          "<bool>", "Use a more compatible (but slower) 68000 CPU mode" },
1.1.1.2   root      145: 
                    146:        { OPT_HEADER, NULL, NULL, NULL, "WinUAE CPU/FPU/bus" },
                    147:        { OPT_CPU_CYCLE_EXACT, NULL, "--cpu-exact",
                    148:          "<bool>", "Use cycle exact CPU emulation" },
                    149:        { OPT_CPU_ADDR24, NULL, "--addr24",
                    150:          "<bool>", "Use 24-bit instead of 32-bit addressing mode" },
                    151:        { OPT_FPU_TYPE, NULL, "--fpu-type",
                    152:          "<x>", "FPU type (x=none/68881/68882/internal)" },
                    153:        { OPT_FPU_COMPATIBLE, NULL, "--fpu-compatible",
                    154:          "<bool>", "Use more compatible, but slower FPU emulation" },
                    155:        { OPT_MMU, NULL, "--mmu",
                    156:          "<bool>", "Use MMU emulation" },
                    157: 
1.1       root      158:        { OPT_HEADER, NULL, NULL, NULL, "Misc system" },
1.1.1.5 ! root      159:        { OPT_REALTIME,   NULL, "--realtime",
        !           160:          "<bool>", "Use host realtime sources" },
1.1       root      161:        { OPT_DSP,       NULL, "--dsp",
1.1.1.5 ! root      162:          "<x>", "DSP emulation (x = none/dummy/emu)" },
1.1.1.2   root      163:        { OPT_MICROPHONE,   NULL, "--mic",
1.1.1.5 ! root      164:          "<bool>", "Enable/disable microphone" },
1.1       root      165:        { OPT_SOUND,   NULL, "--sound",
                    166:          "<x>", "Sound frequency (x=off/6000-50066, off=fastest)" },
                    167:        { OPT_SOUNDBUFFERSIZE,   NULL, "--sound-buffer-size",
1.1.1.2   root      168:          "<x>", "Sound buffer size for SDL in ms (x=0/10-100, 0=default)" },
                    169:        { OPT_RTC,    NULL, "--rtc",
                    170:          "<bool>", "Enable real-time clock" },
                    171: 
1.1       root      172:        { OPT_HEADER, NULL, NULL, NULL, "Debug" },
                    173:        { OPT_DEBUG,     "-D", "--debug",
                    174:          NULL, "Toggle whether CPU exceptions invoke debugger" },
                    175:        { OPT_TRACE,   NULL, "--trace",
                    176:          "<trace1,...>", "Activate emulation tracing, see '--trace help'" },
                    177:        { OPT_TRACEFILE, NULL, "--trace-file",
                    178:          "<file>", "Save trace output to <file> (default=stderr)" },
                    179:        { OPT_PARSE, NULL, "--parse",
                    180:          "<file>", "Parse/execute debugger commands from <file>" },
                    181:        { OPT_SAVECONFIG, NULL, "--saveconfig",
                    182:          NULL, "Save current Hatari configuration and exit" },
                    183:        { OPT_PARACHUTE, NULL, "--no-parachute",
                    184:          NULL, "Disable SDL parachute to get Hatari core dumps" },
                    185: #if HAVE_UNIX_DOMAIN_SOCKETS
                    186:        { OPT_CONTROLSOCKET, NULL, "--control-socket",
                    187:          "<file>", "Hatari reads options from given socket at run-time" },
                    188: #endif
                    189:        { OPT_LOGFILE, NULL, "--log-file",
                    190:          "<file>", "Save log output to <file> (default=stderr)" },
                    191:        { OPT_LOGLEVEL, NULL, "--log-level",
                    192:          "<x>", "Log output level (x=debug/todo/info/warn/error/fatal)" },
                    193:        { OPT_ALERTLEVEL, NULL, "--alert-level",
                    194:          "<x>", "Show dialog for log messages above given level" },
                    195: 
                    196:        { OPT_ERROR, NULL, NULL, NULL, NULL }
                    197: };
                    198: 
                    199: 
                    200: /**
                    201:  * Show version string and license.
                    202:  */
                    203: static void Opt_ShowVersion(void)
                    204: {
                    205:        printf("\n" PROG_NAME
1.1.1.5 ! root      206:               " - the NeXT emulator.\n\n");
        !           207:        printf(PROG_NAME " is free software licensed under the GNU General"
1.1       root      208:               " Public License.\n\n");
                    209: }
                    210: 
                    211: 
                    212: /**
                    213:  * Calculate option + value len
                    214:  */
                    215: static unsigned int Opt_OptionLen(const opt_t *opt)
                    216: {
                    217:        unsigned int len;
                    218:        len = strlen(opt->str);
                    219:        if (opt->arg)
                    220:        {
                    221:                len += strlen(opt->arg);
                    222:                len += 1;
                    223:                /* with arg, short options go to another line */
                    224:        }
                    225:        else
                    226:        {
                    227:                if (opt->chr)
                    228:                {
                    229:                        /* ' or -c' */
                    230:                        len += 6;
                    231:                }
                    232:        }
                    233:        return len;
                    234: }
                    235: 
                    236: 
                    237: /**
                    238:  * Show single option
                    239:  */
                    240: static void Opt_ShowOption(const opt_t *opt, unsigned int maxlen)
                    241: {
                    242:        char buf[64];
                    243:        if (!maxlen)
                    244:        {
                    245:                maxlen = Opt_OptionLen(opt);
                    246:        }
                    247:        assert(maxlen < sizeof(buf));
                    248:        if (opt->arg)
                    249:        {
                    250:                sprintf(buf, "%s %s", opt->str, opt->arg);
                    251:                printf("  %-*s %s\n", maxlen, buf, opt->desc);
                    252:                if (opt->chr)
                    253:                {
                    254:                        printf("    or %s %s\n", opt->chr, opt->arg);
                    255:                }
                    256:        }
                    257:        else
                    258:        {
                    259:                if (opt->chr)
                    260:                {
                    261:                        sprintf(buf, "%s or %s", opt->str, opt->chr);
                    262:                        printf("  %-*s %s\n", maxlen, buf, opt->desc);
                    263:                }
                    264:                else
                    265:                {
                    266:                        printf("  %-*s %s\n", maxlen, opt->str, opt->desc);
                    267:                }
                    268:        }
                    269: }
                    270: 
                    271: /**
                    272:  * Show options for section starting from 'start_opt',
                    273:  * return next option after this section.
                    274:  */
                    275: static const opt_t *Opt_ShowHelpSection(const opt_t *start_opt)
                    276: {
                    277:        const opt_t *opt, *last;
                    278:        unsigned int len, maxlen = 0;
                    279:        const char *previous = NULL;
                    280: 
                    281:        /* find longest option name and check option IDs */
                    282:        for (opt = start_opt; opt->id != OPT_HEADER && opt->id != OPT_ERROR; opt++)
                    283:        {
                    284:                len = Opt_OptionLen(opt);
                    285:                if (len > maxlen)
                    286:                {
                    287:                        maxlen = len;
                    288:                }
                    289:        }
                    290:        last = opt;
                    291:        
                    292:        /* output all options */
                    293:        for (opt = start_opt; opt != last; opt++)
                    294:        {
                    295:                if (previous != opt->str)
                    296:                {
                    297:                        Opt_ShowOption(opt, maxlen);
                    298:                }
                    299:                previous = opt->str;
                    300:        }
                    301:        return last;
                    302: }
                    303: 
                    304: 
                    305: /**
                    306:  * Show help text.
                    307:  */
                    308: static void Opt_ShowHelp(void)
                    309: {
                    310:        const opt_t *opt = HatariOptions;
                    311: 
                    312:        Opt_ShowVersion();
1.1.1.5 ! root      313:        printf("Usage:\n previous [options] [directory|disk image|Atari program]\n");
1.1       root      314: 
                    315:        while(opt->id != OPT_ERROR)
                    316:        {
                    317:                if (opt->id == OPT_HEADER)
                    318:                {
                    319:                        assert(opt->desc);
                    320:                        printf("\n%s options:\n", opt->desc);
                    321:                        opt++;
                    322:                }
                    323:                opt = Opt_ShowHelpSection(opt);
                    324:        }
                    325:        printf("\nSpecial option values:\n");
                    326:        printf("<bool>\tDisable by using 'n', 'no', 'off', 'false', or '0'\n");
                    327:        printf("\tEnable by using 'y', 'yes', 'on', 'true' or '1'\n");
                    328:        printf("<file>\tDevices accept also special 'stdout' and 'stderr' file names\n");
                    329:        printf("\t(if you use stdout for midi or printer, set log to stderr).\n");
                    330:        printf("\tSetting the file to 'none', disables given device or disk\n");
                    331: }
                    332: 
                    333: 
                    334: /**
                    335:  * Show Hatari version and usage.
                    336:  * If 'error' given, show that error message.
                    337:  * If 'optid' != OPT_ERROR, tells for which option the error is,
                    338:  * otherwise 'value' is show as the option user gave.
                    339:  * Return false if error string was given, otherwise true
                    340:  */
                    341: static bool Opt_ShowError(unsigned int optid, const char *value, const char *error)
                    342: {
                    343:        const opt_t *opt;
                    344: 
                    345:        Opt_ShowVersion();
                    346:        printf("Usage:\n hatari [options] [disk image name]\n\n"
                    347:               "Try option \"-h\" or \"--help\" to display more information.\n");
                    348: 
                    349:        if (error)
                    350:        {
                    351:                if (optid == OPT_ERROR)
                    352:                {
                    353:                        fprintf(stderr, "\nError: %s (%s)\n", error, value);
                    354:                }
                    355:                else
                    356:                {
                    357:                        for (opt = HatariOptions; opt->id != OPT_ERROR; opt++)
                    358:                        {
                    359:                                if (optid == opt->id)
                    360:                                        break;
                    361:                        }
                    362:                        if (value != NULL)
                    363:                        {
                    364:                                fprintf(stderr,
                    365:                                        "\nError while parsing argument \"%s\" for option \"%s\":\n"
                    366:                                        "  %s\n", value, opt->str, error);
                    367:                        }
                    368:                        else
                    369:                        {
                    370:                                fprintf(stderr, "\nError (%s): %s\n", opt->str, error);
                    371:                        }
                    372:                        fprintf(stderr, "\nOption usage:\n");
                    373:                        Opt_ShowOption(opt, 0);
                    374:                }
                    375:                return false;
                    376:        }
                    377:        return true;
                    378: }
                    379: 
                    380: 
                    381: /**
                    382:  * If 'conf' given, set it:
                    383:  * - true if given option 'arg' is y/yes/on/true/1
                    384:  * - false if given option 'arg' is n/no/off/false/0
                    385:  * Return false for any other value, otherwise true
                    386:  */
                    387: static bool Opt_Bool(const char *arg, int optid, bool *conf)
                    388: {
                    389:        const char *enablers[] = { "y", "yes", "on", "true", "1", NULL };
                    390:        const char *disablers[] = { "n", "no", "off", "false", "0", NULL };
                    391:        const char **bool_str, *orig = arg;
                    392:        char *input, *str;
                    393: 
                    394:        input = strdup(arg);
                    395:        str = input;
                    396:        while (*str)
                    397:        {
                    398:                *str++ = tolower(*arg++);
                    399:        }
                    400:        for (bool_str = enablers; *bool_str; bool_str++)
                    401:        {
                    402:                if (strcmp(input, *bool_str) == 0)
                    403:                {
                    404:                        free(input);
                    405:                        if (conf)
                    406:                        {
                    407:                                *conf = true;
                    408:                        }
                    409:                        return true;
                    410:                }
                    411:        }
                    412:        for (bool_str = disablers; *bool_str; bool_str++)
                    413:        {
                    414:                if (strcmp(input, *bool_str) == 0)
                    415:                {
                    416:                        free(input);
                    417:                        if (conf)
                    418:                        {
                    419:                                *conf = false;
                    420:                        }
                    421:                        return true;
                    422:                }
                    423:        }
                    424:        free(input);
                    425:        return Opt_ShowError(optid, orig, "Not a <bool> value");
                    426: }
                    427: 
                    428: 
                    429: /**
                    430:  * checks str argument agaist options of type "--option<digit>".
                    431:  * If match is found, returns ID for that, otherwise OPT_CONTINUE
                    432:  * and OPT_ERROR for errors.
                    433:  */
                    434: static int Opt_CheckBracketValue(const opt_t *opt, const char *str)
                    435: {
                    436:        const char *bracket, *optstr;
                    437:        size_t offset;
                    438:        int digit, i;
                    439: 
                    440:        if (!opt->str)
                    441:        {
                    442:                return OPT_CONTINUE;
                    443:        }
                    444:        bracket = strchr(opt->str, '<');
                    445:        if (!bracket)
                    446:        {
                    447:                return OPT_CONTINUE;
                    448:        }
                    449:        offset = bracket - opt->str;
                    450:        if (strncmp(opt->str, str, offset) != 0)
                    451:        {
                    452:                return OPT_CONTINUE;
                    453:        }
                    454:        digit = str[offset] - '0';
                    455:        if (digit < 0 || digit > 9)
                    456:        {
                    457:                return OPT_CONTINUE;
                    458:        }
                    459:        optstr = opt->str;
                    460:        for (i = 0; opt->str == optstr; opt++, i++)
                    461:        {
                    462:                if (i == digit)
                    463:                {
                    464:                        return opt->id;
                    465:                }
                    466:        }
                    467:        /* fprintf(stderr, "opt: %s (%d), str: %s (%d), digit: %d\n",
                    468:                opt->str, offset+1, str, strlen(str), digit);
                    469:         */
                    470:        return OPT_ERROR;
                    471: }
                    472: 
                    473: 
                    474: /**
                    475:  * matches string under given index in the argv against all Hatari
                    476:  * short and long options. If match is found, returns ID for that,
                    477:  * otherwise shows help and returns OPT_ERROR.
                    478:  * 
                    479:  * Checks also that if option is supposed to have argument,
                    480:  * whether there's one.
                    481:  */
1.1.1.2   root      482: static int Opt_WhichOption(int argc, const char * const argv[], int idx)
1.1       root      483: {
                    484:        const opt_t *opt;
                    485:        const char *str = argv[idx];
                    486:        int id;
                    487: 
                    488:        for (opt = HatariOptions; opt->id != OPT_ERROR; opt++)
                    489:        {       
                    490:                /* exact option name matches? */
                    491:                if (!((opt->str && !strcmp(str, opt->str)) ||
                    492:                      (opt->chr && !strcmp(str, opt->chr))))
                    493:                {
                    494:                        /* no, maybe name<digit> matches? */
                    495:                        id = Opt_CheckBracketValue(opt, str);
                    496:                        if (id == OPT_CONTINUE)
                    497:                        {
                    498:                                continue;
                    499:                        }
                    500:                        if (id == OPT_ERROR)
                    501:                        {
                    502:                                break;
                    503:                        }
                    504:                }
                    505:                /* matched, check args */
                    506:                if (opt->arg)
                    507:                {
                    508:                        if (idx+1 >= argc)
                    509:                        {
                    510:                                Opt_ShowError(opt->id, NULL, "Missing argument");
                    511:                                return OPT_ERROR;
                    512:                        }
                    513:                        /* early check for bools */
                    514:                        if (strcmp(opt->arg, "<bool>") == 0)
                    515:                        {
                    516:                                if (!Opt_Bool(argv[idx+1], opt->id, NULL))
                    517:                                {
                    518:                                        return OPT_ERROR;
                    519:                                }
                    520:                        }
                    521:                }
                    522:                return opt->id;
                    523:        }
                    524:        Opt_ShowError(OPT_ERROR, argv[idx], "Unrecognized option");
                    525:        return OPT_ERROR;
                    526: }
                    527: 
                    528: 
                    529: /**
                    530:  * If 'checkexits' is true, assume 'src' is a file and check whether it
                    531:  * exists before copying 'src' to 'dst'. Otherwise just copy option src
                    532:  * string to dst.
                    533:  * If a pointer to (bool) 'option' is given, set that option to true.
                    534:  * - However, if src is "none", leave dst unmodified & set option to false.
                    535:  *   ("none" is used to disable options related to file arguments)
                    536:  * Return false if there were errors, otherwise true
                    537:  */
                    538: static bool Opt_StrCpy(int optid, bool checkexist, char *dst, const char *src, size_t dstlen, bool *option)
                    539: {
                    540:        if (option)
                    541:        {
                    542:                *option = false;
                    543:                if(strcasecmp(src, "none") == 0)
                    544:                {
                    545:                        return true;
                    546:                }
                    547:        }
                    548:        if (strlen(src) >= dstlen)
                    549:        {
                    550:                return Opt_ShowError(optid, src, "File name too long!");
                    551:        }
                    552:        if (checkexist && !File_Exists(src))
                    553:        {
                    554:                return Opt_ShowError(optid, src, "Given file doesn't exist (or has wrong file permissions)!");
                    555:        }
                    556:        if (option)
                    557:        {
                    558:                *option = true;
                    559:        }
                    560:        strcpy(dst, src);
                    561:        return true;
                    562: }
                    563: 
                    564: 
                    565: /**
                    566:  * Return SDL_INIT_NOPARACHUTE flag if user requested SDL parachute
                    567:  * to be disabled to get proper Hatari core dumps.  By default returns
                    568:  * zero so that SDL parachute will be used to restore video mode on
                    569:  * unclean Hatari termination.
                    570:  */
                    571: Uint32 Opt_GetNoParachuteFlag(void)
                    572: {
                    573:        if (bNoSDLParachute) {
                    574:                return SDL_INIT_NOPARACHUTE;
                    575:        }
                    576:        return 0;
                    577: }
                    578: 
                    579: 
                    580: /**
1.1.1.2   root      581:  * Handle last (non-option) argument.  It can be a path or filename.
                    582:  * Filename can be a disk image or Atari program.
                    583:  * Return false if it's none of these.
                    584:  */
                    585: static bool Opt_HandleArgument(const char *path)
                    586: {
                    587:        char *dir = NULL;
                    588:        Uint8 test[2];
                    589:        FILE *fp;
                    590: 
                    591:        /* Atari program? */
                    592:        if (File_Exists(path) && (fp = fopen(path, "rb"))) {
                    593: 
                    594:                /* file starts with GEMDOS magic? */
                    595:                if (fread(test, 1, 2, fp) == 2 &&
                    596:                    test[0] == 0x60 && test[1] == 0x1A) {
                    597: 
                    598:                        const char *prgname = strrchr(path, PATHSEP);
                    599:                        if (prgname) {
                    600:                                dir = strdup(path);
                    601:                                dir[prgname-path] = '\0';
                    602:                                prgname++;
                    603:                        } else {
                    604:                                dir = strdup(Paths_GetWorkingDir());
                    605:                                prgname = path;
                    606:                        }
                    607:                        /* after above, dir should point to valid dir,
                    608:                         * then make sure that given program from that
                    609:                         * dir will be started.
                    610:                         */
                    611: //                     TOS_AutoStart(prgname);
                    612:                }
                    613:                fclose(fp);
                    614:        }
                    615:        if (dir) {
                    616:                path = dir;
                    617:        }
                    618: 
                    619:        /* GEMDOS HDD directory (as argument, or for the Atari program)? */
                    620:        if (File_DirExists(path)) {
1.1.1.3   root      621: //             if (Opt_StrCpy(OPT_HARDDRIVE, false, ConfigureParams.HardDisk.szHardDiskDirectories[0],
                    622: //                            path, sizeof(ConfigureParams.HardDisk.szHardDiskDirectories[0]),
                    623: //                            &ConfigureParams.HardDisk.bUseHardDiskDirectories)
                    624: //                 && ConfigureParams.HardDisk.bUseHardDiskDirectories)
1.1.1.2   root      625:                {
1.1.1.4   root      626: //                     ConfigureParams.SCSI.bBootFromHardDisk = true;
1.1.1.2   root      627:                }
                    628:                if (dir) {
                    629:                        free(dir);
                    630:                }
                    631:                return true;
                    632:        } else {
                    633:                if (dir) {
                    634:                        /* if dir is set, it should be valid... */
                    635:                        Log_Printf(LOG_ERROR, "Given atari program path '%s' doesn't exist (anymore?)!\n", dir);
                    636:                        free(dir);
                    637:                        exit(1);
                    638:                }
                    639:        }
                    640: 
                    641:        return Opt_ShowError(OPT_ERROR, path, "Not a disk image, Atari program or directory");
                    642: }
                    643: 
                    644: /**
1.1       root      645:  * parse all Hatari command line options and set Hatari state accordingly.
                    646:  * Returns true if everything was OK, false otherwise.
                    647:  */
1.1.1.2   root      648: bool Opt_ParseParameters(int argc, const char * const argv[])
1.1       root      649: {
1.1.1.5 ! root      650:        int ncpu, cpuclock, memsize, freq, temp;
1.1       root      651:        const char *errstr;
                    652:        int i, ok = true;
                    653: 
                    654:        for(i = 1; i < argc; i++)
                    655:        {
1.1.1.2   root      656:                /* last argument can be a non-option */
                    657:                if (argv[i][0] != '-' && i+1 == argc)
                    658:                        return Opt_HandleArgument(argv[i]);
1.1       root      659:     
                    660:                /* WhichOption() checks also that there is an argument,
                    661:                 * so we don't need to check that below
                    662:                 */
                    663:                switch(Opt_WhichOption(argc, argv, i))
                    664:                {
                    665:                
                    666:                        /* general options */
                    667:                case OPT_HELP:
                    668:                        Opt_ShowHelp();
                    669:                        return false;
                    670:                        
                    671:                case OPT_VERSION:
                    672:                        Opt_ShowVersion();
                    673:                        return false;
                    674: 
                    675:                case OPT_CONFIRMQUIT:
                    676:                        ok = Opt_Bool(argv[++i], OPT_CONFIRMQUIT, &ConfigureParams.Log.bConfirmQuit);
                    677:                        break;
                    678:                        
                    679:                case OPT_CONFIGFILE:
                    680:                        i += 1;
                    681:                        /* true -> file needs to exist */
                    682:                        ok = Opt_StrCpy(OPT_CONFIGFILE, true, sConfigFileName,
                    683:                                        argv[i], sizeof(sConfigFileName), NULL);
                    684:                        if (ok)
                    685:                        {
                    686:                                Configuration_Load(NULL);
                    687:                        }
                    688:                        break;
                    689:                
1.1.1.2   root      690:                        /* common display options */
1.1       root      691: 
                    692:                case OPT_MONITOR:
                    693:                        i += 1;
                    694:                        if (strcasecmp(argv[i], "mono") == 0)
                    695:                        {
1.1.1.4   root      696: //                             ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_MONO;
1.1       root      697:                        }
                    698:                        else if (strcasecmp(argv[i], "rgb") == 0)
                    699:                        {
1.1.1.4   root      700: //                             ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_RGB;
1.1       root      701:                        }
                    702:                        else if (strcasecmp(argv[i], "vga") == 0)
                    703:                        {
1.1.1.4   root      704: //                             ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_VGA;
1.1       root      705:                        }
                    706:                        else if (strcasecmp(argv[i], "tv") == 0)
                    707:                        {
1.1.1.4   root      708: //                             ConfigureParams.Screen.nMonitorType = MONITOR_TYPE_TV;
1.1       root      709:                        }
                    710:                        else
                    711:                        {
                    712:                                return Opt_ShowError(OPT_MONITOR, argv[i], "Unknown monitor type");
                    713:                        }
                    714:                        break;
                    715:                        
                    716:                case OPT_FULLSCREEN:
                    717:                        ConfigureParams.Screen.bFullScreen = true;
                    718:                        break;
                    719:                        
                    720:                case OPT_WINDOW:
                    721:                        ConfigureParams.Screen.bFullScreen = false;
                    722:                        break;
                    723: 
                    724:                case OPT_GRAB:
                    725:                        bGrabMouse = true;
                    726:                        break;
1.1.1.5 ! root      727:                                                
1.1       root      728:                case OPT_STATUSBAR:
                    729:                        ok = Opt_Bool(argv[++i], OPT_STATUSBAR, &ConfigureParams.Screen.bShowStatusbar);
                    730:                        break;
                    731:                        
                    732:                case OPT_DRIVE_LED:
                    733:                        ok = Opt_Bool(argv[++i], OPT_DRIVE_LED, &ConfigureParams.Screen.bShowDriveLed);
                    734:                        break;
1.1.1.5 ! root      735:                                                                        
1.1.1.2   root      736:                case OPT_PRINTER:
                    737:                        i += 1;
                    738:                        /* "none" can be used to disable printer */
                    739:                        ok = Opt_StrCpy(OPT_PRINTER, false, ConfigureParams.Printer.szPrintToFileName,
                    740:                                        argv[i], sizeof(ConfigureParams.Printer.szPrintToFileName),
1.1.1.4   root      741:                                        &ConfigureParams.Printer.bPrinterConnected);
1.1.1.2   root      742:                        break;
                    743:                        
                    744:                        /* disk options */
                    745: 
                    746:                case OPT_WRITEPROT_HD:
                    747:                        i += 1;
1.1.1.5 ! root      748:                        if (strcasecmp(argv[i], "off") == 0)
        !           749:                                ConfigureParams.SCSI.nWriteProtection = WRITEPROT_OFF;
        !           750:                        else if (strcasecmp(argv[i], "on") == 0)
        !           751:                                ConfigureParams.SCSI.nWriteProtection = WRITEPROT_ON;
        !           752:                        else if (strcasecmp(argv[i], "auto") == 0)
        !           753:                                ConfigureParams.SCSI.nWriteProtection = WRITEPROT_AUTO;
        !           754:                        else
1.1.1.2   root      755:                                return Opt_ShowError(OPT_WRITEPROT_HD, argv[i], "Unknown option value");
                    756:                        break;
1.1       root      757:                        
                    758:                        /* Memory options */
                    759:                case OPT_MEMSIZE:
                    760:                        memsize = atoi(argv[++i]);
                    761:                        if (memsize < 0 || memsize > 14)
                    762:                        {
                    763:                                return Opt_ShowError(OPT_MEMSIZE, argv[i], "Invalid memory size");
                    764:                        }
1.1.1.3   root      765: //                     ConfigureParams.Memory.nMemorySize = memsize;
1.1       root      766:                        break;
1.1.1.5 ! root      767:                        
1.1       root      768:                        /* CPU options */
                    769:                case OPT_CPULEVEL:
                    770:                        /* UAE core uses cpu_level variable */
                    771:                        ncpu = atoi(argv[++i]);
                    772:                        if(ncpu < 0 || ncpu > 4)
                    773:                        {
                    774:                                return Opt_ShowError(OPT_CPULEVEL, argv[i], "Invalid CPU level");
                    775:                        }
                    776:                        ConfigureParams.System.nCpuLevel = ncpu;
                    777:                        break;
                    778:                        
                    779:                case OPT_CPUCLOCK:
                    780:                        cpuclock = atoi(argv[++i]);
                    781:                        if(cpuclock != 8 && cpuclock != 16 && cpuclock != 32)
                    782:                        {
                    783:                                return Opt_ShowError(OPT_CPUCLOCK, argv[i], "Invalid CPU clock");
                    784:                        }
                    785:                        ConfigureParams.System.nCpuFreq = cpuclock;
                    786:                        break;
                    787:                        
                    788:                case OPT_COMPATIBLE:
                    789:                        ok = Opt_Bool(argv[++i], OPT_COMPATIBLE, &ConfigureParams.System.bCompatibleCpu);
                    790:                        break;
                    791: 
                    792:                        /* system options */
                    793:                case OPT_MACHINE:
                    794:                        i += 1;
                    795:                        if (strcasecmp(argv[i], "st") == 0)
                    796:                        {
                    797:                                ConfigureParams.System.nCpuLevel = 0;
                    798:                                ConfigureParams.System.nCpuFreq = 8;
                    799:                        }
                    800:                        else if (strcasecmp(argv[i], "ste") == 0)
                    801:                        {
                    802:                                ConfigureParams.System.nCpuLevel = 0;
                    803:                                ConfigureParams.System.nCpuFreq = 8;
                    804:                        }
                    805:                        else if (strcasecmp(argv[i], "tt") == 0)
                    806:                        {
                    807:                                ConfigureParams.System.nCpuLevel = 3;
                    808:                                ConfigureParams.System.nCpuFreq = 32;
                    809:                        }
                    810:                        else if (strcasecmp(argv[i], "falcon") == 0)
                    811:                        {
1.1.1.2   root      812: #if ENABLE_DSP_EMU
                    813:                ConfigureParams.System.nDSPType = DSP_TYPE_EMU;
                    814: #endif
1.1       root      815:                                ConfigureParams.System.nCpuLevel = 3;
                    816:                                ConfigureParams.System.nCpuFreq = 16;
                    817:                        }
                    818:                        else
                    819:                        {
                    820:                                return Opt_ShowError(OPT_MACHINE, argv[i], "Unknown machine type");
                    821:                        }
                    822:                        break;
                    823:                        
1.1.1.5 ! root      824:                case OPT_REALTIME:
        !           825:                        ok = Opt_Bool(argv[++i], OPT_REALTIME, &ConfigureParams.System.bRealtime);
        !           826:                        break;
        !           827:                                                
1.1.1.2   root      828:                case OPT_RTC:
                    829:                        ok = Opt_Bool(argv[++i], OPT_RTC, &ConfigureParams.System.bRealTimeClock);
                    830:                        break;                  
                    831: 
                    832:                case OPT_DSP:
                    833:                        i += 1;
                    834:                        if (strcasecmp(argv[i], "none") == 0)
                    835:                        {
                    836:                                ConfigureParams.System.nDSPType = DSP_TYPE_NONE;
                    837:                        }
                    838:                        else if (strcasecmp(argv[i], "dummy") == 0)
                    839:                        {
                    840:                                ConfigureParams.System.nDSPType = DSP_TYPE_DUMMY;
                    841:                        }
                    842:                        else if (strcasecmp(argv[i], "emu") == 0)
                    843:                        {
                    844: #if ENABLE_DSP_EMU
                    845:                                ConfigureParams.System.nDSPType = DSP_TYPE_EMU;
                    846: #else
                    847:                                return Opt_ShowError(OPT_DSP, argv[i], "DSP type 'emu' support not compiled in");
                    848: #endif
                    849:                        }
                    850:                        else
                    851:                        {
                    852:                                return Opt_ShowError(OPT_DSP, argv[i], "Unknown DSP type");
                    853:                        }
                    854:                        break;
                    855: 
                    856:                case OPT_FPU_TYPE:
                    857:                        i += 1;
                    858:                        if (strcasecmp(argv[i], "none") == 0)
                    859:                        {
                    860:                                ConfigureParams.System.n_FPUType = FPU_NONE;
                    861:                        }
                    862:                        else if (strcasecmp(argv[i], "68881") == 0)
                    863:                        {
                    864:                                ConfigureParams.System.n_FPUType = FPU_68881;
                    865:                        }
                    866:                        else if (strcasecmp(argv[i], "68882") == 0)
                    867:                        {
                    868:                                ConfigureParams.System.n_FPUType = FPU_68882;
                    869:                        }
                    870:                        else if (strcasecmp(argv[i], "internal") == 0)
                    871:                        {
                    872:                                ConfigureParams.System.n_FPUType = FPU_CPU;
                    873:                        }
                    874:                        else
                    875:                        {
                    876:                                return Opt_ShowError(OPT_FPU_TYPE, argv[i], "Unknown FPU type");
                    877:                        }
                    878:                        break;
                    879: 
                    880:                case OPT_FPU_COMPATIBLE:
                    881:                        ok = Opt_Bool(argv[++i], OPT_FPU_COMPATIBLE, &ConfigureParams.System.bCompatibleFPU);
                    882:                        break;                  
                    883: 
                    884:                case OPT_MMU:
                    885:                        ok = Opt_Bool(argv[++i], OPT_MMU, &ConfigureParams.System.bMMU);
                    886:                        break;
1.1       root      887: 
1.1.1.2   root      888:                case OPT_SOUND:
                    889:                        i += 1;
                    890:                        if (strcasecmp(argv[i], "off") == 0)
                    891:                        {
                    892:                                ConfigureParams.Sound.bEnableSound = false;
                    893:                        }
                    894:                        else
                    895:                        {
                    896:                                freq = atoi(argv[i]);
1.1.1.5 ! root      897:                                if (freq != 44100)
1.1.1.2   root      898:                                {
1.1.1.5 ! root      899:                                        return Opt_ShowError(OPT_SOUND, argv[i], "Unsupported sound frequency, only 44100 supported");
1.1.1.2   root      900:                                }
                    901:                                ConfigureParams.Sound.bEnableSound = true;
                    902:                        }
                    903:                        break;
1.1       root      904: 
                    905:                case OPT_SOUNDBUFFERSIZE:
                    906:                        i += 1;
                    907:                        temp = atoi(argv[i]);
                    908:                        if ( temp == 0 )                        /* use default setting for SDL */
                    909:                                ;
                    910:                        else if (temp < 10 || temp > 100)
                    911:                                {
                    912:                                        return Opt_ShowError(OPT_SOUNDBUFFERSIZE, argv[i], "Unsupported sound buffer size");
                    913:                                }
1.1.1.4   root      914: //                     ConfigureParams.Sound.SdlAudioBufferSize = temp;
1.1       root      915:                        break;
1.1.1.2   root      916:                        
                    917:                case OPT_MICROPHONE:
                    918:                        ok = Opt_Bool(argv[++i], OPT_MICROPHONE, &ConfigureParams.Sound.bEnableMicrophone);
                    919:                        break;                  
1.1       root      920: 
                    921:                case OPT_KEYMAPFILE:
                    922:                        i += 1;
                    923:                        ok = Opt_StrCpy(OPT_KEYMAPFILE, true, ConfigureParams.Keyboard.szMappingFileName,
                    924:                                        argv[i], sizeof(ConfigureParams.Keyboard.szMappingFileName),
                    925:                                        NULL);
                    926:                        if (ok)
                    927:                        {
                    928:                                ConfigureParams.Keyboard.nKeymapType = KEYMAP_LOADED;
                    929:                        }
                    930:                        break;
                    931:                        
                    932:                        /* debug options */
                    933:                case OPT_DEBUG:
                    934:                        if (bExceptionDebugging)
                    935:                        {
                    936:                                fprintf(stderr, "Exception debugging disabled.\n");
                    937:                                bExceptionDebugging = false;
                    938:                        }
                    939:                        else
                    940:                        {
                    941:                                fprintf(stderr, "Exception debugging enabled.\n");
                    942:                                bExceptionDebugging = true;
                    943:                        }
                    944:                        break;
                    945: 
                    946:                case OPT_PARACHUTE:
                    947:                        bNoSDLParachute = true;
                    948:                        break;
                    949: 
                    950:                        
                    951:                case OPT_TRACE:
                    952:                        i += 1;
                    953:                        errstr = Log_SetTraceOptions(argv[i]);
                    954:                        if (errstr)
                    955:                        {
                    956:                                if (!errstr[0]) {
                    957:                                        /* silent parsing termination */
                    958:                                        return false;
                    959:                                }
                    960:                                return Opt_ShowError(OPT_TRACE, argv[i], errstr);
                    961:                        }
                    962:                        break;
                    963: 
                    964:                case OPT_TRACEFILE:
                    965:                        i += 1;
                    966:                        ok = Opt_StrCpy(OPT_TRACEFILE, false, ConfigureParams.Log.sTraceFileName,
                    967:                                        argv[i], sizeof(ConfigureParams.Log.sTraceFileName),
                    968:                                        NULL);
                    969:                        break;
                    970: 
                    971:                case OPT_CONTROLSOCKET:
                    972:                        i += 1;
                    973:                        errstr = Control_SetSocket(argv[i]);
                    974:                        if (errstr)
                    975:                        {
                    976:                                return Opt_ShowError(OPT_CONTROLSOCKET, argv[i], errstr);
                    977:                        }
                    978:                        break;
                    979: 
                    980:                case OPT_LOGFILE:
                    981:                        i += 1;
                    982:                        ok = Opt_StrCpy(OPT_LOGFILE, false, ConfigureParams.Log.sLogFileName,
                    983:                                        argv[i], sizeof(ConfigureParams.Log.sLogFileName),
                    984:                                        NULL);
                    985:                        break;
                    986: 
                    987:                case OPT_PARSE:
                    988:                        i += 1;
                    989:                        ok = DebugUI_SetParseFile(argv[i]);
                    990:                        break;
                    991: 
                    992:                case OPT_SAVECONFIG:
                    993:                        /* Hatari-UI needs Hatari config to start */
                    994:                        Configuration_Save();
                    995:                        exit(0);
                    996:                        break;
                    997: 
                    998:                case OPT_LOGLEVEL:
                    999:                        i += 1;
                   1000:                        ConfigureParams.Log.nTextLogLevel = Log_ParseOptions(argv[i]);
                   1001:                        if (ConfigureParams.Log.nTextLogLevel == LOG_NONE)
                   1002:                        {
                   1003:                                return Opt_ShowError(OPT_LOGLEVEL, argv[i], "Unknown log level!");
                   1004:                        }
                   1005:                        break;
                   1006: 
                   1007:                case OPT_ALERTLEVEL:
                   1008:                        i += 1;
                   1009:                        ConfigureParams.Log.nAlertDlgLogLevel = Log_ParseOptions(argv[i]);
                   1010:                        if (ConfigureParams.Log.nAlertDlgLogLevel == LOG_NONE)
                   1011:                        {
                   1012:                                return Opt_ShowError(OPT_ALERTLEVEL, argv[i], "Unknown alert level!");
                   1013:                        }
                   1014:                        break;
                   1015:                       
                   1016:                case OPT_ERROR:
                   1017:                        /* unknown option or missing option parameter */
                   1018:                        return false;
                   1019: 
                   1020:                default:
                   1021:                        return Opt_ShowError(OPT_ERROR, argv[i], "Internal Hatari error, unhandled option");
                   1022:                }
                   1023:                if (!ok)
                   1024:                {
                   1025:                        /* Opt_Bool() or Opt_StrCpy() failed */
                   1026:                        return false;
                   1027:                }
                   1028:        }
                   1029: 
                   1030:        return true;
                   1031: }
                   1032: 
                   1033: /**
                   1034:  * Readline match callback for option name completion.
                   1035:  * STATE = 0 -> different text from previous one.
                   1036:  * Return next match or NULL if no matches.
                   1037:  */
                   1038: char *Opt_MatchOption(const char *text, int state)
                   1039: {
                   1040:        static int i, len;
                   1041:        const char *name;
                   1042:        
                   1043:        if (!state) {
                   1044:                /* first match */
                   1045:                len = strlen(text);
                   1046:                i = 0;
                   1047:        }
                   1048:        /* next match */
                   1049:        while (i < ARRAYSIZE(HatariOptions)) {
                   1050:                name = HatariOptions[i++].str;
                   1051:                if (name && strncasecmp(name, text, len) == 0)
                   1052:                        return (strdup(name));
                   1053:        }
                   1054:        return NULL;
                   1055: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.