 /***************************************************************************

  config.c

  Stores global options and per-game options;

***************************************************************************/

#include "driver.h"

#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <math.h>
#include <sys/stat.h>
#include <direct.h>
#include "neogeo.h"/* dbg-bios */
#include "win32.h"
#include "misc.h"
#include "DirectDraw.h"
#include "DIKeyboard.h"
#include "DIJoystick.h"
#include "Joystick.h"
#include "resource.h"

/***************************************************************************
    Internal function prototypes
 ***************************************************************************/

static void  LoadOptions(void);
static void  SaveOptions(void);
static void  SaveBackupOptions(void);

static void  SaveIniDirectoriesOptions(void);
static void  LoadIniDirectoriesOptions(void);

static void  SaveIniSettingsOptions(void);
static void  LoadIniSettingsOptions(char *szVersion);

static void  LoadIniGameOptions(options_type *osd_options);
static void  SaveIniGameOptions(options_type *osd_options);

static void  SaveFolderFlags(char *folderName, DWORD dwFlags);

static void  ColumnEncodeString(void *data, char *str);
static void  ColumnDecodeString(const char *str, void *data);

static void  ColumnDecodeWidths(const char *ptr, void *data);

static void  SplitterEncodeString(void *data, char *str);
static void  SplitterDecodeString(const char *str, void *data);

static void  ListEncodeString(void *data, char *str);
static void  ListDecodeString(const char *str, void *data);

static void  FontEncodeString(void *data, char *str);
static void  FontDecodeString(const char *str, void *data);

static BOOL IniCreate(void);
static void IniDestroy(void);
static void IniReset(void);
static BOOL IniReadDefaultFile(FILE *fp, char *linebuf);
static void IniReadFile(FILE *fp, char *linebuf);
static void IniWriteFile(FILE *fp, const char *keyname);
static long IniQueryValue(const char *name, void *value, DWORD *size);
static void IniSetValue(const char *name, void *value, DWORD size);

static DWORD GetIniOption(char *name);
static void PutIniOption(char *name, DWORD value);

static BOOL GetIniBoolOption(char *name);
static void PutIniBoolOption(char *name, BOOL value);

static char *GetIniStringOption(char *name);
static void PutIniStringOption(char *name, char *option);

static void GetIniObj(INI_OPTIONS *iniOpt);
static void PutIniObj(INI_OPTIONS *iniOpt);

INLINE int GetIndexByName(const char *name);

/***************************************************************************
    Internal defines
 ***************************************************************************/

#define DEFAULT_INI     "ini/mame32jp.ini"
#define GUIBACK_INI     "ini/guiback.ini"
#define GAMEBACK_INI    "ini/gameback.ini"
#define FOLDERS_INI     "ini/folders.ini"
#define GAMES_INI       "ini/games.ini"
#define DIRECTORIES_INI "ini/dirs.ini"

#define LINEBUF_SIZE  65536

#if defined(NEOMAME)
#define DEFAULT_GAME  "nam1975"
#elif defined(CPSMAME)
#define DEFAULT_GAME  "ssf2"
#else
#define DEFAULT_GAME  "pacman"
#endif

/***************************************************************************
    Internal structures
 ***************************************************************************/

typedef struct ini_t {
    char *name;
    char *value;
} ini_struct;

static ini_struct *ini;

/***************************************************************************
    Internal variables
 ***************************************************************************/

static directories_type directories;
static settings_type settings;

static options_type gOpts;  /* Used when saving/loading from Registry */
static options_type global; /* Global 'default' options */
static options_type backup; /* Backup 'default' options */
static options_type *game;  /* Array of Game specific options */

/* Directory options */
INI_OPTIONS iniDirectories[] =
{
    { "RomPath",             IO_PSTRING,   &directories.rompath,         0, 0 },
    { "SamplepPth",          IO_PSTRING,   &directories.samplepath,      0, 0 },
    { "ConfigDirectory",     IO_PSTRING,   &directories.cfgdir,          0, 0 },
#ifdef EXTRA_FOLDER
    { "FolderDirectory",     IO_PSTRING,   &directories.folderdir,       0, 0 },
#endif
    { "NVRamDirectory",      IO_PSTRING,   &directories.nvdir,           0, 0 },
    { "MemCardDirectory",    IO_PSTRING,   &directories.memcarddir,      0, 0 },
    { "InputDirectory",      IO_PSTRING,   &directories.inpdir,          0, 0 },
    { "HiscoreDirectory",    IO_PSTRING,   &directories.hidir,           0, 0 },
    { "StateDirectory",      IO_PSTRING,   &directories.stadir,          0, 0 },
    { "ArtworkDirectory",    IO_PSTRING,   &directories.artworkdir,      0, 0 },
    { "SnapshotDirectory",   IO_PSTRING,   &directories.screenshotdir,   0, 0 },
    { "DiffDirectory",       IO_PSTRING,   &directories.diffdir,         0, 0 },
    { "CtrlrDirectory",      IO_PSTRING,   &directories.ctrlrdir,        0, 0 },
    { "IconDirectory",       IO_PSTRING,   &directories.icondir,         0, 0 },
    { "WavDirectory",        IO_PSTRING,   &directories.wavedir,         0, 0 },
    { "FlyerDirectroy",      IO_PSTRING,   &directories.flyerdir,        0, 0 },
    { "CabinetDirectory",    IO_PSTRING,   &directories.cabinetdir,      0, 0 },
    { "MarqueeDirectory",    IO_PSTRING,   &directories.marqueedir,      0, 0 },
#ifdef TAB_CONTROLL
    { "TitleDirectory",      IO_PSTRING,   &directories.titledir,        0, 0 },
#endif /* TAB_CONTROLL */
#ifdef RANDAM_BACKGROUND
    { "BkgroundDirectory",   IO_PSTRING,   &directories.bgdir,           0, 0 },
#endif /* RANDAM_BACKGROUND */
};

/* Global UI options */
INI_OPTIONS iniSettings[] =
{
    { "DefaultGame",         IO_STRING,    settings.default_game,        0, 0 },
    { "FolderID",            IO_INT,       &settings.folder_id,          0, 0 },
    { "ShowScreenShot",      IO_BOOL,      &settings.show_screenshot,    0, 0 },
#ifdef TAB_CONTROLL
    { "HistoryTab",          IO_INT,       &settings.history_tab,        0, 0 },
    { "ShowPageTab",         IO_BOOL,      &settings.show_tabctrl,       0, 0 },
#endif /* TAB_CONTROLL */
    { "ShowFlyer",           IO_INT,       &settings.show_pict_type,     0, 0 },
    { "ShowToolBar",         IO_BOOL,      &settings.show_toolbar,       0, 0 },
    { "ShowStatusBar",       IO_BOOL,      &settings.show_statusbar,     0, 0 },
    { "ShowFolderList",      IO_BOOL,      &settings.show_folderlist,    0, 0 },
    { "GameCheck",           IO_BOOL,      &settings.game_check,         0, 0 },
    { "VersionCheck",        IO_BOOL,      &settings.version_check,      0, 0 },
    { "MMXCheck",            IO_BOOL,      &settings.mmx_check,          0, 0 },
#ifdef JOYGUI
    { "JoyGUI",              IO_BOOL,      &settings.use_joygui,         0, 0 },
    { "JoyGUIDI",            IO_BOOL,      &settings.use_joyguidi,       0, 0 },
    { "DJoyGUI",             IO_BOOL,      &settings.use_djoygui,        0, 0 },
#endif
#ifdef RANDAM_BACKGROUND
    { "random_bg",           IO_BOOL,      &settings.random_bg,          0, 0 },
#endif /* RANDAM_BACKGROUND */
#ifdef JAPANESE
    { "UseJapaneseList",     IO_BOOL,      &settings.use_japanese_list,  0, 0 },
    { "ModifyThe",           IO_BOOL,      &settings.modify_the,         0, 0 },
#endif
#ifdef KAILLERA
    { "UseFavoriteNetPlay",  IO_BOOL,      &settings.use_netplay_folder, 0, 0 },
    { "UseIMEInChat",        IO_BOOL,      &settings.use_ime_in_chat,    0, 0 },
    { "ChatDrawMode",        IO_INT,       &settings.chat_draw_mode,     0, 0 },
#endif /* KAILLERA */
    { "Vsync60Hz",           IO_BOOL,      &settings.vsync_60,           0, 0 },
    { "TilemapMMX",          IO_BOOL,      &settings.tilemap_mmx,        0, 0 },
    { "SortColumn",          IO_INT,       &settings.sort_column,        0, 0 },
    { "SortReverse",         IO_BOOL,      &settings.sort_reverse,       0, 0 },
    { "GUIPosX",             IO_INT,       &settings.area.x,             0, 0 },
    { "GUIPosY",             IO_INT,       &settings.area.y,             0, 0 },
    { "GUIWidth",            IO_INT,       &settings.area.width,         0, 0 },
    { "GUIHeight",           IO_INT,       &settings.area.height,        0, 0 },
#ifndef JAPANESE
    { "Language",            IO_PSTRING,   &settings.language,           0, 0 },
#endif
    { "ListMode",            IO_ENCODE,    &settings.view,               ListEncodeString,     ListDecodeString     },
    { "Splitters",           IO_ENCODE,    settings.splitter,            SplitterEncodeString, SplitterDecodeString },
    { "ListFont",            IO_ENCODE,    &settings.list_font,          FontEncodeString,     FontDecodeString     },
    { "ColumnWidths",        IO_ENCODE,    &settings.column_width,       ColumnEncodeString,   ColumnDecodeWidths   },
    { "ColumnOrder",         IO_ENCODE,    &settings.column_order,       ColumnEncodeString,   ColumnDecodeString   },
    { "ColumnShown",         IO_ENCODE,    &settings.column_shown,       ColumnEncodeString,   ColumnDecodeString   },
};

/* Game Options */
INI_OPTIONS iniGameOpts[] =
{
    { "ScreenWidth",            IO_INT,    &gOpts.width,             0, 0 },
    { "ScreenHeight",           IO_INT,    &gOpts.height,            0, 0 },
    { "RefreshRate",            IO_INT,    &gOpts.refreshrate,       0, 0 },
    { "SwitchResolution",       IO_BOOL,   &gOpts.switchres,         0, 0 },
    { "WindowMode",             IO_BOOL,   &gOpts.window_mode,       0, 0 },
    { "Monitor",                IO_INT,    &gOpts.monitor,           0, 0 },
    { "Brightness",             IO_INT,    &gOpts.brightness,        0, 0 },
    { "GammaCorrection",        IO_DOUBLE, &gOpts.gamma_correct,     0, 0 },
    { "InternalBPP",            IO_INT,    &gOpts.color_depth,       0, 0 },
    { "ScreenBPP",              IO_INT,    &gOpts.screen_depth,      0, 0 },
    { "AutoFrameSkip",          IO_BOOL,   &gOpts.autoframeskip,     0, 0 },
    { "FrameSkip",              IO_INT,    &gOpts.frameskip,         0, 0 },
    { "Rotate",                 IO_INT,    &gOpts.rotate,            0, 0 },
    { "FlipX",                  IO_BOOL,   &gOpts.flipx,             0, 0 },
    { "FlipY",                  IO_BOOL,   &gOpts.flipy,             0, 0 },

    { "AdjustAspectRatio",      IO_BOOL,   &gOpts.adjust_aspect,     0, 0 },
#ifdef FSSTRETCH
    { "StretchFullScreen",      IO_BOOL,   &gOpts.fat_mode,          0, 0 },
#endif
    { "InternalDouble",         IO_BOOL,   &gOpts.double_size,       0, 0 },
#ifdef SAI
    { "2xScale",                IO_BOOL,   &gOpts.double_filter,     0, 0 },
#endif
    { "HorizontalScanlines",    IO_BOOL,   &gOpts.hscanlines,        0, 0 },
    { "VerticalScanLines",      IO_BOOL,   &gOpts.vscanlines,        0, 0 },
    { "ScanlineBrightness",     IO_INT,    &gOpts.sl_brightness,     0, 0 },
    { "HardwareStretch",        IO_INT,    &gOpts.hw_stretch,        0, 0 },
    { "StretchScale",           IO_INT,    &gOpts.scale,             0, 0 },
    { "TripleBuffer",           IO_BOOL,   &gOpts.use_triplebuf,     0, 0 },
    { "TripleBufferWait",       IO_BOOL,   &gOpts.tbvsync,           0, 0 },
    { "VSync",                  IO_BOOL,   &gOpts.wait_vsync,        0, 0 },
    { "UseSleep",               IO_BOOL,   &gOpts.use_sleep,         0, 0 },
    { "UseDDrawHEL",            IO_BOOL,   &gOpts.use_hel,           0, 0 },
    { "UseSystemMemory",        IO_BOOL,   &gOpts.use_sysmem,        0, 0 },

    { "SoundType",              IO_INT,    &gOpts.sound_type,        0, 0 },
    { "SampleRate",             IO_INT,    &gOpts.samplerate,        0, 0 },
    { "VolumeAttenuation",      IO_INT,    &gOpts.attenuation,       0, 0 },
    { "SoundDelay",             IO_INT,    &gOpts.sound_delay,       0, 0 },
    { "Stereo",                 IO_BOOL,   &gOpts.stereo,            0, 0 },
    { "UseSamples",             IO_BOOL,   &gOpts.use_samples,       0, 0 },
    { "ResampleFilter",         IO_BOOL,   &gOpts.use_filter,        0, 0 },
    { "ForcePanpot",            IO_BOOL,   &gOpts.force_panpot,      0, 0 },
    { "LimitAdjust",            IO_BOOL,   &gOpts.limit_adjust,      0, 0 },
    { "FormatVolume",           IO_BOOL,   &gOpts.format_volume,     0, 0 },
    { "AutoAdjust",             IO_BOOL,   &gOpts.auto_adjust,       0, 0 },
    { "PreSoundfix",            IO_BOOL,   &gOpts.presoundfix,       0, 0 },

    { "UseJoystick",            IO_BOOL,   &gOpts.use_joystick,      0, 0 },
    { "DirectInputJoystick",    IO_BOOL,   &gOpts.di_joystick,       0, 0 },
    { "UseDjoystick",           IO_BOOL,   &gOpts.use_djoystick,     0, 0 },
    { "JoystickID1",            IO_INT,    &gOpts.joyid[0],          0, 0 },
    { "JoystickID2",            IO_INT,    &gOpts.joyid[1],          0, 0 },
    { "JoystickID3",            IO_INT,    &gOpts.joyid[2],          0, 0 },
    { "JoystickID4",            IO_INT,    &gOpts.joyid[3],          0, 0 },
    { "UseMouse",               IO_BOOL,   &gOpts.use_mouse,         0, 0 },
    { "DirectInputMouse",       IO_BOOL,   &gOpts.di_mouse,          0, 0 },
    { "DirectInputKeyboard",    IO_BOOL,   &gOpts.di_keyboard,       0, 0 },
    { "DefaultInputLayout",     IO_INT,    &gOpts.default_input,     0, 0 },

    { "UseArtwork",             IO_BOOL,   &gOpts.use_artwork,       0, 0 },
    { "AutoPause",              IO_BOOL,   &gOpts.auto_pause,        0, 0 },
    { "EnableCheat",            IO_BOOL,   &gOpts.cheat,             0, 0 },
#ifdef MAME_DEBUG
    { "EnableDebugger",         IO_BOOL,   &gOpts.mame_debug,        0, 0 },
#endif
    { "DisableMMX",             IO_BOOL,   &gOpts.disable_mmx,       0, 0 },
    { "DisableMMX2",            IO_BOOL,   &gOpts.disable_mmx2,      0, 0 },
    { "DisablePCounter",        IO_BOOL,   &gOpts.disable_pcounter,  0, 0 },
    { "Log",                    IO_BOOL,   &gOpts.errorlog,          0, 0 },
#ifdef NFILTER
    { "DisableBFilter",         IO_BOOL,   &gOpts.nfilter,           0, 0 },
#endif
    { "Transparency",           IO_BOOL,   &gOpts.transparency,      0, 0 },
    { "TransparencyRate",       IO_INT,    &gOpts.transparency_rate, 0, 0 },
#ifdef ROMPATCH
    { "UseRomPatch",            IO_BOOL,   &gOpts.patch_roms,        0, 0 },
#endif

#ifdef MAME32JP
    { "HiscoreForce",           IO_BOOL,   &gOpts.hiscore_force,	 0, 0 }, 
    { "HiscoreDisable",         IO_BOOL,   &gOpts.hiscore_disable,	 0, 0 }, 
    { "Blackout",               IO_BOOL,   &gOpts.blackout,	         0, 0 }, // BLACKOUT
    { "AutofireMessage",        IO_BOOL,   &gOpts.autofire_message,  0, 0 }, // AUTOFIRE_MESSAGE
#endif /* MAME32JP */

	{ "Bios_type",              IO_BOOL,   &gOpts.bios_type,         0, 0 },/* dbg-bios */
    { "Antialias",              IO_BOOL,   &gOpts.antialias,         0, 0 },
    { "Translucency",           IO_BOOL,   &gOpts.translucency,      0, 0 },
    { "Beam",                   IO_DOUBLE, &gOpts.beam,              0, 0 },
    { "Flicker",                IO_INT,    &gOpts.flicker,           0, 0 },
};

#define NUM_DIRECTORIES  (sizeof(iniDirectories) / sizeof(iniDirectories[0]))
#define NUM_SETTINGS     (sizeof(iniSettings) / sizeof(iniSettings[0]))
#define NUM_GAMEOPTS     (sizeof(iniGameOpts) / sizeof(iniGameOpts[0]))
#define NUM_EXTRA        (64)
#define INI_MAX_ENTRIES  (NUM_DIRECTORIES + NUM_SETTINGS + NUM_GAMEOPTS + NUM_EXTRA)

static int  num_games      = 0;
static BOOL bResetGUI      = FALSE;
static BOOL bResetGameDefs = FALSE;


#ifdef MAME32JP
#ifdef JAPANESE
/* Default sizes based on 12pt font w/sort arrow in that column */
static int default_column_width[] = { 280,102, 60, 88, 50, 88, 68,155, 50,216, 68 };
#else
/* Default sizes based on 8pt font w/sort arrow in that column */
static int default_column_width[] = { 186, 68, 84, 84, 64, 88, 74,108, 60,144, 45 };
#endif
static int default_column_shown[] = {   1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1 };
static int default_column_order[] = {   0,  2,  3,  4,  5,  6,  7,  8,  9, 10,  1 };
#else
/* Default sizes based on 8pt font w/sort arrow in that column */
static int default_column_width[] = { 186, 68, 84, 84, 64, 88, 74,108, 60,144 };
static int default_column_shown[] = {   1,  0,  1,  1,  1,  1,  1,  1,  1,  1 };
static int default_column_order[] = {   0,  2,  3,  4,  5,  6,  7,  8,  9,  1 };
#endif

static char *view_modes[VIEW_MAX] = { "Large Icons", "Small Icons", "List", "Details" };

/***************************************************************************
    External functions
 ***************************************************************************/

void win32_config_init(int total_games)
{
    int i, save = 0;
    struct stat stat_buffer;

    num_games = total_games;

    directories.rompath        = strdup("roms");
    directories.samplepath     = strdup("samples");
    directories.cfgdir         = strdup("cfgwin");
#ifdef EXTRA_FOLDER
    directories.folderdir      = strdup("folders");
#endif
    directories.nvdir          = strdup("nvram");
    directories.memcarddir     = strdup("memcard");
    directories.inpdir         = strdup("inp");
    directories.hidir          = strdup("hi");
    directories.stadir         = strdup("sta");
    directories.artworkdir     = strdup("artwork");
    directories.screenshotdir  = strdup("snap");
    directories.diffdir        = strdup("diff");
    directories.ctrlrdir       = strdup("ctrlr");
    directories.icondir        = strdup("icons");
    directories.wavedir        = strdup("wav");
    directories.flyerdir       = strdup("flyers");
    directories.cabinetdir     = strdup("cabinets");
    directories.marqueedir     = strdup("marquees");
#ifdef TAB_CONTROLL
    directories.titledir       = strdup("titles");
#endif /* TAB_CONTROLL */
#ifdef RANDAM_BACKGROUND
    directories.bgdir          = strdup("bkground");
#endif /* RANDAM_BACKGROUND */

    strcpy(settings.default_game, DEFAULT_GAME);
    settings.folder_id         = 0;
    settings.view              = VIEW_REPORT;
    settings.show_folderlist   = TRUE;
    settings.show_toolbar      = TRUE;
    settings.show_statusbar    = TRUE;
    settings.show_screenshot   = TRUE;
    settings.game_check        = TRUE;
    settings.version_check     = TRUE;
    settings.mmx_check         = TRUE;
#ifdef JOYGUI
    settings.use_joygui        = FALSE;
    settings.use_joyguidi      = FALSE;
    settings.use_djoygui       = FALSE;
#endif
#ifdef RANDAM_BACKGROUND
    settings.random_bg         = FALSE;
#endif /* RANDAM_BACKGROUND */
#ifdef JAPANESE
    settings.use_japanese_list = FALSE;
    settings.modify_the        = TRUE;
#endif

#ifdef MAME32JP
    settings.vsync_60          = TRUE;
#endif

#ifdef KAILLERA
    settings.use_netplay_folder= FALSE;
    settings.use_ime_in_chat   = FALSE;
    settings.chat_draw_mode    = 0;
#endif /* KAILLERA */

    for (i = 0; i < COLUMN_MAX; i++)
    {
        settings.column_width[i] = default_column_width[i];
        settings.column_order[i] = default_column_order[i];
        settings.column_shown[i] = default_column_shown[i];
    }

    settings.sort_column                = 0;
    settings.sort_reverse               = FALSE;
    settings.area.x                     = 0;
    settings.area.y                     = 0;
    settings.area.width                 = 640;
    settings.area.height                = 400;
    settings.splitter[0]                = 150;
    settings.splitter[1]                = 300;

#ifndef JAPANESE
    settings.language                   = strdup("english");
#endif

    settings.list_font_color            = (COLORREF)-1;
#ifdef JAPANESE
    settings.list_font.lfHeight         = -12;
#else
    settings.list_font.lfHeight         = -8;
#endif
    settings.list_font.lfWidth          = 0;
    settings.list_font.lfEscapement     = 0;
    settings.list_font.lfOrientation    = 0;
    settings.list_font.lfWeight         = FW_NORMAL;
    settings.list_font.lfItalic         = FALSE;
    settings.list_font.lfUnderline      = FALSE;
    settings.list_font.lfStrikeOut      = FALSE;
#ifdef JAPANESE
    settings.list_font.lfCharSet        = SHIFTJIS_CHARSET;
#else
    settings.list_font.lfCharSet        = ANSI_CHARSET;
#endif
    settings.list_font.lfOutPrecision   = OUT_DEFAULT_PRECIS;
    settings.list_font.lfClipPrecision  = CLIP_DEFAULT_PRECIS;
    settings.list_font.lfQuality        = DEFAULT_QUALITY;
    settings.list_font.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
#ifdef JAPANESE
    strcpy(settings.list_font.lfFaceName, "ＭＳ Ｐゴシック");
#else
    strcpy(settings.list_font.lfFaceName, "MS Sans Serif");
#endif

    global.use_default            = FALSE;
    global.play_count             = 0;
    global.has_roms               = UNKNOWN;
    global.has_samples            = UNKNOWN;
    global.is_favorite            = FALSE;
    global.autofiredelay          = 1;

    global.width                  = 640;
    global.height                 = 480;
    global.refreshrate            = 0;
    global.switchres              = TRUE;
    global.window_mode            = FALSE;
    global.monitor                = 0;
    global.brightness             = 100;
    global.autoframeskip          = TRUE;
    global.frameskip              = 0;
    global.rotate                 = ROTATE_NONE;

    global.adjust_aspect          = FALSE;
#ifdef FSSTRETCH
    global.fat_mode               = FALSE;
#endif
    global.double_size            = FALSE;
#ifdef SAI
    global.double_filter          = FALSE;
#endif
    global.hscanlines             = FALSE;
    global.vscanlines             = FALSE;
    global.sl_brightness          = 0;
    global.hw_stretch             = FALSE;
    global.scale                  = 1;
    global.use_triplebuf          = FALSE;
    global.tbvsync                = FALSE;
    global.wait_vsync             = FALSE;
    global.use_hel                = FALSE;
    global.use_sysmem             = FALSE;

    global.stereo                 = TRUE;
    global.sound_delay            = 6;

    global.use_joystick           = FALSE;
    global.use_djoystick          = FALSE;
    global.use_mouse              = TRUE;
    global.di_mouse               = TRUE;
    global.di_keyboard            = TRUE;
    global.di_joystick            = TRUE;
    global.default_input          = INPUT_LAYOUT_STD;
    global.joyid[0]               = 0;
    global.joyid[1]               = 1;
    global.joyid[2]               = 2;
    global.joyid[3]               = 3;

    global.disable_mmx            = TRUE;
    global.disable_mmx2           = TRUE;
    global.disable_pcounter       = FALSE;
    global.use_sleep              = FALSE;
    global.auto_pause             = TRUE;

    global.color_depth            = 0;
    global.screen_depth           = 0;
    global.flipx                  = FALSE;
    global.flipy                  = FALSE;
    global.gamma_correct          = 1.0;

    global.antialias              = TRUE;
    global.translucency           = TRUE;
    global.beam                   = 1.0;
    global.flicker                = 0;

    global.samplerate             = 44100;
    global.use_samples            = TRUE;
    global.use_filter             = TRUE;
    global.force_panpot           = FALSE;
    global.limit_adjust           = FALSE;
    global.format_volume          = FALSE;
    global.auto_adjust            = FALSE;
    global.presoundfix            = FALSE;
    global.sound_type             = 1;
    global.attenuation            = 0;

    global.use_artwork            = TRUE;
    global.cheat                  = FALSE;
    global.mame_debug             = FALSE;
    global.errorlog               = FALSE;
#ifdef NFILTER
    global.nfilter                = FALSE;
#endif
    global.transparency      = FALSE;
    global.transparency_rate = 50;
#ifdef ROMPATCH
    global.patch_roms             = FALSE;
#endif
#ifdef MAME32JP
    global.hiscore_force		= FALSE; // BLACKOUT
    global.hiscore_disable		= FALSE; // BLACKOUT
    global.blackout				= FALSE; // BLACKOUT
    global.autofire_message		= FALSE; // AUTOFIRE_MESSAGE
#endif /* MAME32JP */
	global.bios_type         = NEOGEOBIOS_STANDARD;/* dbg-bios */

    backup = global;

    if (stat("ini", &stat_buffer) != 0)
    {
        mkdir("ini");
        save = 1;
    }
    else
    {
        if (stat("ini/dirs.ini", &stat_buffer) != 0)
        {
            remove(DEFAULT_INI);
            remove(GAMES_INI);
            remove(FOLDERS_INI);
            remove(GUIBACK_INI);
            remove(GAMEBACK_INI);
            save = 1;
        }
    }

    /* This allocation should be checked */
    game = (options_type *)malloc(num_games * sizeof(options_type));

    for (i = 0; i < num_games; i++)
    {
        game[i] = global;
        game[i].use_default = TRUE;
    }

    IniCreate();
    SaveBackupOptions();
    if (save) SaveOptions();
    LoadOptions();
}

void win32_config_exit(void)
{
    SaveOptions();
    free(game);
#ifndef JAPANESE
    free(settings.language);
#endif
    free(directories.rompath);
    free(directories.samplepath);
    free(directories.cfgdir);
#ifdef EXTRA_FOLDER
    free(directories.folderdir);
#endif
    free(directories.hidir);
    free(directories.inpdir);
    free(directories.screenshotdir);
    free(directories.stadir);
    free(directories.artworkdir);
    free(directories.memcarddir);
    free(directories.icondir);
    free(directories.wavedir);
    free(directories.flyerdir);
    free(directories.cabinetdir);
    free(directories.marqueedir);
#ifdef TAB_CONTROLL
    free(directories.titledir);
#endif /* TAB_CONTROLL */
#ifdef RANDAM_BACKGROUND
    free(directories.bgdir);
#endif /* RANDAM_BACKGROUND */
    free(directories.nvdir);
    IniDestroy();
}


/* returns if we should immediately start the game */
int ParseCommandLine(int argc, char *argv[], int game_index, int gui)
{
    BOOL cpu_detect = GetMMXCheck();
    BOOL ignore_badoptions = FALSE;
    int h = 0, w = 0;
    int i, j;
    char buf[500];
    options_type *o, origOpts;

    for (i = 1; i < argc; i++)
    {
        if (argv[i][0] == '-' && argv[i][1] == 'i')
            if (strcmp(argv[i],"-ignorebadoptions") == 0)
                ignore_badoptions = TRUE;
    }

    o = GetGameOptions(game_index);

    memcpy(&origOpts, o, sizeof(options_type));

    for (i = 1; i < argc; i++)
    {
        if (argv[i][0] != '-')
            continue;

        /*--------------------------------------------------------------------*/

        if (sscanf(argv[i], "-%dx%d", &w, &h) == 2
        ||  !stricmp(argv[i], "-resolution") || !stricmp(argv[i], "-r"))
        {
            struct tDisplayModes*   pDisplayModes;
            BOOL                    bFound = FALSE;

            if (!stricmp(argv[i], "-resolution") || !stricmp(argv[i], "-r"))
            {
                if (argc <= ++i)
                    break;

                if (sscanf(argv[i], "%dx%d", &w, &h) != 2)
                    break;
            }

            pDisplayModes = DirectDraw_GetDisplayModes();

            /* Verify that such a mode exists, 8 or 16 bit. */
            for (j = 0; j < pDisplayModes->m_nNumModes; j++)
            {
                if (w == (int)pDisplayModes->m_Modes[j].m_dwWidth
                &&  h == (int)pDisplayModes->m_Modes[j].m_dwHeight)
                {
                    bFound = TRUE;

                    /* Set to FULL_SCREEN */
                    o->width            = w;
                    o->height           = h;
                    o->window_mode      = FALSE;
                    o->switchres        = FALSE;

                    break;
                }
            }

            if (!bFound)
            {
#ifdef JAPANESE
                sprintf(buf, "画面サイズのエラー: %dx%d は対応していません", w, h);
#else
                sprintf(buf, "Error parsing screen size: %dx%d not supported", w, h);
#endif
                MessageBox(NULL, buf, MAME32NAME, MB_OK | MB_ICONERROR);
            }
            continue;
        }

        if (!stricmp(argv[i], "-refreshrate"))
        {
            if (argc <= ++i)
                break;

            o->refreshrate = atoi(argv[i]);
            if (o->refreshrate < 50
            ||  o->refreshrate > 120)
                o->refreshrate = 0; /* auto */
            continue;
        }
        if (!stricmp(argv[i], "-autoframeskip") || !stricmp(argv[i], "-afs"))
        {
            o->autoframeskip = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-noautoframeskip") || !stricmp(argv[i], "-noafs"))
        {
            o->autoframeskip = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-frameskip") || !stricmp(argv[i], "-fs"))
        {
            i++;
            if (i < argc && argv[i][0] != '-')
            {
                int skip = atoi(argv[i]);

                /* the Main mame code allows from 0 to 11 for this value */
                if (skip < 0)  skip = 0;
                if (skip > 12) skip = 11;
                o->frameskip = skip;
                continue;
            }
            else
            {
                i--;
            }
            continue;
        }
        if (!stricmp(argv[i], "-window") || !stricmp(argv[i], "-w"))
        {
            o->window_mode = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-nowindow") || !stricmp(argv[i], "-now"))
        {
            o->window_mode = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-brightness"))
        {
            if (argc <= ++i)
                break;

            o->brightness = atoi(argv[i]);
            continue;
        }
        if (!stricmp(argv[i], "-gamma"))
        {
            double dGamma;

            if (argc <= ++i)
                break;

            dGamma = atof(argv[i]);
            if (0.50 > dGamma || dGamma > 2.00)
                continue;

            o->gamma_correct = dGamma;
            continue;
        }
        if (!stricmp(argv[i], "-bpp"))
        {
            if (argc <= ++i)
                break;

            o->color_depth = atoi(argv[i]);
            if (o->color_depth != 15
            &&  o->color_depth != 16
            &&  o->color_depth != 32
            )
                o->color_depth = 0; /* auto */
            continue;
        }
        if (!stricmp(argv[i], "-screeen_bpp"))
        {
            if (argc <= ++i)
                break;

            o->screen_depth = atoi(argv[i]);
            if (o->screen_depth != 16
            &&  o->screen_depth != 24
            &&  o->screen_depth != 32
            )
                o->screen_depth = 0; /* auto */
            continue;
        }
        if (!stricmp(argv[i], "-norotate"))
        {
            o->rotate   = ROTATE_NONE;
            continue;
        }
        if (!stricmp(argv[i], "-ror"))
        {
            o->rotate   = ROTATE_RIGHT;
            continue;
        }
        if (!stricmp(argv[i], "-rol"))
        {
            o->rotate   = ROTATE_LEFT;
            continue;
        }
        if (!stricmp(argv[i], "-flipx"))
        {
            o->flipx = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-noflipx"))
        {
            o->flipx = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-flipy"))
        {
            o->flipy = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-noflipy"))
        {
            o->flipy = FALSE;
            continue;
        }

        if (!stricmp(argv[i], "-antialias") || !stricmp(argv[i], "-aa"))
        {
            o->antialias = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-noantialias") || !stricmp(argv[i], "-noaa"))
        {
            o->antialias = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-translucency") || !stricmp(argv[i], "-tl"))
        {
            o->translucency = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-notranslucency") || !stricmp(argv[i], "-notl"))
        {
            o->translucency = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-beam"))
        {
            double dBeam;

            if (argc <= ++i)
                break;

            dBeam = atof(argv[i]);
            if (1.00 > dBeam || dBeam > 16.00)
                continue;

            o->beam = dBeam;
            continue;
        }
        if (!stricmp(argv[i], "-flicker"))
        {
            if (argc <= ++i)
                break;

            o->flicker = atoi(argv[i]);
            continue;
        }

        /*--------------------------------------------------------------------*/

        if (!stricmp(argv[i], "-adjustaspect"))
        {
            o->adjust_aspect = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-noadjustaspect"))
        {
            o->adjust_aspect = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-double"))
        {
            o->double_size = TRUE;
#ifdef SAI
            o->double_filter = FALSE;
#endif
            continue;
        }
        if (!stricmp(argv[i], "-nodouble"))
        {
            o->double_size = FALSE;
            continue;
        }
#ifdef SAI
        if (!stricmp(argv[i], "-scale2x"))
        {
            o->double_filter = TRUE;
            o->double_size = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-noscale2x"))
        {
            o->double_filter = FALSE;
            continue;
        }
#endif
        if (!stricmp(argv[i], "-hscanlines") || !stricmp(argv[i], "-sl"))
        {
            o->double_size = TRUE;
#ifdef SAI
            o->double_filter = FALSE;
#endif
            o->hscanlines = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-nohscanlines") || !stricmp(argv[i], "-nosl"))
        {
            o->hscanlines = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-vscanlines"))
        {
            o->double_size = TRUE;
#ifdef SAI
            o->double_filter = FALSE;
#endif
            o->vscanlines = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-novscanlines"))
        {
            o->vscanlines = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-slbrightness"))
        {
            if (argc <= ++i)
                break;

            o->sl_brightness = atoi(argv[i]);
            if (o->sl_brightness != 25
            &&  o->sl_brightness != 50
            &&  o->sl_brightness != 75)
                o->sl_brightness = 0;
            continue;
        }
        if (!stricmp(argv[i], "-stretchscale"))
        {
            if (argc <= ++i)
                break;

            o->scale = atoi(argv[i]);
            if (o->scale < 1 || o->scale > 4)
                o->scale = 1;
            if (o->scale != 1)
                o->hw_stretch = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-triplebuffer") || !stricmp(argv[i], "-tb"))
        {
            o->use_triplebuf = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-notriplebuffer")|| !stricmp(argv[i], "-notb"))
        {
            o->use_triplebuf = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-tbvsync"))
        {
            o->tbvsync = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-notbvsync"))
        {
            o->tbvsync = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-waitvsync"))
        {
            o->wait_vsync = TRUE;
            o->tbvsync    = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-nowaitvsync"))
        {
            o->wait_vsync = FALSE;
            o->tbvsync    = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-sleep"))
        {
            o->use_sleep = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-nosleep"))
        {
            o->use_sleep = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-sysmem"))
        {
            o->use_sysmem = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-nosystem"))
        {
            o->use_sysmem = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-ddrawhel"))
        {
            o->use_hel = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-noddrawhel"))
        {
            o->use_hel = FALSE;
            continue;
        }

        /*--------------------------------------------------------------------*/

        if (!stricmp(argv[i], "-sound"))
        {
            int type;

            if (argc <= ++i)
                break;

            type = atoi(argv[i]);
            if (type >= 0 && type <= 2)
                o->sound_type = type;

            continue;
        }
        if (!stricmp(argv[i], "-samplerate") || !stricmp(argv[i], "-sr"))
        {
            if (argc <= ++i)
                break;

            if (!stricmp(argv[i], "11025"))
                o->samplerate = 0;
            else
            if (!stricmp(argv[i], "22050"))
                o->samplerate = 1;
            else
            if (!stricmp(argv[i], "44100"))
                o->samplerate = 2;
            else
            if (!stricmp(argv[i], "48000"))
                o->samplerate = 3;

            continue;
        }
        if (!stricmp(argv[i], "-sound_delay"))
        {
            int size;

            if (argc <= ++i)
                break;

            size = atoi(argv[i]);
            if (size > 0 && size <= 10)
                o->sound_delay = atoi(argv[i]);
            continue;
        }
        if (!stricmp(argv[i], "-samples"))
        {
            o->use_samples = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-nosamples"))
        {
            o->use_samples = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-resamplefilter"))
        {
            o->use_filter = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-noresamplefilter"))
        {
            o->use_filter = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-volume"))
        {
            int vol;

            if (argc <= ++i)
                break;

            vol = atoi(argv[i]);
            if (-32 <= vol && vol <= 0)
                o->attenuation = - vol;

            continue;
        }
        if (!stricmp(argv[i], "-stereo"))
        {
            o->stereo = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-nostereo"))
        {
            o->stereo = FALSE;
            continue;
        }

        /*--------------------------------------------------------------------*/

        if (!stricmp(argv[i], "-joystick") || !stricmp(argv[i], "-joy"))
        {
            o->use_joystick = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-nojoystick") || !stricmp(argv[i], "-nojoy"))
        {
            o->use_joystick = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-dijoystick"))
        {
            if (DIJoystick.Available())
                o->di_joystick = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-nodijoystick"))
        {
            o->di_joystick = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-joyid1"))
        {
            if (argc <= ++i)
                break;

            o->joyid[0] = atoi(argv[i]);
            if (o->joyid[0] < 0)
                o->joyid[0] = 0;
            continue;
        }
        if (!stricmp(argv[i], "-joyid2"))
        {
            if (argc <= ++i)
                break;

            o->joyid[1] = atoi(argv[i]);
            if (o->joyid[1] < 0)
                o->joyid[1] = 0;
            continue;
        }
        if (!stricmp(argv[i], "-joyid3"))
        {
            if (argc <= ++i)
                break;

            o->joyid[2] = atoi(argv[i]);
            if (o->joyid[2] < 0)
                o->joyid[2] = 0;
            continue;
        }
        if (!stricmp(argv[i], "-joyid4"))
        {
            if (argc <= ++i)
                break;

            o->joyid[3] = atoi(argv[i]);
            if (o->joyid[3] < 0)
                o->joyid[3] = 0;
            continue;
        }
        if (!stricmp(argv[i], "-mouse"))
        {
            o->use_mouse = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-nomouse"))
        {
            o->use_mouse = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-dimouse"))
        {
//          if (DIMouse_Available())
                o->di_mouse = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-nodimouse"))
        {
            o->di_mouse = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-dikeyboard"))
        {
            if (DIKeyboard_Available())
                o->di_keyboard = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-nodikeyboard"))
        {
            o->di_keyboard = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-hotrod"))
        {
            o->default_input = INPUT_LAYOUT_HR;
            continue;
        }
        if (!stricmp(argv[i], "-hotrodse"))
        {
            o->default_input = INPUT_LAYOUT_HRSE;
            continue;
        }

        /*--------------------------------------------------------------------*/

        if (!stricmp(argv[i], "-artwork") || !stricmp(argv[i], "-art"))
        {
            o->use_artwork = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-noartwork") || !stricmp(argv[i], "-noart"))
        {
            o->use_artwork = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-cheat") || !stricmp(argv[i], "-c"))
        {
            o->cheat = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-nocheat") || !stricmp(argv[i], "-noc"))
        {
            o->cheat = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-autopause"))
        {
            o->auto_pause = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-noautopause"))
        {
            o->auto_pause = FALSE;
            continue;
        }
        if (!stricmp(argv[i], "-nommx"))
        {
            o->disable_mmx = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-nommx2"))
        {
            o->disable_mmx2 = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-log"))
        {
            o->errorlog = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-nolog"))
        {
            o->errorlog = FALSE;
            continue;
        }
#ifdef NFILTER
        if (!stricmp(argv[i], "-nonvf"))
        {
            o->nfilter = TRUE;
            continue;
        }
#endif

#ifdef FSSTRETCH
        if (!stricmp(argv[i], "-fatmode"))
        {
            o->fat_mode = TRUE;
            continue;
        }
#endif

        /*--------------------------------------------------------------------*/

#ifdef MAME_DEBUG
        if (!stricmp(argv[i], "-debug") || !stricmp(argv[i], "-d"))
        {
            o->mame_debug = TRUE;
            continue;
        }
        if (!stricmp(argv[i], "-nodebug") || !stricmp(argv[i], "-nod"))
        {
            o->mame_debug = FALSE;
            continue;
        }
#else
        if ((!stricmp(argv[i], "-debug") || !stricmp(argv[i], "-d"))
        ||  (!stricmp(argv[i], "-nodebug") || !stricmp(argv[i], "-nod")))
        {
            continue;
        }
#endif
        if (!stricmp(argv[i], "-nocpudetect"))
        {
            cpu_detect = FALSE;
            continue;
        }

        if (!stricmp(argv[i], "-nogui")
        ||  !stricmp(argv[i], "-joygui")
        ||  !stricmp(argv[i], "-dijoygui")
        ||  !stricmp(argv[i], "-broadcast")
        ||  !stricmp(argv[i], "-nobroadcast"))
            continue;

        /* Let the user decide if they want to contunue
         * if we encounter an Unknown command line option.
         *
         * This allows people who want to use a different
         * front end, to continue to do so.
         *
         * In addition, there is a -ignorebadoptions command
         * line flag.
         */
        if (argv[i][0] == '-' && ignore_badoptions == FALSE)
        {
            char cBuf[200];

#ifdef JAPANESE
            sprintf(cBuf, " '%s' ,は不明なオプションです。続けますか？", argv[i]);
            if (IDNO == MessageBox(0, cBuf, MAME32NAME " - 不明なオプション",
                                   MB_YESNO | MB_ICONQUESTION))
#else
            sprintf(cBuf, "Unknown option '%s', continue anyway?", argv[i]);
            if (IDNO == MessageBox(0, cBuf, MAME32NAME " - Unknown Option",
                                   MB_YESNO | MB_ICONQUESTION))
#endif
            {
                ExitProcess(0);
            }
            else
            {
                ignore_badoptions = TRUE;
            }
            continue;
        }
    }

    if (cpu_detect)
        MAME32App.m_nMMXDetected = MAME32App.DetectMMX();

    if (memcmp(&origOpts, o, sizeof(options_type)) != 0)
        o->use_default = FALSE;

    return TRUE;
}


void SetPlayingGameOptions(int index)
{
    options_type *o = MAME32App.m_Options;
	struct InternalMachineDriver drv;

    memcpy(o, GetGameOptions(index), sizeof(options_type));

    if (!(MAME32App.m_nMMXDetected & 1))
    {
        o->disable_mmx = TRUE;
    }
    if (!(MAME32App.m_nMMXDetected & 2))
    {
        o->disable_mmx2 = TRUE;
    }

    if (!Joystick.Available())
        o->use_joystick = FALSE;

    if (!DIKeyboard_Available())
        o->di_keyboard = FALSE;

    if (!DIJoystick.Available())
        o->di_joystick = FALSE;

    if (!GameUsesTrackball(index))
        o->use_mouse = FALSE;

#ifdef ROMPATCH
    if (!GameUsesRomPatch(index))
        o->patch_roms = FALSE;
#endif

#ifndef JAPANESE
    if (settings.language == NULL || settings.language[0] == '\0')
        options.language_file = NULL;
    else
        options.language_file = osd_fopen(0, settings.language, OSD_FILETYPE_LANGUAGE, 0);
#endif

#ifdef MAME_DEBUG
    options.mame_debug = o->mame_debug ? 1 : 0;
#else
    options.mame_debug = 0;
#endif
    options.cheat      = o->cheat ? 1 : 0;
    options.gui_host   = 1;
    options.game_index = index;

    if (!o->sound_type)
    {
        Machine->sample_rate = 0;
        options.samplerate   = 0;
    }
    else
    {
        options.samplerate = o->samplerate;
    }
    options.use_samples         = o->use_samples;
    options.use_filter          = o->use_filter;
    options.force_panpot        = o->force_panpot;
    options.limit_adjust        = o->limit_adjust;
    options.format_volume       = o->format_volume;
    options.auto_adjust         = o->auto_adjust;
    options.presoundfix         = o->presoundfix;

    options.color_depth = o->color_depth;
    if (o->window_mode == FALSE
    &&  o->switchres   == FALSE)
    {
        options.vector_width  = o->width;
        options.vector_height = o->height;
    }
    else
    {
        options.vector_width  = 0; /* use default */
        options.vector_height = 0; /* use default */
    }

    options.debug_width  = 640;
    options.debug_height = 480;

    options.norotate = 0;

    switch (o->rotate)
    {
    case ROTATE_RIGHT:
        options.ror = 1;
        options.rol = 0;
        break;

    case ROTATE_LEFT:
        options.ror = 0;
        options.rol = 1;
        break;

    default:
        options.ror = 0;
        options.rol = 0;
        break;
    }

    options.flipx = o->flipx;
    options.flipy = o->flipy;

    options.beam   = (int)(o->beam * 0x00010000);
    if (options.beam < 0x00010000)    /* beam MUST be at least 1 pixel */
        options.beam = 0x00010000;
    if (options.beam > 0x00100000)    /* set max to 16 pixels */
        options.beam = 0x00100000;

    options.vector_flicker = o->flicker * 2.55;
    if (options.vector_flicker < 0.0)
        options.vector_flicker = 0.0;
    if (options.vector_flicker > 255.0)
        options.vector_flicker = 255.0;

    options.translucency  = o->translucency;
    options.antialias     = o->antialias;
    options.use_artwork   = o->use_artwork;
    options.savegame      = 0;

    options.autofiredelay = o->autofiredelay;

	expand_machine_driver(drivers[index]->drv, &drv);
    if ((drv.video_attributes & VIDEO_RGB_DIRECT)
    && (!(drv.video_attributes & VIDEO_NEEDS_6BITS_PER_GUN))
    &&  options.color_depth != 32)
        options.color_depth = 15;

    if (o->di_joystick)
        options.use_joystick = 2;
    else if (o->use_joystick)
        options.use_joystick = 1;
    else
        options.use_joystick = 0;

    if (o->use_djoystick)
        options.use_djoystick = 1;
    else
        options.use_djoystick = 0;

#ifdef ROMPATCH
    if (o->patch_roms)
        options.patch_roms = 1;
    else
        options.patch_roms = 0;
#endif
#ifdef MAME32JP
    if (o->hiscore_force)
        options.hiscore_force = 1;
    else
        options.hiscore_force = 0;

    if (o->hiscore_disable)
        options.hiscore_disable = 1;
    else
        options.hiscore_disable = 0;

	options.blackout = o->blackout;					//BLACKOUT
	options.autofire_message = o->autofire_message; //AUTOFIRE_MESSAGE
#endif /* MAME32JP */
	options.bios_type = o->bios_type;/* dbg-bios */
}


options_type *GetDefaultOptions(void)
{
    return &global;
}

options_type *GetGameOptions(int num_game)
{
    int play_count;
    int has_roms;
    int has_samples;
    BOOL is_favorite;
#ifdef MAME32JP
    BOOL autofiredelay;
#endif

    assert(0 <= num_game && num_game < num_games);

    play_count  = game[num_game].play_count;
    has_roms    = game[num_game].has_roms;
    has_samples = game[num_game].has_samples;
    is_favorite = game[num_game].is_favorite;
#ifdef MAME32JP
    autofiredelay = game[num_game].autofiredelay;
#endif

    if (game[num_game].use_default)
    {
        game[num_game]              = global;
        game[num_game].use_default  = TRUE;
        game[num_game].play_count   = play_count;
        game[num_game].has_roms     = has_roms;
        game[num_game].has_samples  = has_samples;
        game[num_game].is_favorite  = is_favorite;
#ifdef MAME32JP
        game[num_game].autofiredelay = autofiredelay;
#endif
    }
    return &game[num_game];
}

void ResetGUI(void)
{
    bResetGUI = TRUE;
}

void SetViewMode(int val)
{
    settings.view = val;
}

int GetViewMode(void)
{
    return settings.view;
}

#ifdef TAB_CONTROLL
void SetHistoryTab(int val)
{
	settings.history_tab = val;
}

int GetHistoryTab(void)
{
	return settings.history_tab;
}
#endif /* TAB_CONTROLL */

void SetGameCheck(BOOL game_check)
{
    settings.game_check = game_check;
}

BOOL GetGameCheck(void)
{
    return settings.game_check;
}

void SetVersionCheck(BOOL version_check)
{
    settings.version_check = version_check;
}

BOOL GetVersionCheck(void)
{
    return settings.version_check;
}

void SetMMXCheck(BOOL mmx_check)
{
    settings.mmx_check = mmx_check;
}

BOOL GetMMXCheck(void)
{
    return settings.mmx_check;
}

#ifdef JOYGUI
void SetJoyGUI(BOOL use_joygui)
{
	settings.use_joygui = use_joygui;
}

BOOL GetJoyGUI(void)
{
	return settings.use_joygui;
}

void SetJoyGUIDI(BOOL use_joygui)
{
	settings.use_joyguidi = use_joygui;
}

BOOL GetJoyGUIDI(void)
{
	return settings.use_joyguidi;
}

void SetDJoyGUI(BOOL use_djoygui)
{
	settings.use_djoygui = use_djoygui;
}

BOOL GetDJoyGUI(void)
{
	return settings.use_djoygui;
}
#endif

#ifdef RANDAM_BACKGROUND
void SetRandomBg(BOOL random_bg)
{
	settings.random_bg = random_bg;
}

BOOL GetRandomBg(void)
{
	return settings.random_bg;
}
#endif /* RANDAM_BACKGROUND */

void SetSavedFolderID(UINT val)
{
    settings.folder_id = val;
}

UINT GetSavedFolderID(void)
{
    return settings.folder_id;
}

void SetShowScreenShot(BOOL val)
{
    settings.show_screenshot = val;
}

BOOL GetShowScreenShot(void)
{
    return settings.show_screenshot;
}

#ifdef TAB_CONTROLL
void SetShowTabCtrl(BOOL val)
{
	settings.show_tabctrl = val;
}

BOOL GetShowTabCtrl(void)
{
	return settings.show_tabctrl;
}
#endif /* TAB_CONTROLL */

void SetShowFolderList(BOOL val)
{
    settings.show_folderlist = val;
}

BOOL GetShowFolderList(void)
{
    return settings.show_folderlist;
}

void SetShowStatusBar(BOOL val)
{
    settings.show_statusbar = val;
}

BOOL GetShowStatusBar(void)
{
    return settings.show_statusbar;
}

void SetShowToolBar(BOOL val)
{
    settings.show_toolbar = val;
}

BOOL GetShowToolBar(void)
{
    return settings.show_toolbar;
}

void SetShowPictType(int val)
{
    settings.show_pict_type = val;
}

int GetShowPictType(void)
{
    return settings.show_pict_type;
}

void SetDefaultGame(const char *name)
{
    strcpy(settings.default_game,name);
}

const char *GetDefaultGame(void)
{
    return settings.default_game;
}

void SetWindowArea(AREA *area)
{
    memcpy(&settings.area, area, sizeof(AREA));
}

void GetWindowArea(AREA *area)
{
    memcpy(area, &settings.area, sizeof(AREA));
}

void SetListFont(LOGFONT *font)
{
    memcpy(&settings.list_font, font, sizeof(LOGFONT));
}

void GetListFont(LOGFONT *font)
{
    memcpy(font, &settings.list_font, sizeof(LOGFONT));
}

void SetListFontColor(COLORREF uColor)
{
    if (settings.list_font_color == GetSysColor(COLOR_WINDOWTEXT))
        settings.list_font_color = (COLORREF)-1;
    else
        settings.list_font_color = uColor;
}

COLORREF GetListFontColor(void)
{
    if (settings.list_font_color == (COLORREF)-1)
        return (GetSysColor(COLOR_WINDOWTEXT));

    return settings.list_font_color;
}

void SetColumnWidths(int width[])
{
    int i;

    for (i = 0; i < COLUMN_MAX; i++)
        settings.column_width[i] = width[i];
}

void GetColumnWidths(int width[])
{
    int i;

    for (i = 0; i < COLUMN_MAX; i++)
        width[i] = settings.column_width[i];
}

void SetSplitterPos(int splitterId, int pos)
{
    if (splitterId < SPLITTER_MAX)
        settings.splitter[splitterId] = pos;
}

int  GetSplitterPos(int splitterId)
{
    if (splitterId < SPLITTER_MAX)
        return settings.splitter[splitterId];

    return -1; /* Error */
}

void SetColumnOrder(int order[])
{
    int i;

    for (i = 0; i < COLUMN_MAX; i++)
        settings.column_order[i] = order[i];
}

void GetColumnOrder(int order[])
{
    int i;

    for (i = 0; i < COLUMN_MAX; i++)
        order[i] = settings.column_order[i];
}

void SetColumnShown(int shown[])
{
    int i;

    for (i = 0; i < COLUMN_MAX; i++)
        settings.column_shown[i] = shown[i];
}

void GetColumnShown(int shown[])
{
    int i;

    for (i = 0; i < COLUMN_MAX; i++)
        shown[i] = settings.column_shown[i];
}

void SetSortColumn(int column)
{
    settings.sort_reverse = (column < 0) ? TRUE : FALSE;
    settings.sort_column  = abs(column) - 1;
}

int GetSortColumn(void)
{
    int column = settings.sort_column + 1;

    if (settings.sort_reverse)
        column = -(column);

    return column;
}

const char *GetRomDirs(void)
{
    return directories.rompath;
}

void SetRomDirs(const char *paths)
{
    if (directories.rompath != NULL)
    {
        free(directories.rompath);
        directories.rompath = NULL;
    }

    if (paths != NULL)
        directories.rompath = strdup(paths);
}

const char *GetSampleDirs(void)
{
    return directories.samplepath;
}

void SetSampleDirs(const char *paths)
{
    if (directories.samplepath != NULL)
    {
        free(directories.samplepath);
        directories.samplepath = NULL;
    }

    if (paths != NULL)
        directories.samplepath = strdup(paths);
}

const char *GetCfgDir(void)
{
    return directories.cfgdir;
}

void SetCfgDir(const char *path)
{
    if (directories.cfgdir != NULL)
    {
        free(directories.cfgdir);
        directories.cfgdir = NULL;
    }

    if (path != NULL)
        directories.cfgdir = strdup(path);
}

#ifdef EXTRA_FOLDER
const char *GetFolderDir(void)
{
    return directories.folderdir;
}

void SetFolderDir(const char *path)
{
    if (directories.folderdir != NULL)
    {
        free(directories.folderdir);
        directories.folderdir = NULL;
    }

    if (path != NULL)
        directories.folderdir = strdup(path);
}
#endif

const char *GetHiDir(void)
{
    return directories.hidir;
}

void SetHiDir(const char *path)
{
    if (directories.hidir != NULL)
    {
        free(directories.hidir);
        directories.hidir = NULL;
    }

    if (path != NULL)
        directories.hidir = strdup(path);
}

const char *GetNvramDir(void)
{
    return directories.nvdir;
}

void SetNvramDir(const char *path)
{
    if (directories.nvdir != NULL)
    {
        free(directories.nvdir);
        directories.nvdir = NULL;
    }

    if (path != NULL)
        directories.nvdir = strdup(path);
}

const char *GetInpDir(void)
{
    return directories.inpdir;
}

void SetInpDir(const char *path)
{
    if (directories.inpdir != NULL)
    {
        free(directories.inpdir);
        directories.inpdir = NULL;
    }

    if (path != NULL)
        directories.inpdir = strdup(path);
}

const char *GetSnapDir(void)
{
    return directories.screenshotdir;
}

void SetSnapDir(const char *path)
{
    if (directories.screenshotdir != NULL)
    {
        free(directories.screenshotdir);
        directories.screenshotdir = NULL;
    }

    if (path != NULL)
        directories.screenshotdir = strdup(path);
}

const char *GetStateDir(void)
{
    return directories.stadir;
}

void SetStateDir(const char *path)
{
    if (directories.stadir != NULL)
    {
        free(directories.stadir);
        directories.stadir = NULL;
    }

    if (path != NULL)
        directories.stadir = strdup(path);
}

const char *GetArtDir(void)
{
    return directories.artworkdir;
}

void SetArtDir(const char *path)
{
    if (directories.artworkdir != NULL)
    {
        free(directories.artworkdir);
        directories.artworkdir = NULL;
    }

    if (path != NULL)
        directories.artworkdir = strdup(path);
}

const char *GetMemcardDir(void)
{
    return directories.memcarddir;
}

void SetMemcardDir(const char *path)
{
    if (directories.memcarddir != NULL)
    {
        free(directories.memcarddir);
        directories.memcarddir = NULL;
    }

    if (path != NULL)
        directories.memcarddir = strdup(path);
}

const char *GetIconDir(void)
{
    return directories.icondir;
}

void SetIconDir(const char *path)
{
    if (directories.icondir != NULL)
    {
        free(directories.icondir);
        directories.icondir = NULL;
    }

    if (path != NULL)
        directories.icondir = strdup(path);
}

const char *GetWaveDir(void)
{
    return directories.wavedir;
}

void SetWaveDir(const char *path)
{
    if (directories.wavedir != NULL)
    {
        free(directories.wavedir);
        directories.wavedir = NULL;
    }

    if (path != NULL)
        directories.wavedir = strdup(path);
}

const char *GetFlyerDir(void)
{
    return directories.flyerdir;
}

void SetFlyerDir(const char *path)
{
    if (directories.flyerdir != NULL)
    {
        free(directories.flyerdir);
        directories.flyerdir = NULL;
    }

    if (path != NULL)
        directories.flyerdir = strdup(path);
}

const char *GetCabinetDir(void)
{
    return directories.cabinetdir;
}

void SetCabinetDir(const char *path)
{
    if (directories.cabinetdir != NULL)
    {
        free(directories.cabinetdir);
        directories.cabinetdir = NULL;
    }

    if (path != NULL)
        directories.cabinetdir = strdup(path);
}

const char *GetDiffDir(void)
{
    return directories.diffdir;
}

void SetDiffDir(const char *path)
{
    if (directories.diffdir != NULL)
    {
        free(directories.diffdir);
        directories.diffdir = NULL;
    }

    if (path != NULL)
        directories.diffdir = strdup(path);
}

const char *GetCtrlrDir(void)
{
    return directories.ctrlrdir;
}

void SetCtrlrDir(const char *path)
{
    if (directories.ctrlrdir != NULL)
    {
        free(directories.ctrlrdir);
        directories.ctrlrdir = NULL;
    }

    if (path != NULL)
        directories.ctrlrdir = strdup(path);
}

const char *GetMarqueeDir(void)
{
    return directories.marqueedir;
}

void SetMarqueeDir(const char *path)
{
    if (directories.marqueedir != NULL)
    {
        free(directories.marqueedir);
        directories.marqueedir = NULL;
    }

    if (path != NULL)
        directories.marqueedir = strdup(path);
}

#ifdef TAB_CONTROLL
const char *GetTitleDir(void)
{
    return directories.titledir;
}

void SetTitleDir(const char *path)
{
    if (directories.titledir != NULL)
    {
        free(directories.titledir);
        directories.titledir = NULL;
    }

    if (path != NULL)
        directories.titledir = strdup(path);
}
#endif /* TAB_CONTROLL */

#ifdef RANDAM_BACKGROUND
const char* GetBgDir(void)
{
	return directories.bgdir;
}

void SetBgDir(const char* path)
{
    if (directories.bgdir != NULL)
    {
	free(directories.bgdir);
        directories.bgdir = NULL;
    }

	if (path != NULL)
		directories.bgdir = strdup (path);
}
#endif /* RANDAM_BACKGROUND */

#ifndef JAPANESE
const char* GetLanguage(void)
{
    return settings.language;
}

void SetLanguage(const char* lang)
{
    if (settings.language != NULL)
    {
        free(settings.language);
        settings.language = NULL;
    }

    if (lang != NULL)
        settings.language = strdup(lang);
}
#endif

void ResetGameOptions(int num_game)
{
    int play_count;
    int has_roms;
    int has_samples;

    assert(0 <= num_game && num_game < num_games);

    play_count  = game[num_game].play_count;
    has_roms    = game[num_game].has_roms;
    has_samples = game[num_game].has_samples;

    game[num_game]              = global;
    game[num_game].use_default  = TRUE;
    game[num_game].play_count   = play_count;
    game[num_game].has_roms     = has_roms;
    game[num_game].has_samples  = has_samples;
#ifdef MAME32JP
    game[num_game].autofiredelay = 1;
#endif
}

void ResetGameDefaults(void)
{
    bResetGameDefs = TRUE;
}

void ResetAllGameOptions(void)
{
    int i;

    for (i = 0; i < num_games; i++)
        ResetGameOptions(i);
}

int GetHasRoms(int num_game)
{
    assert(0 <= num_game && num_game < num_games);

    return game[num_game].has_roms;
}

void SetHasRoms(int num_game, int has_roms)
{
    assert(0 <= num_game && num_game < num_games);

    game[num_game].has_roms = has_roms;
}

int  GetHasSamples(int num_game)
{
    assert(0 <= num_game && num_game < num_games);

    return game[num_game].has_samples;
}

void SetHasSamples(int num_game, int has_samples)
{
    assert(0 <= num_game && num_game < num_games);

    game[num_game].has_samples = has_samples;
}

int GetIsFavorite(int num_game)
{
    assert(0 <= num_game && num_game < num_games);

    return game[num_game].is_favorite;
}

void SetIsFavorite(int num_game, int is_favorite)
{
    assert(0 <= num_game && num_game < num_games);

    game[num_game].is_favorite = is_favorite;
}

void IncrementPlayCount(int num_game)
{
    assert(0 <= num_game && num_game < num_games);

    game[num_game].play_count++;
}

void SetFolderFlags(char *folderName, DWORD dwFlags)
{
    SaveFolderFlags(folderName, dwFlags);
}

int GetPlayCount(int num_game)
{
    assert(0 <= num_game && num_game < num_games);

    return game[num_game].play_count;
}

char *GetVersionString(void)
{
    return build_version;
}

BOOL GameUsesTrackball(int game_index)
{
    int port;

    /* new trackball support */
    if (drivers[game_index]->input_ports != 0)
    {
        port = 0;
        while (drivers[game_index]->input_ports[port].type != IPT_END)
        {
            int type = drivers[game_index]->input_ports[port].type & ~IPF_MASK;
            if (type == IPT_DIAL
            ||  type == IPT_PADDLE
            ||  type == IPT_TRACKBALL_X
            ||  type == IPT_TRACKBALL_Y
            ||  type == IPT_AD_STICK_X
            ||  type == IPT_AD_STICK_Y)
            {
                return TRUE;
            }
            port++;
        }
        return FALSE;
    }
    return FALSE;
}

#ifdef JAPANESE
BOOL UseJapaneseList(void)
{
    return settings.use_japanese_list;
}

void SetUseJapaneseList(BOOL is_use)
{
    settings.use_japanese_list = is_use;
}

BOOL UseModifyThe(void)
{
    return settings.modify_the;
}

void SetUseModifyThe(BOOL is_use)
{
    settings.modify_the = is_use;
}
#endif
BOOL Use60HzVsync(void)
{
    return settings.vsync_60;
}

void SetUse60HzVsync(BOOL is_use)
{
    settings.vsync_60 = is_use;
}

BOOL UseTilemapMMX(void)
{
    return settings.tilemap_mmx;
}

void SetUseTilemapMMX(BOOL bUse)
{
    settings.tilemap_mmx = bUse;
}

#ifdef KAILLERA
void SetNetPlayFolder(BOOL bUseFavorite)
{
    settings.use_netplay_folder = bUseFavorite;
}

BOOL GetNetPlayFolder(void)
{
    return settings.use_netplay_folder;
}

BOOL GetUseImeInChat(void)
{
    return settings.use_ime_in_chat;
}

void SetUseImeInChat(BOOL bUseIME)
{
    settings.use_ime_in_chat = bUseIME;
}

BOOL GetChatDrawMode(void)
{
    return settings.chat_draw_mode;
}

void SetChatDrawMode(int nMode)
{
    settings.chat_draw_mode = nMode;
}
#endif /* KAILLERA */

/***************************************************************************
    Internal functions
 ***************************************************************************/

static void LoadOptions(void)
{
    char temp[80];
    char *linebuf;
    FILE *fp;

    linebuf = malloc(LINEBUF_SIZE);
    if (linebuf == NULL)
        return;

    fp = fopen(DEFAULT_INI, "r");
    if (fp == NULL)
    {
        free(linebuf);
        return;
    }

    IniReset();
    if (IniReadDefaultFile(fp, linebuf) == TRUE)
    {
        LoadIniSettingsOptions(temp);

        if (!bResetGUI && settings.version_check)
        {
            if (strcmp(temp, build_version) != 0)
            {
                char msg[400];

#ifdef JAPANESE
                char *oldInfoMsg = MAME32NAME " は、古い設定情報を検出しました。\n\n"
                                   "検出した情報は、" MAME32NAME " バージョン %s のものです。\n"
                                   "現在のバージョンは %s です。\n"
                                   "現在のバージョンによる新しいデフォルト設定を使用することを推奨します。\n\n"
                                   "新しい設定を使用しますか？";
#else
                char *oldInfoMsg = MAME32NAME " has detected outdated configuration data.\n\n"
                                   "The detected configuration data is from Version %s of " MAME32NAME ".\n"
                                   "The current version is %s. It is recommended that the\n"
                                   "configuration is set to the new defaults.\n\n"
                                   "Would you like to use the new configuration?";
#endif

                sprintf(msg, oldInfoMsg, temp, build_version);
#ifdef JAPANESE
                if (MessageBox(0, msg, MAME32NAME " - バージョンの相違", MB_YESNO | MB_ICONQUESTION) == IDYES)
#else
                if (MessageBox(0, msg, "Version Mismatch", MB_YESNO | MB_ICONQUESTION) == IDYES)
#endif
                {
                    bResetGUI = TRUE;
                    bResetGameDefs = TRUE;
                }
            }
        }

        if (bResetGUI)
        {
            fclose(fp);

            fp = fopen(GUIBACK_INI, "r");
            if (fp)
            {
                IniReset();
                if (IniReadDefaultFile(fp, linebuf) == TRUE)
                    LoadIniSettingsOptions(temp);
            }
        }

        if (settings.list_font_color != -1)
        {
            if (settings.list_font_color == GetSysColor(COLOR_WINDOWTEXT))
                settings.list_font_color = (COLORREF)-1;
        }

        LoadIniGameOptions(&global);
    }
    fclose(fp);

    fp = fopen(DIRECTORIES_INI, "r");
    if (fp == NULL)
    {
        free(linebuf);
        return;
    }

    IniReset();
    if (IniReadDefaultFile(fp, linebuf) == TRUE)
        LoadIniDirectoriesOptions();
    fclose(fp);

    fp = fopen(GAMES_INI, "r");
    if (fp == NULL)
    {
        free(linebuf);
        return;
    }

    IniReadFile(fp, linebuf);
    fclose(fp);

    free(linebuf);
}


static void SaveOptions(void)
{
    FILE  *fp;
    int   i;

    fp = fopen(DIRECTORIES_INI, "w");
    if (fp)
    {
        IniReset();
        SaveIniDirectoriesOptions();
        IniWriteFile(fp, "directories");
        fclose(fp);
    }

    fp = fopen(DEFAULT_INI, "w");
    if (fp)
    {
        IniReset();
        SaveIniSettingsOptions();
        global.use_default = FALSE;
        SaveIniGameOptions(&global);
        IniWriteFile(fp, "default");
        fclose(fp);
    }

    fp = fopen(GAMES_INI, "w");
    if (fp)
    {
        for (i = 0; drivers[i]; i++)
        {
            IniReset();
            SaveIniGameOptions(&game[i]);
            IniWriteFile(fp, drivers[i]->name);
        }
        fclose(fp);
    }
}


static void SaveBackupOptions(void)
{
    FILE  *fp;

    fp = fopen(GUIBACK_INI, "w");
    if (fp)
    {
        IniReset();
        SaveIniSettingsOptions();
        IniWriteFile(fp, "default");
        fclose(fp);
    }

    fp = fopen(GAMEBACK_INI, "w");
    if (fp)
    {
        global.use_default = FALSE;
        IniReset();
        SaveIniGameOptions(&global);
        IniWriteFile(fp, "default");
        fclose(fp);
    }
}


DWORD GetFolderFlags(char *folderName)
{
    FILE  *fp;
    char  *linebuf;
    char  value[16];
    DWORD size;
    DWORD flags = 0;

    fp = fopen(FOLDERS_INI, "r");
    if (fp)
    {
        linebuf = malloc(LINEBUF_SIZE);
        if (linebuf)
        {
            IniReset();
            IniReadFile(fp, linebuf);
            free(linebuf);

            if (IniQueryValue(folderName, NULL, &size) == ERROR_SUCCESS)
            {
                if (IniQueryValue(folderName, value, &size) == ERROR_SUCCESS)
                    sscanf(value, "%08lX", &flags);
            }
        }
        fclose(fp);
    }

    return flags;
}

static void SaveFolderFlags(char *folderName, DWORD dwFlags)
{
    FILE *fp;
    char  *linebuf;
    char  value[16];
    int   i, check;

    sprintf(value, "%08lX", dwFlags);

    IniReset();

    fp = fopen(FOLDERS_INI, "r");
    if (fp)
    {
        linebuf = malloc(LINEBUF_SIZE);
        if (linebuf)
        {
            IniReadFile(fp, linebuf);
            free(linebuf);
        }
        fclose(fp);
    }

    fp = fopen(FOLDERS_INI, "w");
    if (fp)
    {
        IniSetValue(folderName, value, strlen(value));
        IniWriteFile(fp, "folders");
        fclose(fp);
    }

    check = 0;
    for (i = 0; ini[i].value; i++)
        check |= atoi(ini[i].value) ? 1 : 0;

    if (check == 0)
        remove(FOLDERS_INI);
}

void SaveGameOptions(int game_num)
{
    FILE  *fp;
    int   i;

    fp = fopen(GAMES_INI, "w");
    if (fp)
    {
        for (i = 0; drivers[i]; i++)
        {
            IniReset();
            SaveIniGameOptions(&game[i]);
            IniWriteFile(fp, drivers[i]->name);
        }
        fclose(fp);
    }
}

void SaveDefaultOptions(void)
{
    FILE  *fp;

    fp = fopen(DEFAULT_INI, "w");
    if (fp)
    {
        IniReset();
        SaveIniSettingsOptions();

        global.use_default = FALSE;

        SaveIniGameOptions(&global);
        IniWriteFile(fp, "default");
        fclose(fp);
    }
}

static void SaveIniDirectoriesOptions(void)
{
    int i;

    for (i = 0; i < NUM_DIRECTORIES; i++)
        PutIniObj(&iniDirectories[i]);
}

static void LoadIniDirectoriesOptions(void)
{
    int i;

    for (i = 0; i < NUM_DIRECTORIES; i++)
        GetIniObj(&iniDirectories[i]);
}

static void SaveIniSettingsOptions(void)
{
    int i;

    PutIniStringOption("SaveVersion", GetVersionString());
    PutIniBoolOption("VersionCheck", settings.version_check);
    PutIniOption("FontColor", settings.list_font_color);
    PutIniBoolOption("ResetGUI", bResetGUI);
    PutIniBoolOption("ResetGameDefaults", bResetGameDefs);

    for (i = 0; i < NUM_SETTINGS; i++)
        PutIniObj(&iniSettings[i]);
}

static void LoadIniSettingsOptions(char *szVersion)
{
    int i;

    strcpy(szVersion, GetIniStringOption("SaveVersion"));
    settings.version_check   = GetIniBoolOption("VersionCheck");
    bResetGUI                = GetIniBoolOption("ResetGUI");
    bResetGameDefs           = GetIniBoolOption("ResetGameDefaults");
    settings.list_font_color = GetIniOption("FontColor");

    for (i = 0; i < NUM_SETTINGS; i++)
        GetIniObj(&iniSettings[i]);
}

static void SaveIniGameOptions(options_type *o)
{
    int i;

    if (o->use_default == TRUE)
        IniReset();

    PutIniOption("PlayCount", o->play_count);
    PutIniOption("HasRoms", o->has_roms);
    PutIniOption("HasSamples", o->has_samples);
    PutIniBoolOption("Favorite", o->is_favorite);
#ifdef MAME32JP
    PutIniOption("AutofireDelay", o->autofiredelay);
#endif

    if (o->use_default == TRUE)
        return;

    gOpts = *o;

    for (i = 0; i < NUM_GAMEOPTS; i++)
        PutIniObj(&iniGameOpts[i]);
}

static void LoadIniGameOptions(options_type *o)
{
    int   i;
    DWORD value;
    DWORD size;

    if ((value = GetIniOption("PlayCount")) != -1)
        o->play_count = value;
    else
        o->play_count = 0;
    if ((value = GetIniOption("HasRoms")) != -1)
        o->has_roms = value;
    else
        o->has_roms = 0;
    if ((value = GetIniOption("HasSamples")) != -1)
        o->has_samples = value;
    else
        o->has_samples = 0;
    o->is_favorite = GetIniBoolOption("Favorite");
#ifdef MAME32JP
    if ((value = GetIniOption("AutofireDelay")) != -1)
        o->autofiredelay = value;
    else
        o->autofiredelay = 1;
#endif

    if (IniQueryValue("AutoFrameSkip", &value, &size) != ERROR_SUCCESS)
       return;

    o->use_default = FALSE;

    gOpts = *o;

    for (i = 0; i < NUM_GAMEOPTS; i++)
        GetIniObj(&iniGameOpts[i]);

    /* copy options back out */
    *o = gOpts;
}

static DWORD GetIniOption(char *name)
{
    char *ptr;
    DWORD value = -1;

    ptr = GetIniStringOption(name);
    if (ptr != NULL)
        value = atoi(ptr);

    return value;
}

static BOOL GetIniBoolOption(char *name)
{
    char *ptr;
    BOOL value = FALSE;

    ptr = GetIniStringOption(name);
    if (ptr != NULL)
        value = (*ptr == '0') ? FALSE : TRUE;

    return value;
}

static char *GetIniStringOption(char *name)
{
    DWORD dwSize;
    static char str[LINEBUF_SIZE];

    if (IniQueryValue(name, NULL, &dwSize) != ERROR_SUCCESS)
        return NULL;

    IniQueryValue(name, str, &dwSize);

    return str;
}

static void PutIniOption(char *name, DWORD value)
{
    char str[16];

    sprintf(str, "%ld", value);

    IniSetValue(name, (void *)&str, strlen(str));
}

static void PutIniBoolOption(char *name, BOOL value)
{
    char str[2];

    str[0] = (value) ? '1' : '0';
    str[1] = '\0';

    IniSetValue(name, (void *)str, 2);
}

static void PutIniStringOption(char *name, char *option)
{
    IniSetValue(name, (void *)option, strlen(option));
}

static void GetIniObj(INI_OPTIONS *iniOpts)
{
    char    *cName = iniOpts->m_cName;
    char    *pString;
    double  *pDouble;

    switch(iniOpts->m_iType)
    {
    case IO_DOUBLE:
        pDouble = (double *)iniOpts->m_vpData;
        if ((pString = GetIniStringOption(cName)) != NULL)
            sscanf(pString, "%lf", pDouble);
        break;

    case IO_BOOL:
        *(BOOL *)iniOpts->m_vpData = GetIniBoolOption(cName);
        break;

    case IO_INT:
        *(int *)iniOpts->m_vpData = GetIniOption(cName);
        break;

    case IO_STRING:
        if ((pString = GetIniStringOption(cName)) != NULL)
            strcpy((char *)iniOpts->m_vpData, pString);
        break;

    case IO_PSTRING:
        if ((pString = GetIniStringOption(cName)) != NULL)
        {
            if (*(char **)iniOpts->m_vpData != NULL)
                free(*(char **)iniOpts->m_vpData);
            *(char **)iniOpts->m_vpData = strdup(pString);
        }
        break;

    case IO_ENCODE:
        if ((pString = GetIniStringOption(cName)) != NULL)
            iniOpts->decode(pString, iniOpts->m_vpData);
        break;

    default:
        break;
    }
}

static void PutIniObj(INI_OPTIONS *iniOpt)
{
    char    *pString;
    double  *pDouble;
    char    *cName = iniOpt->m_cName;
    char    cTemp[80];

    switch (iniOpt->m_iType)
    {
    case IO_DOUBLE:
        pDouble = (double *)iniOpt->m_vpData;
        sprintf(cTemp, "%03.02f", *pDouble);
        PutIniStringOption(cName, cTemp);
        break;

    case IO_BOOL:
        PutIniBoolOption(cName, *(BOOL *)iniOpt->m_vpData);
        break;

    case IO_INT:
        PutIniOption(cName, *(int *)iniOpt->m_vpData);
        break;

    case IO_STRING:
        pString = (char *)iniOpt->m_vpData;
        if (pString)
            PutIniStringOption(cName, pString);
        break;

    case IO_PSTRING:
        pString = *(char **)iniOpt->m_vpData;
        if (pString)
            PutIniStringOption(cName, pString);
        break;

    case IO_ENCODE:
        iniOpt->encode(iniOpt->m_vpData, cTemp);
        PutIniStringOption(cName, cTemp);
        break;

    default:
        break;
    }
}

/*********************************************************************/

static void ColumnEncodeString(void *data, char *str)
{
    int *value = (int *)data;
    int  i;
    char tmpStr[100];

    sprintf(tmpStr, "%d", value[0]);

    strcpy(str, tmpStr);

    for (i = 1; i < COLUMN_MAX; i++)
    {
        sprintf(tmpStr, ",%d", value[i]);
        strcat(str, tmpStr);
    }
}

static void ColumnDecodeString(const char *str, void *data)
{
    int *value = (int *)data;
    int  i;
    char *s, *p;
    char tmpStr[100];

    if (str == NULL)
        return;

    strcpy(tmpStr, str);
    p = tmpStr;

    for (i = 0; p && i < COLUMN_MAX; i++)
    {
        s = p;

        if ((p = strchr(s,',')) != NULL && *p == ',')
        {
            *p = '\0';
            p++;
        }
        value[i] = atoi(s);
    }
}

static void ColumnDecodeWidths(const char *str, void *data)
{
    if (settings.view == VIEW_REPORT)
        ColumnDecodeString(str, data);
}

static void SplitterEncodeString(void *data, char *str)
{
    int *value = (int *)data;
    int  i;
    char tmpStr[100];

    sprintf(tmpStr, "%d", value[0]);

    strcpy(str, tmpStr);

    for (i = 1; i < SPLITTER_MAX; i++)
    {
        sprintf(tmpStr, ",%d", value[i]);
        strcat(str, tmpStr);
    }
}

static void SplitterDecodeString(const char *str, void *data)
{
    int *value = (int *)data;
    int  i;
    char *s, *p;
    char tmpStr[100];

    if (str == NULL)
        return;

    strcpy(tmpStr, str);
    p = tmpStr;

    for (i = 0; p && i < SPLITTER_MAX; i++)
    {
        s = p;

        if ((p = strchr(s,',')) != NULL && *p == ',')
        {
            *p = '\0';
            p++;
        }
        value[i] = atoi(s);
    }
}

static void ListDecodeString(const char *str, void *data)
{
    int *value = (int *)data;
    int i;

    *value = VIEW_REPORT;

    for (i = VIEW_LARGE_ICONS; i < VIEW_MAX; i++)
    {
        if (strcmp(str, view_modes[i]) == 0)
        {
            *value = i;
            return;
        }
    }
}

static void ListEncodeString(void *data, char *str)
{
    int *value = (int *)data;

    strcpy(str, view_modes[*value]);
}

/* Parse the given comma-delimited string into a LOGFONT structure */
static void FontDecodeString(const char *str, void *data)
{
    LOGFONT *f = (LOGFONT *)data;
    char *ptr;
    int n[8];

    sscanf(str, "%ld,%ld,%ld,%ld,%ld,%i,%i,%i,%i,%i,%i,%i,%i",
           &f->lfHeight,
           &f->lfWidth,
           &f->lfEscapement,
           &f->lfOrientation,
           &f->lfWeight,
           &n[0], &n[1], &n[2], &n[3],
           &n[4], &n[5], &n[6], &n[7]);

    f->lfItalic         = (BYTE)n[0];
    f->lfUnderline      = (BYTE)n[1];
    f->lfStrikeOut      = (BYTE)n[2];
    f->lfCharSet        = (BYTE)n[3];
    f->lfOutPrecision   = (BYTE)n[4];
    f->lfClipPrecision  = (BYTE)n[5];
    f->lfQuality        = (BYTE)n[6];
    f->lfPitchAndFamily = (BYTE)n[7];

    ptr = strrchr(str, ',');
    if (ptr != NULL)
        strcpy(f->lfFaceName, ptr + 1);
}

/* Encode the given LOGFONT structure into a comma-delimited string */
static void FontEncodeString(void *data, char *str)
{
    LOGFONT* f = (LOGFONT*)data;

    sprintf(str, "%ld,%ld,%ld,%ld,%ld,%i,%i,%i,%i,%i,%i,%i,%i,%s",
            f->lfHeight,
            f->lfWidth,
            f->lfEscapement,
            f->lfOrientation,
            f->lfWeight,
            (int)f->lfItalic,
            (int)f->lfUnderline,
            (int)f->lfStrikeOut,
            (int)f->lfCharSet,
            (int)f->lfOutPrecision,
            (int)f->lfClipPrecision,
            (int)f->lfQuality,
            (int)f->lfPitchAndFamily,
            f->lfFaceName);
}

/***************************************************************************/

static BOOL IniCreate(void)
{
    int i;

    ini = (ini_struct *)malloc(sizeof(ini_struct) * INI_MAX_ENTRIES);
    if (ini == NULL)
        return FALSE;

    for (i = 0; i < INI_MAX_ENTRIES; i++)
    {
        ini[i].name  = NULL;
        ini[i].value = NULL;
    }

    return TRUE;
}

static void IniDestroy(void)
{
    int i;

    if (ini == NULL)
        return;

    for (i = 0; i < INI_MAX_ENTRIES; i++)
    {
        if (ini[i].name)  free(ini[i].name);
        if (ini[i].value) free(ini[i].value);
    }

    free(ini);
    ini = NULL;
}

static void IniReset(void)
{
    int i;

    if (ini == NULL)
        return;

    for (i = 0; i < INI_MAX_ENTRIES; i++)
    {
        if (ini[i].name)  free(ini[i].name);
        if (ini[i].value) free(ini[i].value);

        ini[i].name  = NULL;
        ini[i].value = NULL;
    }
}

static BOOL IniReadDefaultFile(FILE *fp, char *linebuf)
{
    char *name;
    char *value;
    BOOL found = FALSE;

    while (fgets(linebuf, LINEBUF_SIZE, fp))
    {
        if (linebuf[0] == '[')
        {
            char *p = strchr(linebuf, ']');
            if (p != NULL) *p = '\0';
            if (strcmp("default", &linebuf[1]) == 0)
            {
                found = TRUE;
                break;
            }
            if (strcmp("directories", &linebuf[1]) == 0)
            {
                found = TRUE;
                break;
            }
        }
    }

    if (found == FALSE)
        return FALSE;

    while (fgets(linebuf, LINEBUF_SIZE, fp))
    {
        if (linebuf[0] == '[')
            break;

        if (linebuf[0] == ';')
            continue;

        name = strtok(linebuf, "=\r\n");
        if (name == NULL)
            continue;

        value = strtok(NULL, "=\r\n");

        IniSetValue(name, value, strlen(value));
    }

    return TRUE;
}


static void IniReadFile(FILE *fp, char *linebuf)
{
    char *name;
    char *value;
    char *p;
    int  index = -1;

    while (fgets(linebuf, LINEBUF_SIZE, fp))
    {
        if (linebuf[0] == '[')
        {
            if (index != -1)
                LoadIniGameOptions(&game[index]);

            p = strchr(linebuf, ']');
            if (p == NULL)
                continue;

            *p = '\0';
            index = GetIndexByName(&linebuf[1]);
            IniReset();
            continue;
        }

        if (linebuf[0] == ';')
            continue;

        name = strtok(linebuf, "=\r\n");
        if (name == NULL)
            continue;

        value = strtok(NULL, "=\r\n");

        IniSetValue(name, value, strlen(value));
    }

    if (index != -1)
        LoadIniGameOptions(&game[index]);
}


static void IniWriteFile(FILE *fp, const char *keyname)
{
    int   i, j;
    DWORD size;
    char  saved[INI_MAX_ENTRIES];

    memset(saved, 0, INI_MAX_ENTRIES);

    fprintf(fp, "[%s]\n", keyname);

    if (IniQueryValue("AutoFrameSkip", NULL, &size) == ERROR_SUCCESS)
    {
        for (i = 0; i < NUM_GAMEOPTS; i++)
        {
            for (j = 0; ini[j].name; j++)
            {
                if (saved[j]) continue;

                if (strcmp(iniGameOpts[i].m_cName, ini[j].name) == 0)
                {
                    fprintf(fp, "%s=%s\n", ini[j].name, ini[j].value);
                    saved[j] = 1;
                }
            }
        }
    }

    if (IniQueryValue("DefaultGame", NULL, &size) == ERROR_SUCCESS)
    {
        for (i = 0; i < NUM_SETTINGS; i++)
        {
            for (j = 0; ini[j].name; j++)
            {
                if (saved[j]) continue;

                if (strcmp(iniSettings[i].m_cName, ini[j].name) == 0)
                {
                    fprintf(fp, "%s=%s\n", ini[j].name, ini[j].value);
                    saved[j] = 1;
                }
            }
        }
    }

    if (IniQueryValue("rompath", NULL, &size) == ERROR_SUCCESS)
    {
        for (i = 0; i < NUM_DIRECTORIES; i++)
        {
            for (j = 0; ini[j].name; j++)
            {
                if (saved[j]) continue;

                if (strcmp(iniDirectories[i].m_cName, ini[j].name) == 0)
                {
                    fprintf(fp, "%s=%s\n", ini[j].name, ini[j].value);
                    saved[j] = 1;
                }
            }
        }
    }

    for (i = 0; ini[i].name; i++)
    {
        if (!saved[i])
            fprintf(fp, "%s=%s\n", ini[i].name, ini[i].value);
    }

    fprintf(fp, "\n");
}


static long IniQueryValue(const char *name, void *value, DWORD *size)
{
    int i;

    for (i = 0; ini[i].name; i++)
    {
        if (strcmp(name, ini[i].name) == 0)
        {
            if (value == NULL)
            {
                *size = strlen(ini[i].value);
                return ERROR_SUCCESS;
            }
            else
            {
                if (ini[i].value)
                {
                    strcpy(value, ini[i].value);
                    return ERROR_SUCCESS;
                }
                else
                    return !ERROR_SUCCESS;
            }
        }
    }

    return !ERROR_SUCCESS;
}


static void IniSetValue(const char *name, void *value, DWORD size)
{
    int i;
    BOOL found = FALSE;

    for (i = 0; ini[i].name; i++)
    {
        if (strcmp(name, ini[i].name) == 0)
        {
            found = TRUE;
            break;
        }
    }

    if (!found)
    {
        ini[i].name = malloc(strlen(name) + 1);
        strcpy(ini[i].name, name);
    }

    ini[i].value = realloc(ini[i].value, size + 1);
    strcpy(ini[i].value, value);
}


INLINE int GetIndexByName(const char *name)
{
    int i;

    for (i = 0; drivers[i]; i++)
    {
        if (strcmp(name, drivers[i]->name) == 0)
            return i;
    }
    return -1;
}
