\\\\!\", *s) != NULL)\n {\n *r = '\\\\';\n ++r;\n }\n\n *r = *s;\n ++r;\n }\n\n // Enclosing quotes.\n *r = '\"';\n ++r;\n *r = '\\0';\n\n return result;\n}\n\n// Open a native error box with a message using zenity\n\nstatic int ZenityErrorBox(char *message)\n{\n int result;\n char *escaped_message;\n char *errorboxpath;\n static size_t errorboxpath_size;\n\n if (!ZenityAvailable())\n {\n return 0;\n }\n\n escaped_message = EscapeShellString(message);\n\n errorboxpath_size = strlen(ZENITY_BINARY) + strlen(escaped_message) + 19;\n errorboxpath = malloc(errorboxpath_size);\n M_snprintf(errorboxpath, errorboxpath_size, \"%s --error --text=%s\",\n ZENITY_BINARY, escaped_message);\n\n result = system(errorboxpath);\n\n free(errorboxpath);\n free(escaped_message);\n\n return result;\n}\n\n#endif /* !defined(_WIN32) \u0026\u0026 !defined(__MACOSX__) \u0026\u0026 !defined(__DJGPP__) */\n\n\n//\n// I_Error\n//\n\nstatic boolean already_quitting = false;\n\nvoid I_Error (char *error, ...)\n{\n char msgbuf[512];\n va_list argptr;\n atexit_listentry_t *entry;\n boolean exit_gui_popup;\n\n if (already_quitting)\n {\n fprintf(stderr, \"Warning: recursive call to I_Error detected.\\n\");\n#if ORIGCODE\n exit(-1);\n#endif\n }\n else\n {\n already_quitting = true;\n }\n\n // Message first.\n va_start(argptr, error);\n //fprintf(stderr, \"\\nError: \");\n vfprintf(stderr, error, argptr);\n fprintf(stderr, \"\\n\\n\");\n va_end(argptr);\n fflush(stderr);\n\n // Write a copy of the message into buffer.\n va_start(argptr, error);\n memset(msgbuf, 0, sizeof(msgbuf));\n M_vsnprintf(msgbuf, sizeof(msgbuf), error, argptr);\n va_end(argptr);\n\n extern void gba_fatal(const char *message);\n gba_fatal(msgbuf);\n\n // Shutdown. Here might be other errors.\n\n entry = exit_funcs;\n\n while (entry != NULL)\n {\n if (entry-\u003erun_on_error)\n {\n entry-\u003efunc();\n }\n\n entry = entry-\u003enext;\n }\n\n exit_gui_popup = !M_ParmExists(\"-nogui\");\n\n // Pop up a GUI dialog box to show the error message, if the\n // game was not run from the console (and the user will\n // therefore be unable to otherwise see the message).\n if (exit_gui_popup \u0026\u0026 !I_ConsoleStdout())\n#ifdef _WIN32\n {\n wchar_t wmsgbuf[512];\n\n MultiByteToWideChar(CP_ACP, 0,\n msgbuf, strlen(msgbuf) + 1,\n wmsgbuf, sizeof(wmsgbuf));\n\n MessageBoxW(NULL, wmsgbuf, L\"\", MB_OK);\n }\n#elif defined(__MACOSX__)\n {\n CFStringRef message;\n\tint i;\n\n\t// The CoreFoundation message box wraps text lines, so replace\n\t// newline characters with spaces so that multiline messages\n\t// are continuous.\n\n\tfor (i = 0; msgbuf[i] != '\\0'; ++i)\n {\n if (msgbuf[i] == '\\n')\n {\n msgbuf[i] = ' ';\n }\n }\n\n message = CFStringCreateWithCString(NULL, msgbuf,\n kCFStringEncodingUTF8);\n\n CFUserNotificationDisplayNotice(0,\n kCFUserNotificationCautionAlertLevel,\n NULL,\n NULL,\n NULL,\n CFSTR(PACKAGE_STRING),\n message,\n NULL);\n }\n#elif defined(__DJGPP__)\n {\n printf(\"%s\\n\", msgbuf);\n exit(-1);\n }\n\n#else\n {\n ZenityErrorBox(msgbuf);\n }\n#endif\n\n // abort();\n#if ORIGCODE\n SDL_Quit();\n\n exit(-1);\n#else\n exit(-1);\n#endif\n}\n\n//\n// Read Access Violation emulation.\n//\n// From PrBoom+, by entryway.\n//\n\n// C:\\\u003edebug\n// -d 0:0\n//\n// DOS 6.22:\n// 0000:0000 (57 92 19 00) F4 06 70 00-(16 00)\n// DOS 7.1:\n// 0000:0000 (9E 0F C9 00) 65 04 70 00-(16 00)\n// Win98:\n// 0000:0000 (9E 0F C9 00) 65 04 70 00-(16 00)\n// DOSBox under XP:\n// 0000:0000 (00 00 00 F1) ?? ?? ?? 00-(07 00)\n\n#define DOS_MEM_DUMP_SIZE 10\n\nstatic const unsigned char mem_dump_dos622[DOS_MEM_DUMP_SIZE] = {\n 0x57, 0x92, 0x19, 0x00, 0xF4, 0x06, 0x70, 0x00, 0x16, 0x00};\nstatic const unsigned char mem_dump_win98[DOS_MEM_DUMP_SIZE] = {\n 0x9E, 0x0F, 0xC9, 0x00, 0x65, 0x04, 0x70, 0x00, 0x16, 0x00};\nstatic const unsigned char mem_dump_dosbox[DOS_MEM_DUMP_SIZE] = {\n 0x00, 0x00, 0x00, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00};\nstatic unsigned char mem_dump_custom[DOS_MEM_DUMP_SIZE];\n\nstatic const unsigned char *dos_mem_dump = mem_dump_dos622;\n\nboolean I_GetMemoryValue(unsigned int offset, void *value, int size)\n{\n static boolean firsttime = true;\n\n if (firsttime)\n {\n int p, i, val;\n\n firsttime = false;\n i = 0;\n\n //!\n // @category compat\n // @arg \u003cversion\u003e\n //\n // Specify DOS version to emulate for NULL pointer dereference\n // emulation. Supported versions are: dos622, dos71, dosbox.\n // The default is to emulate DOS 7.1 (Windows 98).\n //\n\n p = M_CheckParmWithArgs(\"-setmem\", 1);\n\n if (p \u003e 0)\n {\n if (!strcasecmp(myargv[p + 1], \"dos622\"))\n {\n dos_mem_dump = mem_dump_dos622;\n }\n if (!strcasecmp(myargv[p + 1], \"dos71\"))\n {\n dos_mem_dump = mem_dump_win98;\n }\n else if (!strcasecmp(myargv[p + 1], \"dosbox\"))\n {\n dos_mem_dump = mem_dump_dosbox;\n }\n else\n {\n for (i = 0; i \u003c DOS_MEM_DUMP_SIZE; ++i)\n {\n ++p;\n\n if (p \u003e= myargc || myargv[p][0] == '-')\n {\n break;\n }\n\n M_StrToInt(myargv[p], \u0026val);\n mem_dump_custom[i++] = (unsigned char) val;\n }\n\n dos_mem_dump = mem_dump_custom;\n }\n }\n }\n\n switch (size)\n {\n case 1:\n *((unsigned char *) value) = dos_mem_dump[offset];\n return true;\n case 2:\n *((unsigned short *) value) = dos_mem_dump[offset]\n | (dos_mem_dump[offset + 1] \u003c\u003c 8);\n return true;\n case 4:\n *((unsigned int *) value) = dos_mem_dump[offset]\n | (dos_mem_dump[offset + 1] \u003c\u003c 8)\n | (dos_mem_dump[offset + 2] \u003c\u003c 16)\n | (dos_mem_dump[offset + 3] \u003c\u003c 24);\n return true;\n }\n\n return false;\n}\n\n","content_mimetype":"text/x-c","created_at":"2026-11-05T18:49:31.566Z"}; window.SSR_PACKAGE_BUILDS = []; window.SSR_RELATED_PACKAGES = [{"package_id":"1bb71080-c9d9-4806-8dad-9546e8b9913b","creator_account_id":"03854e77-22c2-44a0-9cfc-2d4ed6741105","latest_package_release_id":"92d10956-aa95-4eba-8e98-42e66c16f463","last_built_release_id":"92d10956-aa95-4eba-8e98-42e66c16f463","latest_package_release_fs_sha":"md5-73c7349eef4667e7cbc7beecb7e35036","latest_pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=92d10956-aa95-4eba-8e98-42e66c16f463\u0026file_path=dist%2Findex%2Fpcb.svg","latest_sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=92d10956-aa95-4eba-8e98-42e66c16f463\u0026file_path=dist%2Findex%2Fschematic.svg","latest_cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=92d10956-aa95-4eba-8e98-42e66c16f463\u0026file_path=dist%2Findex%2F3d.png","latest_version":"1.0.5","license":"unset","owner_org_id":"7978967e-b956-4ac2-b813-667a08f6310a","org_owner_tscircuit_handle":"abse","owner_github_username":null,"github_repo_full_name":null,"is_source_from_github":false,"description":null,"name":"abse/boostxl-uln2003","unscoped_name":"boostxl-uln2003","star_count":0,"created_at":"2026-08-12T10:10:06.978Z","updated_at":"2026-08-12T22:29:23.783Z","ai_description":"This code defines a React component that models a through-hole or surface-mount LED with specified pin labels, footprint, silkscreen, and 3D CAD model for PCB layout.","ai_usage_instructions":null,"is_private":false,"is_unlisted":false,"is_public":true,"public_dist_enabled":false,"has_public_dist":true,"starred_at":null,"default_view":"files","website":null,"github_installation_id":null,"allow_pr_previews":false,"related_type":"same_author","thumbnail_url":"https://api.tscircuit.com/package_files/view?package_release_id=92d10956-aa95-4eba-8e98-42e66c16f463\u0026file_path=dist%2Findex%2Fpcb.svg"},{"package_id":"1a688437-24fc-4e9f-921c-1ddc4fc53cf5","creator_account_id":"84198f66-bb86-4dc1-97f0-cdf2cf2c843a","latest_package_release_id":"37e98b52-0b1d-4f91-8f06-8e5e321f5e45","last_built_release_id":"37e98b52-0b1d-4f91-8f06-8e5e321f5e45","latest_package_release_fs_sha":"md5-a234ce80dacb6ff214fc7c28c619fd53","latest_pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=37e98b52-0b1d-4f91-8f06-8e5e321f5e45\u0026file_path=dist%2Fassembly%2Fpcb.svg","latest_sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=37e98b52-0b1d-4f91-8f06-8e5e321f5e45\u0026file_path=dist%2Fassembly%2Fschematic.svg","latest_cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=37e98b52-0b1d-4f91-8f06-8e5e321f5e45\u0026file_path=dist%2Fassembly%2F3d.png","latest_version":"1.12.2","license":"ISC","owner_org_id":"07e44f25-c5d3-4583-9c34-2c7bb568f85b","org_owner_tscircuit_handle":"AnasSarkiz","owner_github_username":"AnasSarkiz","github_repo_full_name":null,"is_source_from_github":false,"description":null,"name":"AnasSarkiz/NEMA14_CH32X035G8U6","unscoped_name":"NEMA14_CH32X035G8U6","star_count":0,"created_at":"2026-10-07T17:53:37.598Z","updated_at":"2026-10-16T19:05:31.590Z","ai_description":"A NEMA stepper motor is shown with proposed M3 screws/spacers, four wired motor leads and splices, and a JST SHR-04V-S connector.","ai_usage_instructions":null,"is_private":false,"is_unlisted":false,"is_public":true,"public_dist_enabled":true,"has_public_dist":true,"starred_at":null,"default_view":"files","website":null,"github_installation_id":null,"allow_pr_previews":false,"related_type":"random","thumbnail_url":"https://api.tscircuit.com/package_files/view?package_release_id=37e98b52-0b1d-4f91-8f06-8e5e321f5e45\u0026file_path=dist%2Fassembly%2Fpcb.svg"}]; window.SSR_PACKAGE_ROUTE = {"author":"abse","packageName":"gameboy-advance","packageNameWithScope":"abse/gameboy-advance","version":null,"isLegacyRoute":false,"kind":"file","filePath":"firmware/game-console/doomgeneric/i_system.c"};

abse/gameboy-advance

A tscircuit package created by abse.

Version
0.0.45
License
unset
Stars
0

firmware/game-console/doomgeneric/i_system.c

//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// DESCRIPTION:
//



#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <stdarg.h>

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <unistd.h>
#endif

#ifdef ORIGCODE
#include "SDL.h"
#endif

#include "config.h"

#include "deh_str.h"
#include "doomtype.h"
#include "m_argv.h"
#include "m_config.h"
#include "m_misc.h"
#include "i_joystick.h"
#include "i_sound.h"
#include "i_timer.h"
#include "i_video.h"

#include "i_system.h"

#include "w_wad.h"
#include "z_zone.h"

#ifdef __MACOSX__
#include <CoreFoundation/CFUserNotification.h>
#endif

#define DEFAULT_RAM 6 /* MiB */
#define MIN_RAM     6  /* MiB */


typedef struct atexit_listentry_s atexit_listentry_t;

struct atexit_listentry_s
{
    atexit_func_t func;
    boolean run_on_error;
    atexit_listentry_t *next;
};

static atexit_listentry_t *exit_funcs = NULL;

void I_AtExit(atexit_func_t func, boolean run_on_error)
{
    atexit_listentry_t *entry;

    entry = malloc(sizeof(*entry));

    entry->func = func;
    entry->run_on_error = run_on_error;
    entry->next = exit_funcs;
    exit_funcs = entry;
}

// Tactile feedback function, probably used for the Logitech Cyberman

void I_Tactile(int on, int off, int total)
{
}

// Zone memory auto-allocation function that allocates the zone size
// by trying progressively smaller zone sizes until one is found that
// works.

static byte *AutoAllocMemory(int *size, int default_ram, int min_ram)
{
    byte *zonemem;

    // Allocate the zone memory.  This loop tries progressively smaller
    // zone sizes until a size is found that can be allocated.
    // If we used the -mb command line parameter, only the parameter
    // provided is accepted.

    zonemem = NULL;

    while (zonemem == NULL)
    {
        // We need a reasonable minimum amount of RAM to start.

        if (default_ram < min_ram)
        {
            I_Error("Unable to allocate %i MiB of RAM for zone", default_ram);
        }

        // Try to allocate the zone memory.

        *size = default_ram * 1024 * 1024;

        zonemem = malloc(*size);

        // Failed to allocate?  Reduce zone size until we reach a size
        // that is acceptable.

        if (zonemem == NULL)
        {
            default_ram -= 1;
        }
    }

    return zonemem;
}

byte *I_ZoneBase (int *size)
{
    byte *zonemem;
    int min_ram, default_ram;
    int p;

    //!
    // @arg <mb>
    //
    // Specify the heap size, in MiB (default 16).
    //

    p = M_CheckParmWithArgs("-mb", 1);

    if (p > 0)
    {
        default_ram = atoi(myargv[p+1]);
        min_ram = default_ram;
    }
    else
    {
        default_ram = DEFAULT_RAM;
        min_ram = MIN_RAM;
    }

    zonemem = AutoAllocMemory(size, default_ram, min_ram);

    printf("zone memory: %p, %x allocated for zone\n", 
           zonemem, *size);

    return zonemem;
}

void I_PrintBanner(char *msg)
{
    int i;
    int spaces = 35 - (strlen(msg) / 2);

    for (i=0; i<spaces; ++i)
        putchar(' ');

    puts(msg);
}

void I_PrintDivider(void)
{
    int i;

    for (i=0; i<75; ++i)
    {
        putchar('=');
    }

    putchar('\n');
}

void I_PrintStartupBanner(char *gamedescription)
{
    I_PrintDivider();
    I_PrintBanner(gamedescription);
    I_PrintDivider();
    
    printf(
    " " PACKAGE_NAME " is free software, covered by the GNU General Public\n"
    " License.  There is NO warranty; not even for MERCHANTABILITY or FITNESS\n"
    " FOR A PARTICULAR PURPOSE. You are welcome to change and distribute\n"
    " copies under certain conditions. See the source for more information.\n");

    I_PrintDivider();
}

// 
// I_ConsoleStdout
//
// Returns true if stdout is a real console, false if it is a file
//

boolean I_ConsoleStdout(void)
{
#ifdef _WIN32
    // SDL "helpfully" always redirects stdout to a file.
    return 0;
#else
#if ORIGCODE
    return isatty(fileno(stdout));
#else
	return 0;
#endif
#endif
}

//
// I_Init
//
/*
void I_Init (void)
{
    I_CheckIsScreensaver();
    I_InitTimer();
    I_InitJoystick();
}
void I_BindVariables(void)
{
    I_BindVideoVariables();
    I_BindJoystickVariables();
    I_BindSoundVariables();
}
*/

//
// I_Quit
//

void I_Quit (void)
{
    atexit_listentry_t *entry;

    // Run through all exit functions
 
    entry = exit_funcs; 

    while (entry != NULL)
    {
        entry->func();
        entry = entry->next;
    }

#if ORIGCODE
    SDL_Quit();

    exit(0);
#endif
}

#if !defined(_WIN32) && !defined(__MACOSX__) && !defined(__DJGPP__)
#define ZENITY_BINARY "/usr/bin/zenity"

// returns non-zero if zenity is available

static int ZenityAvailable(void)
{
    return system(ZENITY_BINARY " --help >/dev/null 2>&1") == 0;
}

// Escape special characters in the given string so that they can be
// safely enclosed in shell quotes.

static char *EscapeShellString(char *string)
{
    char *result;
    char *r, *s;

    // In the worst case, every character might be escaped.
    result = malloc(strlen(string) * 2 + 3);
    r = result;

    // Enclosing quotes.
    *r = '"';
    ++r;

    for (s = string; *s != '\0'; ++s)
    {
        // From the bash manual:
        //
        //  "Enclosing characters in double quotes preserves the literal
        //   value of all characters within the quotes, with the exception
        //   of $, `, \, and, when history expansion is enabled, !."
        //
        // Therefore, escape these characters by prefixing with a backslash.

        if (strchr("$`\\!", *s) != NULL)
        {
            *r = '\\';
            ++r;
        }

        *r = *s;
        ++r;
    }

    // Enclosing quotes.
    *r = '"';
    ++r;
    *r = '\0';

    return result;
}

// Open a native error box with a message using zenity

static int ZenityErrorBox(char *message)
{
    int result;
    char *escaped_message;
    char *errorboxpath;
    static size_t errorboxpath_size;

    if (!ZenityAvailable())
    {
        return 0;
    }

    escaped_message = EscapeShellString(message);

    errorboxpath_size = strlen(ZENITY_BINARY) + strlen(escaped_message) + 19;
    errorboxpath = malloc(errorboxpath_size);
    M_snprintf(errorboxpath, errorboxpath_size, "%s --error --text=%s",
               ZENITY_BINARY, escaped_message);

    result = system(errorboxpath);

    free(errorboxpath);
    free(escaped_message);

    return result;
}

#endif /* !defined(_WIN32) && !defined(__MACOSX__) && !defined(__DJGPP__) */


//
// I_Error
//

static boolean already_quitting = false;

void I_Error (char *error, ...)
{
    char msgbuf[512];
    va_list argptr;
    atexit_listentry_t *entry;
    boolean exit_gui_popup;

    if (already_quitting)
    {
        fprintf(stderr, "Warning: recursive call to I_Error detected.\n");
#if ORIGCODE
        exit(-1);
#endif
    }
    else
    {
        already_quitting = true;
    }

    // Message first.
    va_start(argptr, error);
    //fprintf(stderr, "\nError: ");
    vfprintf(stderr, error, argptr);
    fprintf(stderr, "\n\n");
    va_end(argptr);
    fflush(stderr);

    // Write a copy of the message into buffer.
    va_start(argptr, error);
    memset(msgbuf, 0, sizeof(msgbuf));
    M_vsnprintf(msgbuf, sizeof(msgbuf), error, argptr);
    va_end(argptr);

    extern void gba_fatal(const char *message);
    gba_fatal(msgbuf);

    // Shutdown. Here might be other errors.

    entry = exit_funcs;

    while (entry != NULL)
    {
        if (entry->run_on_error)
        {
            entry->func();
        }

        entry = entry->next;
    }

    exit_gui_popup = !M_ParmExists("-nogui");

    // Pop up a GUI dialog box to show the error message, if the
    // game was not run from the console (and the user will
    // therefore be unable to otherwise see the message).
    if (exit_gui_popup && !I_ConsoleStdout())
#ifdef _WIN32
    {
        wchar_t wmsgbuf[512];

        MultiByteToWideChar(CP_ACP, 0,
                            msgbuf, strlen(msgbuf) + 1,
                            wmsgbuf, sizeof(wmsgbuf));

        MessageBoxW(NULL, wmsgbuf, L"", MB_OK);
    }
#elif defined(__MACOSX__)
    {
        CFStringRef message;
	int i;

	// The CoreFoundation message box wraps text lines, so replace
	// newline characters with spaces so that multiline messages
	// are continuous.

	for (i = 0; msgbuf[i] != '\0'; ++i)
        {
            if (msgbuf[i] == '\n')
            {
                msgbuf[i] = ' ';
            }
        }

        message = CFStringCreateWithCString(NULL, msgbuf,
                                            kCFStringEncodingUTF8);

        CFUserNotificationDisplayNotice(0,
                                        kCFUserNotificationCautionAlertLevel,
                                        NULL,
                                        NULL,
                                        NULL,
                                        CFSTR(PACKAGE_STRING),
                                        message,
                                        NULL);
    }
#elif defined(__DJGPP__)
    {
        printf("%s\n", msgbuf);
        exit(-1);
    }

#else
    {
        ZenityErrorBox(msgbuf);
    }
#endif

    // abort();
#if ORIGCODE
    SDL_Quit();

    exit(-1);
#else
    exit(-1);
#endif
}

//
// Read Access Violation emulation.
//
// From PrBoom+, by entryway.
//

// C:\>debug
// -d 0:0
//
// DOS 6.22:
// 0000:0000  (57 92 19 00) F4 06 70 00-(16 00)
// DOS 7.1:
// 0000:0000  (9E 0F C9 00) 65 04 70 00-(16 00)
// Win98:
// 0000:0000  (9E 0F C9 00) 65 04 70 00-(16 00)
// DOSBox under XP:
// 0000:0000  (00 00 00 F1) ?? ?? ?? 00-(07 00)

#define DOS_MEM_DUMP_SIZE 10

static const unsigned char mem_dump_dos622[DOS_MEM_DUMP_SIZE] = {
  0x57, 0x92, 0x19, 0x00, 0xF4, 0x06, 0x70, 0x00, 0x16, 0x00};
static const unsigned char mem_dump_win98[DOS_MEM_DUMP_SIZE] = {
  0x9E, 0x0F, 0xC9, 0x00, 0x65, 0x04, 0x70, 0x00, 0x16, 0x00};
static const unsigned char mem_dump_dosbox[DOS_MEM_DUMP_SIZE] = {
  0x00, 0x00, 0x00, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00};
static unsigned char mem_dump_custom[DOS_MEM_DUMP_SIZE];

static const unsigned char *dos_mem_dump = mem_dump_dos622;

boolean I_GetMemoryValue(unsigned int offset, void *value, int size)
{
    static boolean firsttime = true;

    if (firsttime)
    {
        int p, i, val;

        firsttime = false;
        i = 0;

        //!
        // @category compat
        // @arg <version>
        //
        // Specify DOS version to emulate for NULL pointer dereference
        // emulation.  Supported versions are: dos622, dos71, dosbox.
        // The default is to emulate DOS 7.1 (Windows 98).
        //

        p = M_CheckParmWithArgs("-setmem", 1);

        if (p > 0)
        {
            if (!strcasecmp(myargv[p + 1], "dos622"))
            {
                dos_mem_dump = mem_dump_dos622;
            }
            if (!strcasecmp(myargv[p + 1], "dos71"))
            {
                dos_mem_dump = mem_dump_win98;
            }
            else if (!strcasecmp(myargv[p + 1], "dosbox"))
            {
                dos_mem_dump = mem_dump_dosbox;
            }
            else
            {
                for (i = 0; i < DOS_MEM_DUMP_SIZE; ++i)
                {
                    ++p;

                    if (p >= myargc || myargv[p][0] == '-')
                    {
                        break;
                    }

                    M_StrToInt(myargv[p], &val);
                    mem_dump_custom[i++] = (unsigned char) val;
                }

                dos_mem_dump = mem_dump_custom;
            }
        }
    }

    switch (size)
    {
    case 1:
        *((unsigned char *) value) = dos_mem_dump[offset];
        return true;
    case 2:
        *((unsigned short *) value) = dos_mem_dump[offset]
                                    | (dos_mem_dump[offset + 1] << 8);
        return true;
    case 4:
        *((unsigned int *) value) = dos_mem_dump[offset]
                                  | (dos_mem_dump[offset + 1] << 8)
                                  | (dos_mem_dump[offset + 2] << 16)
                                  | (dos_mem_dump[offset + 3] << 24);
        return true;
    }

    return false;
}