mirror of
https://github.com/CTCaer/RetroArch.git
synced 2025-01-09 04:21:33 +00:00
commit
f604d7e377
@ -122,6 +122,9 @@ void autosave_unlock(autosave_t *handle)
|
||||
|
||||
void autosave_free(autosave_t *handle)
|
||||
{
|
||||
if (!handle)
|
||||
return;
|
||||
|
||||
slock_lock(handle->cond_lock);
|
||||
handle->quit = true;
|
||||
slock_unlock(handle->cond_lock);
|
||||
@ -139,7 +142,7 @@ void autosave_free(autosave_t *handle)
|
||||
void lock_autosave(void)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < ARRAY_SIZE(g_extern.autosave); i++)
|
||||
for (i = 0; i < g_extern.num_autosave; i++)
|
||||
{
|
||||
if (g_extern.autosave[i])
|
||||
autosave_lock(g_extern.autosave[i]);
|
||||
@ -149,7 +152,7 @@ void lock_autosave(void)
|
||||
void unlock_autosave(void)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < ARRAY_SIZE(g_extern.autosave); i++)
|
||||
for (i = 0; i < g_extern.num_autosave; i++)
|
||||
{
|
||||
if (g_extern.autosave[i])
|
||||
autosave_unlock(g_extern.autosave[i]);
|
||||
|
@ -8,7 +8,7 @@ retroarch \- The reference frontend for the libretro API.
|
||||
|
||||
.SH SYNOPSIS
|
||||
|
||||
\fBretroarch\fR [rom file] [OPTIONS]...
|
||||
\fBretroarch\fR [rom file(s)] [OPTIONS]...
|
||||
|
||||
.SH "DESCRIPTION"
|
||||
|
||||
@ -117,28 +117,11 @@ Multiple config files are delimited by ','.
|
||||
Every config file will be appended in order where the key-value pairs of the next config file takes priority over the old ones.
|
||||
|
||||
.TP
|
||||
\fB--gameboy PATH, -g PATH\fR
|
||||
Path to a Nintendo Game Boy ROM. If this flag is set, the Super Game Boy subsystem will be activated. The Super Game Boy BIOS needs to be loaded as the normal rom.
|
||||
|
||||
.TP
|
||||
\fB--bsx PATH, -b PATH\fR
|
||||
Path to BS-X rom. Load BS-X BIOS as the regular rom.
|
||||
When using BS-X, save ram paths will be inferred from the BS-X BIOS path, not BS-X rom path.
|
||||
|
||||
.TP
|
||||
\fB--bsxslot PATH, -B PATH\fR
|
||||
Path to BS-X slotted rom. Load BS-X BIOS as the regular rom.
|
||||
When using BS-X, save ram paths will be inferred from the BS-X BIOS path, not BS-X rom path.
|
||||
|
||||
.TP
|
||||
\fB--sufamiA PATH\fR
|
||||
Path to A slot in Sufami Turbo. Load Sufami Turbo BIOS as regular rom.
|
||||
When using Sufami, save ram paths will be inferred from the Sufami BIOS path, not slot paths.
|
||||
|
||||
.TP
|
||||
\fB--sufamiB PATH\fR
|
||||
Path to B slot in Sufami Turbo. Load Sufami Turbo BIOS as regular rom.
|
||||
When using Sufami, save ram paths will be inferred from the Sufami BIOS path, not slot paths.
|
||||
\fB--subsystem SUBSYSTEM\fR
|
||||
Use a subsystem of the loaded libretro core. Multiple ROMs are loaded as multiple arguments.
|
||||
If a ROM is skipped, use a blank ("") command line argument.
|
||||
ROMs must be loaded in an order which depends on the particular subsystem used.
|
||||
See verbose log output to learn how a particular subsystem wants ROMs to be loaded.
|
||||
|
||||
.TP
|
||||
\fB--mouse PORT, -m PORT\fR
|
||||
|
44
dynamic.c
44
dynamic.c
@ -185,6 +185,21 @@ void libretro_free_system_info(struct retro_system_info *info)
|
||||
memset(info, 0, sizeof(*info));
|
||||
}
|
||||
|
||||
const struct retro_subsystem_info *libretro_find_subsystem_info(const struct retro_subsystem_info *info, unsigned num_info,
|
||||
const char *ident)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < num_info; i++)
|
||||
{
|
||||
if (!strcmp(info[i].ident, ident))
|
||||
return &info[i];
|
||||
else if (!strcmp(info[i].desc, ident)) // Doesn't hurt
|
||||
return &info[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool find_first_libretro(char *path, size_t size,
|
||||
const char *dir, const char *rom_path)
|
||||
{
|
||||
@ -417,6 +432,7 @@ void uninit_libretro_sym(void)
|
||||
}
|
||||
|
||||
// No longer valid.
|
||||
free(g_extern.system.special);
|
||||
memset(&g_extern.system, 0, sizeof(g_extern.system));
|
||||
#ifdef HAVE_CAMERA
|
||||
g_extern.camera_active = false;
|
||||
@ -914,6 +930,34 @@ bool rarch_environment_cb(unsigned cmd, void *data)
|
||||
return driver_update_system_av_info((const struct retro_system_av_info*)data);
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO:
|
||||
{
|
||||
RARCH_LOG("Environ SET_SUBSYSTEM_INFO.\n");
|
||||
unsigned i, j;
|
||||
const struct retro_subsystem_info *info = (const struct retro_subsystem_info*)data;
|
||||
for (i = 0; info[i].ident; i++)
|
||||
{
|
||||
RARCH_LOG("Special game type: %s\n", info[i].desc);
|
||||
RARCH_LOG(" Ident: %s\n", info[i].ident);
|
||||
RARCH_LOG(" ID: %u\n", info[i].id);
|
||||
RARCH_LOG(" ROMs:\n");
|
||||
for (j = 0; j < info[i].num_roms; j++)
|
||||
{
|
||||
RARCH_LOG(" %s (%s)\n",
|
||||
info[i].roms[j].desc, info[i].roms[j].required ? "required" : "optional");
|
||||
}
|
||||
}
|
||||
|
||||
free(g_extern.system.special);
|
||||
g_extern.system.special = (struct retro_subsystem_info*)calloc(i, sizeof(*g_extern.system.special));
|
||||
if (!g_extern.system.special)
|
||||
return false;
|
||||
|
||||
memcpy(g_extern.system.special, info, i * sizeof(*g_extern.system.special));
|
||||
g_extern.system.num_special = i;
|
||||
break;
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_EXEC:
|
||||
case RETRO_ENVIRONMENT_EXEC_ESCAPE:
|
||||
|
||||
|
@ -64,6 +64,8 @@ void libretro_free_system_info(struct retro_system_info *info);
|
||||
// Transforms a library id to a name suitable as a pathname.
|
||||
void libretro_get_current_core_pathname(char *name, size_t size);
|
||||
|
||||
const struct retro_subsystem_info *libretro_find_subsystem_info(const struct retro_subsystem_info *info, unsigned num_info, const char *ident);
|
||||
|
||||
extern void (*pretro_init)(void);
|
||||
extern void (*pretro_deinit)(void);
|
||||
|
||||
|
350
file.c
350
file.c
@ -143,35 +143,8 @@ static ssize_t read_rom_file(const char *path, void **buf)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static const char *ramtype2str(int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case RETRO_MEMORY_SAVE_RAM:
|
||||
case RETRO_MEMORY_SNES_GAME_BOY_RAM:
|
||||
case RETRO_MEMORY_SNES_BSX_RAM:
|
||||
return ".srm";
|
||||
|
||||
case RETRO_MEMORY_RTC:
|
||||
case RETRO_MEMORY_SNES_GAME_BOY_RTC:
|
||||
return ".rtc";
|
||||
|
||||
case RETRO_MEMORY_SNES_BSX_PRAM:
|
||||
return ".pram";
|
||||
|
||||
case RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM:
|
||||
return ".aram";
|
||||
case RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM:
|
||||
return ".bram";
|
||||
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to save valuable RAM data somewhere ...
|
||||
static void dump_to_file_desperate(const void *data, size_t size, int type)
|
||||
static void dump_to_file_desperate(const void *data, size_t size, unsigned type)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
const char *base = getenv("APPDATA");
|
||||
@ -185,14 +158,13 @@ static void dump_to_file_desperate(const void *data, size_t size, int type)
|
||||
goto error;
|
||||
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, sizeof(path), "%s/RetroArch-recovery-", base);
|
||||
snprintf(path, sizeof(path), "%s/RetroArch-recovery-%u", base, type);
|
||||
char timebuf[PATH_MAX];
|
||||
|
||||
time_t time_;
|
||||
time(&time_);
|
||||
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d-%H-%M-%S", localtime(&time_));
|
||||
strlcat(path, timebuf, sizeof(path));
|
||||
strlcat(path, ramtype2str(type), sizeof(path));
|
||||
|
||||
if (write_file(path, data, size))
|
||||
RARCH_WARN("Succeeded in saving RAM data to \"%s\".\n", path);
|
||||
@ -231,6 +203,13 @@ bool save_state(const char *path)
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct sram_block
|
||||
{
|
||||
unsigned type;
|
||||
void *data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
bool load_state(const char *path)
|
||||
{
|
||||
unsigned i;
|
||||
@ -248,75 +227,55 @@ bool load_state(const char *path)
|
||||
bool ret = true;
|
||||
RARCH_LOG("State size: %u bytes.\n", (unsigned)size);
|
||||
|
||||
void *block_buf[2] = {NULL, NULL};
|
||||
int block_type[2] = {-1, -1};
|
||||
size_t block_size[2] = {0};
|
||||
struct sram_block *blocks = NULL;
|
||||
unsigned num_blocks = 0;
|
||||
|
||||
if (g_settings.block_sram_overwrite)
|
||||
if (g_settings.block_sram_overwrite && g_extern.savefiles && g_extern.savefiles->size)
|
||||
{
|
||||
RARCH_LOG("Blocking SRAM overwrite.\n");
|
||||
switch (g_extern.game_type)
|
||||
blocks = (struct sram_block*)calloc(g_extern.savefiles->size, sizeof(*blocks));
|
||||
if (blocks)
|
||||
{
|
||||
case RARCH_CART_NORMAL:
|
||||
block_type[0] = RETRO_MEMORY_SAVE_RAM;
|
||||
block_type[1] = RETRO_MEMORY_RTC;
|
||||
break;
|
||||
|
||||
case RARCH_CART_BSX:
|
||||
case RARCH_CART_BSX_SLOTTED:
|
||||
block_type[0] = RETRO_MEMORY_SNES_BSX_RAM;
|
||||
block_type[1] = RETRO_MEMORY_SNES_BSX_PRAM;
|
||||
break;
|
||||
|
||||
case RARCH_CART_SUFAMI:
|
||||
block_type[0] = RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM;
|
||||
block_type[1] = RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM;
|
||||
break;
|
||||
|
||||
case RARCH_CART_SGB:
|
||||
block_type[0] = RETRO_MEMORY_SNES_GAME_BOY_RAM;
|
||||
block_type[1] = RETRO_MEMORY_SNES_GAME_BOY_RTC;
|
||||
break;
|
||||
num_blocks = g_extern.savefiles->size;
|
||||
for (i = 0; i < num_blocks; i++)
|
||||
blocks[i].type = g_extern.savefiles->elems[i].attr.i;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
if (block_type[i] != -1)
|
||||
block_size[i] = pretro_get_memory_size(block_type[i]);
|
||||
for (i = 0; i < num_blocks; i++)
|
||||
blocks[i].size = pretro_get_memory_size(blocks[i].type);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
if (block_size[i])
|
||||
block_buf[i] = malloc(block_size[i]);
|
||||
for (i = 0; i < num_blocks; i++)
|
||||
if (blocks[i].size)
|
||||
blocks[i].data = malloc(blocks[i].size);
|
||||
|
||||
// Backup current SRAM which is overwritten by unserialize.
|
||||
for (i = 0; i < 2; i++)
|
||||
for (i = 0; i < num_blocks; i++)
|
||||
{
|
||||
if (block_buf[i])
|
||||
if (blocks[i].data)
|
||||
{
|
||||
const void *ptr = pretro_get_memory_data(block_type[i]);
|
||||
const void *ptr = pretro_get_memory_data(blocks[i].type);
|
||||
if (ptr)
|
||||
memcpy(block_buf[i], ptr, block_size[i]);
|
||||
memcpy(blocks[i].data, ptr, blocks[i].size);
|
||||
}
|
||||
}
|
||||
|
||||
ret = pretro_unserialize(buf, size);
|
||||
|
||||
// Flush back :D
|
||||
for (i = 0; i < 2 && ret; i++)
|
||||
for (i = 0; i < num_blocks; i++)
|
||||
{
|
||||
if (block_buf[i])
|
||||
if (blocks[i].data)
|
||||
{
|
||||
void *ptr = pretro_get_memory_data(block_type[i]);
|
||||
void *ptr = pretro_get_memory_data(blocks[i].type);
|
||||
if (ptr)
|
||||
memcpy(ptr, block_buf[i], block_size[i]);
|
||||
memcpy(ptr, blocks[i].data, blocks[i].size);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
if (block_buf[i])
|
||||
free(block_buf[i]);
|
||||
|
||||
free(buf);
|
||||
for (i = 0; i < num_blocks; i++)
|
||||
free(blocks[i].data);
|
||||
free(blocks);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -362,175 +321,164 @@ void save_ram_file(const char *path, int type)
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_ROMS 4
|
||||
|
||||
static bool load_roms(unsigned rom_type, const char **rom_paths, size_t roms)
|
||||
static bool load_roms(const struct retro_subsystem_info *special, const struct string_list *roms)
|
||||
{
|
||||
size_t i;
|
||||
unsigned i;
|
||||
bool ret = true;
|
||||
|
||||
if (roms == 0)
|
||||
struct retro_game_info *info = (struct retro_game_info*)calloc(roms->size, sizeof(*info));
|
||||
if (!info)
|
||||
return false;
|
||||
|
||||
if (roms > MAX_ROMS)
|
||||
return false;
|
||||
|
||||
void *rom_buf[MAX_ROMS] = {NULL};
|
||||
long rom_len[MAX_ROMS] = {0};
|
||||
struct retro_game_info info[MAX_ROMS] = {{NULL}};
|
||||
|
||||
if (!g_extern.system.info.need_fullpath)
|
||||
for (i = 0; i < roms->size; i++)
|
||||
{
|
||||
RARCH_LOG("Loading ROM file: %s.\n", rom_paths[0]);
|
||||
if ((rom_len[0] = read_rom_file(rom_paths[0], &rom_buf[0])) == -1)
|
||||
const char *path = roms->elems[i].data;
|
||||
int attr = roms->elems[i].attr.i;
|
||||
|
||||
bool need_fullpath = attr & 2;
|
||||
bool require_rom = attr & 4;
|
||||
|
||||
if (require_rom && !*path)
|
||||
{
|
||||
RARCH_ERR("Could not read ROM file.\n");
|
||||
RARCH_LOG("libretro core requires a ROM, but none were provided.\n");
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
RARCH_LOG("ROM size: %u bytes.\n", (unsigned)rom_len[0]);
|
||||
}
|
||||
else
|
||||
RARCH_LOG("ROM loading skipped. Implementation will load it on its own.\n");
|
||||
info[i].path = *path ? path : NULL;
|
||||
|
||||
info[0].path = rom_paths[0];
|
||||
info[0].data = rom_buf[0];
|
||||
info[0].size = rom_len[0];
|
||||
info[0].meta = NULL; // Not relevant at this moment.
|
||||
|
||||
for (i = 1; i < roms; i++)
|
||||
{
|
||||
if (rom_paths[i] &&
|
||||
!g_extern.system.info.need_fullpath &&
|
||||
(rom_len[i] = read_file(rom_paths[i], &rom_buf[i])) == -1)
|
||||
if (!need_fullpath && *path) // Load the ROM into memory.
|
||||
{
|
||||
RARCH_ERR("Could not read ROM file: \"%s\".\n", rom_paths[i]);
|
||||
ret = false;
|
||||
goto end;
|
||||
RARCH_LOG("Loading ROM file: %s.\n", path);
|
||||
// First ROM is significant, attempt to do patching, CRC checking, etc ...
|
||||
long size = i == 0 ? read_rom_file(path, (void**)&info[i].data) : read_file(path, (void**)&info[i].data);
|
||||
if (size < 0)
|
||||
{
|
||||
RARCH_ERR("Could not read ROM file \"%s\".\n", path);
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
info[i].size = size;
|
||||
}
|
||||
|
||||
info[i].path = rom_paths[i];
|
||||
info[i].data = rom_buf[i];
|
||||
info[i].size = rom_len[i];
|
||||
info[i].meta = NULL;
|
||||
else
|
||||
RARCH_LOG("ROM loading skipped. Implementation will load it on its own.\n");
|
||||
}
|
||||
|
||||
if (rom_type == 0)
|
||||
ret = pretro_load_game(&info[0]);
|
||||
if (special)
|
||||
ret = pretro_load_game_special(special->id, info, roms->size);
|
||||
else
|
||||
ret = pretro_load_game_special(rom_type, info, roms);
|
||||
ret = pretro_load_game(*roms->elems[0].data ? info : NULL);
|
||||
|
||||
if (!ret)
|
||||
RARCH_ERR("Failed to load game.\n");
|
||||
|
||||
end:
|
||||
for (i = 0; i < MAX_ROMS; i++)
|
||||
free(rom_buf[i]);
|
||||
for (i = 0; i < roms->size; i++)
|
||||
free((void*)info[i].data);
|
||||
free(info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool load_normal_rom(void)
|
||||
bool init_rom_file(void)
|
||||
{
|
||||
if (g_extern.libretro_no_rom && g_extern.system.no_game)
|
||||
return pretro_load_game(NULL);
|
||||
else if (g_extern.libretro_no_rom && !g_extern.system.no_game)
|
||||
{
|
||||
RARCH_ERR("No ROM is used, but libretro core does not support this.\n");
|
||||
unsigned i;
|
||||
|
||||
g_extern.temporary_roms = string_list_new();
|
||||
if (!g_extern.temporary_roms)
|
||||
return false;
|
||||
|
||||
const struct retro_subsystem_info *special = NULL;
|
||||
|
||||
if (*g_extern.subsystem)
|
||||
{
|
||||
special = libretro_find_subsystem_info(g_extern.system.special, g_extern.system.num_special,
|
||||
g_extern.subsystem);
|
||||
|
||||
if (!special)
|
||||
{
|
||||
RARCH_ERR("Failed to find subsystem \"%s\" in libretro implementation.\n",
|
||||
g_extern.subsystem);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (special->num_roms && !g_extern.subsystem_fullpaths)
|
||||
{
|
||||
RARCH_ERR("libretro core requires special ROMs, but none were provided.\n");
|
||||
return false;
|
||||
}
|
||||
else if (special->num_roms && special->num_roms != g_extern.subsystem_fullpaths->size)
|
||||
{
|
||||
RARCH_ERR("libretro core requires %u ROMs for subsystem \"%s\", but %u ROMs were provided.\n", special->num_roms, special->desc,
|
||||
(unsigned)g_extern.subsystem_fullpaths->size);
|
||||
return false;
|
||||
}
|
||||
else if (!special->num_roms && g_extern.subsystem_fullpaths && g_extern.subsystem_fullpaths->size)
|
||||
{
|
||||
RARCH_ERR("libretro core takes no ROMs for subsystem \"%s\", but %u ROMs were provided.\n", special->desc,
|
||||
(unsigned)g_extern.subsystem_fullpaths->size);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
union string_list_elem_attr attr;
|
||||
struct string_list *roms = string_list_new();
|
||||
if (!roms)
|
||||
return false;
|
||||
|
||||
if (*g_extern.subsystem)
|
||||
{
|
||||
for (i = 0; i < g_extern.subsystem_fullpaths->size; i++)
|
||||
{
|
||||
attr.i = special->roms[i].block_extract;
|
||||
attr.i |= special->roms[i].need_fullpath << 1;
|
||||
attr.i |= special->roms[i].required << 2;
|
||||
string_list_append(roms, g_extern.subsystem_fullpaths->elems[i].data, attr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *path = g_extern.fullpath;
|
||||
return load_roms(0, &path, 1);
|
||||
attr.i = g_extern.system.info.block_extract;
|
||||
attr.i |= g_extern.system.info.need_fullpath << 1;
|
||||
attr.i |= (!g_extern.system.no_game) << 2;
|
||||
string_list_append(roms, g_extern.libretro_no_rom ? "" : g_extern.fullpath, attr);
|
||||
}
|
||||
}
|
||||
|
||||
static bool load_sgb_rom(void)
|
||||
{
|
||||
const char *path[2] = {
|
||||
*g_extern.fullpath ? g_extern.fullpath : NULL,
|
||||
g_extern.gb_rom_path
|
||||
};
|
||||
|
||||
return load_roms(RETRO_GAME_TYPE_SUPER_GAME_BOY, path, 2);
|
||||
}
|
||||
|
||||
static bool load_bsx_rom(bool slotted)
|
||||
{
|
||||
const char *path[2] = {
|
||||
*g_extern.fullpath ? g_extern.fullpath : NULL,
|
||||
g_extern.bsx_rom_path
|
||||
};
|
||||
|
||||
return load_roms(slotted ? RETRO_GAME_TYPE_BSX_SLOTTED : RETRO_GAME_TYPE_BSX, path, 2);
|
||||
}
|
||||
|
||||
static bool load_sufami_rom(void)
|
||||
{
|
||||
const char *path[3] = {
|
||||
*g_extern.fullpath ? g_extern.fullpath : NULL,
|
||||
*g_extern.sufami_rom_path[0] ? g_extern.sufami_rom_path[0] : NULL,
|
||||
*g_extern.sufami_rom_path[1] ? g_extern.sufami_rom_path[1] : NULL,
|
||||
};
|
||||
|
||||
return load_roms(RETRO_GAME_TYPE_SUFAMI_TURBO, path, 3);
|
||||
}
|
||||
|
||||
bool init_rom_file(enum rarch_game_type type)
|
||||
{
|
||||
#ifdef HAVE_ZLIB
|
||||
if (*g_extern.fullpath && !g_extern.system.block_extract)
|
||||
// Try to extract every ROM we're going to load if appropriate.
|
||||
for (i = 0; i < roms->size; i++)
|
||||
{
|
||||
const char *ext = path_get_extension(g_extern.fullpath);
|
||||
// block extract check
|
||||
if (roms->elems[i].attr.i & 1)
|
||||
continue;
|
||||
|
||||
const char *ext = path_get_extension(roms->elems[i].data);
|
||||
|
||||
const char *valid_ext = special ?
|
||||
special->roms[i].valid_extensions :
|
||||
g_extern.system.info.valid_extensions;
|
||||
|
||||
if (ext && !strcasecmp(ext, "zip"))
|
||||
{
|
||||
g_extern.rom_file_temporary = true;
|
||||
|
||||
if (!zlib_extract_first_rom(g_extern.fullpath, sizeof(g_extern.fullpath), g_extern.system.valid_extensions))
|
||||
char temporary_rom[PATH_MAX];
|
||||
strlcpy(temporary_rom, roms->elems[i].data, sizeof(temporary_rom));
|
||||
if (!zlib_extract_first_rom(temporary_rom, sizeof(temporary_rom), valid_ext,
|
||||
*g_settings.extraction_directory ? g_settings.extraction_directory : NULL))
|
||||
{
|
||||
RARCH_ERR("Failed to extract ROM from zipped file: %s.\n", g_extern.fullpath);
|
||||
g_extern.rom_file_temporary = false;
|
||||
RARCH_ERR("Failed to extract ROM from zipped file: %s.\n", temporary_rom);
|
||||
string_list_free(roms);
|
||||
return false;
|
||||
}
|
||||
|
||||
strlcpy(g_extern.last_rom, g_extern.fullpath, sizeof(g_extern.last_rom));
|
||||
string_list_set(roms, i, temporary_rom);
|
||||
string_list_append(g_extern.temporary_roms, temporary_rom, attr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case RARCH_CART_SGB:
|
||||
if (!load_sgb_rom())
|
||||
return false;
|
||||
break;
|
||||
|
||||
case RARCH_CART_NORMAL:
|
||||
if (!load_normal_rom())
|
||||
return false;
|
||||
break;
|
||||
|
||||
case RARCH_CART_BSX:
|
||||
if (!load_bsx_rom(false))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case RARCH_CART_BSX_SLOTTED:
|
||||
if (!load_bsx_rom(true))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case RARCH_CART_SUFAMI:
|
||||
if (!load_sufami_rom())
|
||||
return false;
|
||||
break;
|
||||
|
||||
default:
|
||||
RARCH_ERR("Invalid ROM type.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
// Set attr to need_fullpath as appropriate.
|
||||
|
||||
bool ret = load_roms(special, roms);
|
||||
string_list_free(roms);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
2
file.h
2
file.h
@ -36,7 +36,7 @@ bool save_state(const char *path);
|
||||
void load_ram_file(const char *path, int type);
|
||||
void save_ram_file(const char *path, int type);
|
||||
|
||||
bool init_rom_file(enum rarch_game_type type);
|
||||
bool init_rom_file(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -308,6 +308,7 @@ end:
|
||||
struct zip_extract_userdata
|
||||
{
|
||||
char *zip_path;
|
||||
const char *extraction_directory;
|
||||
size_t zip_path_size;
|
||||
struct string_list *ext;
|
||||
bool found_rom;
|
||||
@ -323,8 +324,13 @@ static bool zip_extract_cb(const char *name, const uint8_t *cdata, unsigned cmod
|
||||
if (ext && string_list_find_elem(data->ext, ext))
|
||||
{
|
||||
char new_path[PATH_MAX];
|
||||
fill_pathname_resolve_relative(new_path, data->zip_path,
|
||||
path_basename(name), sizeof(new_path));
|
||||
|
||||
if (data->extraction_directory)
|
||||
fill_pathname_join(new_path, data->extraction_directory,
|
||||
path_basename(name), sizeof(new_path));
|
||||
else
|
||||
fill_pathname_resolve_relative(new_path, data->zip_path,
|
||||
path_basename(name), sizeof(new_path));
|
||||
|
||||
switch (cmode)
|
||||
{
|
||||
@ -350,7 +356,8 @@ static bool zip_extract_cb(const char *name, const uint8_t *cdata, unsigned cmod
|
||||
return true;
|
||||
}
|
||||
|
||||
bool zlib_extract_first_rom(char *zip_path, size_t zip_path_size, const char *valid_exts)
|
||||
bool zlib_extract_first_rom(char *zip_path, size_t zip_path_size, const char *valid_exts,
|
||||
const char *extraction_directory)
|
||||
{
|
||||
bool ret;
|
||||
struct zip_extract_userdata userdata = {0};
|
||||
@ -369,6 +376,7 @@ bool zlib_extract_first_rom(char *zip_path, size_t zip_path_size, const char *va
|
||||
|
||||
userdata.zip_path = zip_path;
|
||||
userdata.zip_path_size = zip_path_size;
|
||||
userdata.extraction_directory = extraction_directory;
|
||||
userdata.ext = list;
|
||||
|
||||
if (!zlib_parse_file(zip_path, zip_extract_cb, &userdata))
|
||||
|
@ -30,7 +30,7 @@ typedef bool (*zlib_file_cb)(const char *name,
|
||||
bool zlib_parse_file(const char *file, zlib_file_cb file_cb, void *userdata);
|
||||
|
||||
// Built with zlib_parse_file.
|
||||
bool zlib_extract_first_rom(char *zip_path, size_t zip_path_size, const char *valid_exts);
|
||||
bool zlib_extract_first_rom(char *zip_path, size_t zip_path_size, const char *valid_exts, const char *extraction_dir);
|
||||
struct string_list *zlib_get_file_list(const char *path);
|
||||
|
||||
bool zlib_inflate_data_to_file(const char *path, const uint8_t *data,
|
||||
|
@ -211,6 +211,12 @@ bool string_list_append(struct string_list *list, const char *elem, union string
|
||||
return true;
|
||||
}
|
||||
|
||||
void string_list_set(struct string_list *list, unsigned index, const char *str)
|
||||
{
|
||||
free(list->elems[index].data);
|
||||
rarch_assert(list->elems[index].data = strdup(str));
|
||||
}
|
||||
|
||||
void string_list_join_concat(char *buffer, size_t size, const struct string_list *list, const char *sep)
|
||||
{
|
||||
size_t len = strlen(buffer);
|
||||
|
@ -61,6 +61,7 @@ struct string_list *string_list_new(void);
|
||||
bool string_list_append(struct string_list *list, const char *elem, union string_list_elem_attr attr);
|
||||
void string_list_free(struct string_list *list);
|
||||
void string_list_join_concat(char *buffer, size_t size, const struct string_list *list, const char *sep);
|
||||
void string_list_set(struct string_list *list, unsigned index, const char *str);
|
||||
|
||||
bool path_is_directory(const char *path);
|
||||
bool path_file_exists(const char *path);
|
||||
|
@ -244,12 +244,7 @@ void menu_rom_history_push_current(void)
|
||||
|
||||
char tmp[PATH_MAX];
|
||||
|
||||
// We loaded a zip, and fullpath points to the extracted file.
|
||||
// Look at basename instead.
|
||||
if (g_extern.rom_file_temporary)
|
||||
snprintf(tmp, sizeof(tmp), "%s.zip", g_extern.basename);
|
||||
else
|
||||
strlcpy(tmp, g_extern.fullpath, sizeof(tmp));
|
||||
strlcpy(tmp, g_extern.fullpath, sizeof(tmp));
|
||||
|
||||
if (*tmp)
|
||||
path_resolve_realpath(tmp, sizeof(tmp));
|
||||
|
36
general.h
36
general.h
@ -286,6 +286,8 @@ struct settings
|
||||
char screenshot_directory[PATH_MAX];
|
||||
char system_directory[PATH_MAX];
|
||||
|
||||
char extraction_directory[PATH_MAX];
|
||||
|
||||
bool rewind_enable;
|
||||
size_t rewind_buffer_size;
|
||||
unsigned rewind_granularity;
|
||||
@ -316,15 +318,6 @@ struct settings
|
||||
bool core_specific_config;
|
||||
};
|
||||
|
||||
enum rarch_game_type
|
||||
{
|
||||
RARCH_CART_NORMAL = 0,
|
||||
RARCH_CART_SGB,
|
||||
RARCH_CART_BSX,
|
||||
RARCH_CART_BSX_SLOTTED,
|
||||
RARCH_CART_SUFAMI
|
||||
};
|
||||
|
||||
typedef struct rarch_resolution
|
||||
{
|
||||
unsigned idx;
|
||||
@ -358,9 +351,8 @@ struct global
|
||||
#endif
|
||||
bool force_fullscreen;
|
||||
|
||||
bool rom_file_temporary;
|
||||
char last_rom[PATH_MAX];
|
||||
enum rarch_game_type game_type;
|
||||
struct string_list *temporary_roms;
|
||||
|
||||
uint32_t cart_crc;
|
||||
|
||||
char gb_rom_path[PATH_MAX];
|
||||
@ -386,11 +378,15 @@ struct global
|
||||
|
||||
char basename[PATH_MAX];
|
||||
char fullpath[PATH_MAX];
|
||||
char savefile_name_srm[PATH_MAX];
|
||||
char savefile_name_rtc[PATH_MAX]; // Make sure that fill_pathname has space.
|
||||
char savefile_name_psrm[PATH_MAX];
|
||||
char savefile_name_asrm[PATH_MAX];
|
||||
char savefile_name_bsrm[PATH_MAX];
|
||||
|
||||
// A list of save types and associated paths for all ROMs.
|
||||
struct string_list *savefiles;
|
||||
|
||||
// For --subsystem ROMs.
|
||||
char subsystem[256];
|
||||
struct string_list *subsystem_fullpaths;
|
||||
|
||||
char savefile_name[PATH_MAX];
|
||||
char savestate_name[PATH_MAX];
|
||||
|
||||
// Used on reentrancy to use a savestate dir.
|
||||
@ -448,6 +444,9 @@ struct global
|
||||
retro_usec_t frame_time_last;
|
||||
|
||||
core_option_manager_t *core_options;
|
||||
|
||||
struct retro_subsystem_info *special;
|
||||
unsigned num_special;
|
||||
} system;
|
||||
|
||||
struct
|
||||
@ -563,7 +562,8 @@ struct global
|
||||
unsigned turbo_count;
|
||||
|
||||
// Autosave support.
|
||||
autosave_t *autosave[2];
|
||||
autosave_t **autosave;
|
||||
unsigned num_autosave;
|
||||
|
||||
// Netplay.
|
||||
#ifdef HAVE_NETPLAY
|
||||
|
@ -115,6 +115,21 @@ void retro_set_environment(retro_environment_t cb)
|
||||
|
||||
if (!cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &logging))
|
||||
logging.log = fallback_log;
|
||||
|
||||
static const struct retro_subsystem_memory_info mem1[] = {{ "ram1", 0x400 }, { "ram2", 0x401 }};
|
||||
static const struct retro_subsystem_memory_info mem2[] = {{ "ram3", 0x402 }, { "ram4", 0x403 }};
|
||||
|
||||
static const struct retro_subsystem_rom_info roms[] = {
|
||||
{ "Test Rom #1", "bin", false, false, true, mem1, 2, },
|
||||
{ "Test Rom #2", "bin", false, false, true, mem2, 2, },
|
||||
};
|
||||
|
||||
static const struct retro_subsystem_info types[] = {
|
||||
{ "Foo", "foo", roms, 2, 0x200, },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
cb(RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO, (void*)types);
|
||||
}
|
||||
|
||||
void retro_set_audio_sample(retro_audio_sample_t cb)
|
||||
@ -370,10 +385,11 @@ unsigned retro_get_region(void)
|
||||
|
||||
bool retro_load_game_special(unsigned type, const struct retro_game_info *info, size_t num)
|
||||
{
|
||||
(void)type;
|
||||
(void)info;
|
||||
(void)num;
|
||||
return false;
|
||||
if (type != 0x200)
|
||||
return false;
|
||||
if (num != 2)
|
||||
return false;
|
||||
return retro_load_game(NULL);
|
||||
}
|
||||
|
||||
size_t retro_serialize_size(void)
|
||||
|
68
libretro.h
68
libretro.h
@ -162,7 +162,7 @@ extern "C" {
|
||||
|
||||
// Regular save ram. This ram is usually found on a game cartridge, backed up by a battery.
|
||||
// If save game data is too complex for a single memory buffer,
|
||||
// the SYSTEM_DIRECTORY environment callback can be used.
|
||||
// the SAVE_DIRECTORY (preferably) or SYSTEM_DIRECTORY environment callback can be used.
|
||||
#define RETRO_MEMORY_SAVE_RAM 0
|
||||
|
||||
// Some games have a built-in clock to keep track of time.
|
||||
@ -175,21 +175,6 @@ extern "C" {
|
||||
// Video ram lets a frontend peek into a game systems video RAM (VRAM).
|
||||
#define RETRO_MEMORY_VIDEO_RAM 3
|
||||
|
||||
// Special memory types.
|
||||
#define RETRO_MEMORY_SNES_BSX_RAM ((1 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_BSX_PRAM ((2 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM ((3 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM ((4 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_GAME_BOY_RAM ((5 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_GAME_BOY_RTC ((6 << 8) | RETRO_MEMORY_RTC)
|
||||
|
||||
// Special game types passed into retro_load_game_special().
|
||||
// Only used when multiple ROMs are required.
|
||||
#define RETRO_GAME_TYPE_BSX 0x101
|
||||
#define RETRO_GAME_TYPE_BSX_SLOTTED 0x102
|
||||
#define RETRO_GAME_TYPE_SUFAMI_TURBO 0x103
|
||||
#define RETRO_GAME_TYPE_SUPER_GAME_BOY 0x104
|
||||
|
||||
// Keysyms used for ID in input state callback when polling RETRO_KEYBOARD.
|
||||
enum retro_key
|
||||
{
|
||||
@ -614,9 +599,58 @@ enum retro_mod
|
||||
// e.g. for cases where the frontend wants to call directly into the core.
|
||||
//
|
||||
// If a core wants to expose this interface, SET_PROC_ADDRESS_CALLBACK **MUST** be called from within retro_set_environment().
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO 34
|
||||
// const struct retro_subsystem_info * --
|
||||
// This environment call introduces the concept of libretro "subsystems".
|
||||
// A subsystem is a variant of a libretro core which supports different kinds of games.
|
||||
// The purpose of this is to support e.g. emulators which might have special needs, e.g. Super Nintendos Super GameBoy, Sufami Turbo.
|
||||
// It can also be used to pick among subsystems in an explicit way if the libretro implementation is a multi-system emulator itself.
|
||||
//
|
||||
// Loading a game via a subsystem is done with retro_load_game_special(),
|
||||
// and this environment call allows a libretro core to expose which subsystems are supported for use with retro_load_game_special().
|
||||
// A core passes an array of retro_game_special_info which is terminated with a zeroed out retro_game_special_info struct.
|
||||
//
|
||||
// If a core wants to use this functionality, SET_SPECIAL_GAME_TYPES **MUST** be called from within retro_set_environment().
|
||||
|
||||
struct retro_subsystem_memory_info
|
||||
{
|
||||
const char *extension; // The extension associated with a memory type, e.g. "psram".
|
||||
unsigned type; // The memory type for retro_get_memory(). This should be at least 0x100 to avoid conflict with standardized libretro memory types.
|
||||
};
|
||||
|
||||
struct retro_subsystem_rom_info
|
||||
{
|
||||
const char *desc; // Describes what the ROM is (SGB bios, GB rom, etc).
|
||||
const char *valid_extensions; // Same definition as retro_get_system_info().
|
||||
bool need_fullpath; // Same definition as retro_get_system_info().
|
||||
bool block_extract; // Same definition as retro_get_system_info().
|
||||
bool required; // This is set if the ROM is required to load a game. If this is set to false, a zeroed-out retro_game_info can be passed.
|
||||
|
||||
// ROMs can have multiple associated persistent memory types (retro_get_memory()).
|
||||
const struct retro_subsystem_memory_info *memory;
|
||||
unsigned num_memory;
|
||||
};
|
||||
|
||||
struct retro_subsystem_info
|
||||
{
|
||||
const char *desc; // Human-readable string of the subsystem type, e.g. "Super GameBoy"
|
||||
// A computer friendly short string identifier for the subsystem type.
|
||||
// This name must be [a-z].
|
||||
// E.g. if desc is "Super GameBoy", this can be "sgb".
|
||||
// This identifier can be used for command-line interfaces, etc.
|
||||
const char *ident;
|
||||
|
||||
// Infos for each ROM. The first entry is assumed to be the "most significant" ROM for frontend purposes.
|
||||
// E.g. with Super GameBoy, the first ROM should be the GameBoy ROM, as it is the most "significant" ROM to a user.
|
||||
// If a frontend creates new file paths based on the ROM used (e.g. savestates), it should use the path for the first ROM to do so.
|
||||
const struct retro_subsystem_rom_info *roms;
|
||||
|
||||
unsigned num_roms; // Number of ROMs associated with a subsystem.
|
||||
unsigned id; // The type passed to retro_load_game_special().
|
||||
};
|
||||
|
||||
typedef void (*retro_proc_address_t)(void);
|
||||
|
||||
// libretro API extension functions:
|
||||
// (None here so far).
|
||||
//////
|
||||
|
423
retroarch.c
423
retroarch.c
@ -776,11 +776,10 @@ static void print_help(void)
|
||||
#ifdef HAVE_DYNAMIC
|
||||
puts("\t-L/--libretro: Path to libretro implementation. Overrides any config setting.");
|
||||
#endif
|
||||
puts("\t-g/--gameboy: Path to Gameboy ROM. Load SuperGameBoy as the regular rom.");
|
||||
puts("\t-b/--bsx: Path to BSX rom. Load BSX BIOS as the regular rom.");
|
||||
puts("\t-B/--bsxslot: Path to BSX slotted rom. Load BSX BIOS as the regular rom.");
|
||||
puts("\t--sufamiA: Path to A slot of Sufami Turbo. Load Sufami base cart as regular rom.");
|
||||
puts("\t--sufamiB: Path to B slot of Sufami Turbo.");
|
||||
puts("\t--subsystem: Use a subsystem of the libretro core. Multiple ROMs are loaded as multiple arguments.");
|
||||
puts("\t\tIf a ROM is skipped, use a blank (\"\") command line argument");
|
||||
puts("\t\tROMs must be loaded in an order which depends on the particular subsystem used.");
|
||||
puts("\t\tSee verbose log output to learn how a particular subsystem wants ROMs to be loaded.");
|
||||
|
||||
printf("\t-N/--nodevice: Disconnects controller device connected to port (1 to %d).\n", MAX_PLAYERS);
|
||||
printf("\t-A/--dualanalog: Connect a DualAnalog controller to port (1 to %d).\n", MAX_PLAYERS);
|
||||
@ -836,19 +835,53 @@ static void set_basename(const char *path)
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
static void set_special_paths(char **argv, unsigned roms)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
// First ROM is the significant one.
|
||||
set_basename(argv[0]);
|
||||
|
||||
g_extern.subsystem_fullpaths = string_list_new();
|
||||
rarch_assert(g_extern.subsystem_fullpaths);
|
||||
|
||||
union string_list_elem_attr attr;
|
||||
attr.i = 0;
|
||||
|
||||
for (i = 0; i < roms; i++)
|
||||
string_list_append(g_extern.subsystem_fullpaths, argv[i], attr);
|
||||
|
||||
// We defer SRAM path updates until we can resolve it.
|
||||
// It is more complicated for special game types.
|
||||
|
||||
if (!g_extern.has_set_state_path)
|
||||
fill_pathname_noext(g_extern.savestate_name, g_extern.basename, ".state", sizeof(g_extern.savestate_name));
|
||||
|
||||
if (path_is_directory(g_extern.savestate_name))
|
||||
{
|
||||
fill_pathname_dir(g_extern.savestate_name, g_extern.basename, ".state", sizeof(g_extern.savestate_name));
|
||||
RARCH_LOG("Redirecting save state to \"%s\".\n", g_extern.savestate_name);
|
||||
}
|
||||
|
||||
// If this is already set,
|
||||
// do not overwrite it as this was initialized before in a menu or otherwise.
|
||||
if (!*g_settings.system_directory)
|
||||
fill_pathname_basedir(g_settings.system_directory, argv[0], sizeof(g_settings.system_directory));
|
||||
}
|
||||
|
||||
static void set_paths(const char *path)
|
||||
{
|
||||
set_basename(path);
|
||||
|
||||
if (!g_extern.has_set_save_path)
|
||||
fill_pathname_noext(g_extern.savefile_name_srm, g_extern.basename, ".srm", sizeof(g_extern.savefile_name_srm));
|
||||
fill_pathname_noext(g_extern.savefile_name, g_extern.basename, ".srm", sizeof(g_extern.savefile_name));
|
||||
if (!g_extern.has_set_state_path)
|
||||
fill_pathname_noext(g_extern.savestate_name, g_extern.basename, ".state", sizeof(g_extern.savestate_name));
|
||||
|
||||
if (path_is_directory(g_extern.savefile_name_srm))
|
||||
if (path_is_directory(g_extern.savefile_name))
|
||||
{
|
||||
fill_pathname_dir(g_extern.savefile_name_srm, g_extern.basename, ".srm", sizeof(g_extern.savefile_name_srm));
|
||||
RARCH_LOG("Redirecting save file to \"%s\".\n", g_extern.savefile_name_srm);
|
||||
fill_pathname_dir(g_extern.savefile_name, g_extern.basename, ".srm", sizeof(g_extern.savefile_name));
|
||||
RARCH_LOG("Redirecting save file to \"%s\".\n", g_extern.savefile_name);
|
||||
}
|
||||
if (path_is_directory(g_extern.savestate_name))
|
||||
{
|
||||
@ -869,6 +902,7 @@ static void parse_input(int argc, char *argv[])
|
||||
g_extern.has_set_save_path = false;
|
||||
g_extern.has_set_state_path = false;
|
||||
g_extern.has_set_libretro = false;
|
||||
*g_extern.subsystem = '\0';
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
@ -895,7 +929,6 @@ static void parse_input(int argc, char *argv[])
|
||||
{ "size", 1, &val, 's' },
|
||||
#endif
|
||||
{ "verbose", 0, NULL, 'v' },
|
||||
{ "gameboy", 1, NULL, 'g' },
|
||||
{ "config", 1, NULL, 'c' },
|
||||
{ "appendconfig", 1, &val, 'C' },
|
||||
{ "mouse", 1, NULL, 'm' },
|
||||
@ -905,11 +938,7 @@ static void parse_input(int argc, char *argv[])
|
||||
{ "justifiers", 0, NULL, 'J' },
|
||||
{ "dualanalog", 1, NULL, 'A' },
|
||||
{ "savestate", 1, NULL, 'S' },
|
||||
{ "bsx", 1, NULL, 'b' },
|
||||
{ "bsxslot", 1, NULL, 'B' },
|
||||
{ "multitap", 0, NULL, '4' },
|
||||
{ "sufamiA", 1, NULL, 'Y' },
|
||||
{ "sufamiB", 1, NULL, 'Z' },
|
||||
#ifdef HAVE_BSV_MOVIE
|
||||
{ "bsvplay", 1, NULL, 'P' },
|
||||
{ "bsvrecord", 1, NULL, 'R' },
|
||||
@ -932,6 +961,7 @@ static void parse_input(int argc, char *argv[])
|
||||
{ "no-patch", 0, &val, 'n' },
|
||||
{ "detach", 0, NULL, 'D' },
|
||||
{ "features", 0, &val, 'f' },
|
||||
{ "subsystem", 1, NULL, 'Z' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
@ -959,7 +989,7 @@ static void parse_input(int argc, char *argv[])
|
||||
#define BSV_MOVIE_ARG
|
||||
#endif
|
||||
|
||||
const char *optstring = "hs:fvS:m:p4jJA:g:b:c:B:Y:Z:U:DN:" BSV_MOVIE_ARG NETPLAY_ARG DYNAMIC_ARG FFMPEG_RECORD_ARG;
|
||||
const char *optstring = "hs:fvS:m:p4jJA:c:U:DN:" BSV_MOVIE_ARG NETPLAY_ARG DYNAMIC_ARG FFMPEG_RECORD_ARG;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@ -970,7 +1000,6 @@ static void parse_input(int argc, char *argv[])
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 'h':
|
||||
@ -992,6 +1021,10 @@ static void parse_input(int argc, char *argv[])
|
||||
g_extern.has_set_libretro_device[1] = true;
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
strlcpy(g_extern.subsystem, optarg, sizeof(g_extern.subsystem));
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
port = strtol(optarg, NULL, 0);
|
||||
if (port < 1 || port > MAX_PLAYERS)
|
||||
@ -1005,7 +1038,7 @@ static void parse_input(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
case 's':
|
||||
strlcpy(g_extern.savefile_name_srm, optarg, sizeof(g_extern.savefile_name_srm));
|
||||
strlcpy(g_extern.savefile_name, optarg, sizeof(g_extern.savefile_name));
|
||||
g_extern.has_set_save_path = true;
|
||||
break;
|
||||
|
||||
@ -1013,31 +1046,6 @@ static void parse_input(int argc, char *argv[])
|
||||
g_extern.force_fullscreen = true;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
strlcpy(g_extern.gb_rom_path, optarg, sizeof(g_extern.gb_rom_path));
|
||||
g_extern.game_type = RARCH_CART_SGB;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
strlcpy(g_extern.bsx_rom_path, optarg, sizeof(g_extern.bsx_rom_path));
|
||||
g_extern.game_type = RARCH_CART_BSX;
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
strlcpy(g_extern.bsx_rom_path, optarg, sizeof(g_extern.bsx_rom_path));
|
||||
g_extern.game_type = RARCH_CART_BSX_SLOTTED;
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
strlcpy(g_extern.sufami_rom_path[0], optarg, sizeof(g_extern.sufami_rom_path[0]));
|
||||
g_extern.game_type = RARCH_CART_SUFAMI;
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
strlcpy(g_extern.sufami_rom_path[1], optarg, sizeof(g_extern.sufami_rom_path[1]));
|
||||
g_extern.game_type = RARCH_CART_SUFAMI;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
strlcpy(g_extern.savestate_name, optarg, sizeof(g_extern.savestate_name));
|
||||
g_extern.has_set_state_path = true;
|
||||
@ -1239,14 +1247,16 @@ static void parse_input(int argc, char *argv[])
|
||||
rarch_fail(1, "parse_input()");
|
||||
}
|
||||
}
|
||||
else if (optind < argc)
|
||||
else if (!*g_extern.subsystem && optind < argc)
|
||||
set_paths(argv[optind]);
|
||||
else if (*g_extern.subsystem && optind < argc)
|
||||
set_special_paths(argv + optind, argc - optind);
|
||||
else
|
||||
g_extern.libretro_no_rom = true;
|
||||
|
||||
// Copy SRM/state dirs used, so they can be reused on reentrancy.
|
||||
if (g_extern.has_set_save_path && path_is_directory(g_extern.savefile_name_srm))
|
||||
strlcpy(g_extern.savefile_dir, g_extern.savefile_name_srm, sizeof(g_extern.savefile_dir));
|
||||
if (g_extern.has_set_save_path && path_is_directory(g_extern.savefile_name))
|
||||
strlcpy(g_extern.savefile_dir, g_extern.savefile_name, sizeof(g_extern.savefile_dir));
|
||||
if (g_extern.has_set_state_path && path_is_directory(g_extern.savestate_name))
|
||||
strlcpy(g_extern.savestate_dir, g_extern.savestate_name, sizeof(g_extern.savestate_dir));
|
||||
}
|
||||
@ -1302,73 +1312,26 @@ static void init_controllers(void)
|
||||
|
||||
static inline void load_save_files(void)
|
||||
{
|
||||
switch (g_extern.game_type)
|
||||
{
|
||||
case RARCH_CART_NORMAL:
|
||||
load_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SAVE_RAM);
|
||||
load_ram_file(g_extern.savefile_name_rtc, RETRO_MEMORY_RTC);
|
||||
break;
|
||||
unsigned i;
|
||||
if (!g_extern.savefiles)
|
||||
return;
|
||||
|
||||
case RARCH_CART_SGB:
|
||||
load_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SNES_GAME_BOY_RAM);
|
||||
load_ram_file(g_extern.savefile_name_rtc, RETRO_MEMORY_SNES_GAME_BOY_RTC);
|
||||
break;
|
||||
|
||||
case RARCH_CART_BSX:
|
||||
case RARCH_CART_BSX_SLOTTED:
|
||||
load_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SNES_BSX_RAM);
|
||||
load_ram_file(g_extern.savefile_name_psrm, RETRO_MEMORY_SNES_BSX_PRAM);
|
||||
break;
|
||||
|
||||
case RARCH_CART_SUFAMI:
|
||||
load_ram_file(g_extern.savefile_name_asrm, RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM);
|
||||
load_ram_file(g_extern.savefile_name_bsrm, RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < g_extern.savefiles->size; i++)
|
||||
load_ram_file(g_extern.savefiles->elems[i].data, g_extern.savefiles->elems[i].attr.i);
|
||||
}
|
||||
|
||||
static inline void save_files(void)
|
||||
{
|
||||
switch (g_extern.game_type)
|
||||
unsigned i;
|
||||
if (!g_extern.savefiles)
|
||||
return;
|
||||
|
||||
for (i = 0; i < g_extern.savefiles->size; i++)
|
||||
{
|
||||
case RARCH_CART_NORMAL:
|
||||
RARCH_LOG("Saving regular SRAM.\n");
|
||||
RARCH_LOG("SRM: %s\n", g_extern.savefile_name_srm);
|
||||
RARCH_LOG("RTC: %s\n", g_extern.savefile_name_rtc);
|
||||
save_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SAVE_RAM);
|
||||
save_ram_file(g_extern.savefile_name_rtc, RETRO_MEMORY_RTC);
|
||||
break;
|
||||
|
||||
case RARCH_CART_SGB:
|
||||
RARCH_LOG("Saving Gameboy SRAM.\n");
|
||||
RARCH_LOG("SRM: %s\n", g_extern.savefile_name_srm);
|
||||
RARCH_LOG("RTC: %s\n", g_extern.savefile_name_rtc);
|
||||
save_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SNES_GAME_BOY_RAM);
|
||||
save_ram_file(g_extern.savefile_name_rtc, RETRO_MEMORY_SNES_GAME_BOY_RTC);
|
||||
break;
|
||||
|
||||
case RARCH_CART_BSX:
|
||||
case RARCH_CART_BSX_SLOTTED:
|
||||
RARCH_LOG("Saving BSX (P)RAM.\n");
|
||||
RARCH_LOG("SRM: %s\n", g_extern.savefile_name_srm);
|
||||
RARCH_LOG("PSRM: %s\n", g_extern.savefile_name_psrm);
|
||||
save_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SNES_BSX_RAM);
|
||||
save_ram_file(g_extern.savefile_name_psrm, RETRO_MEMORY_SNES_BSX_PRAM);
|
||||
break;
|
||||
|
||||
case RARCH_CART_SUFAMI:
|
||||
RARCH_LOG("Saving Sufami turbo A/B RAM.\n");
|
||||
RARCH_LOG("ASRM: %s\n", g_extern.savefile_name_asrm);
|
||||
RARCH_LOG("BSRM: %s\n", g_extern.savefile_name_bsrm);
|
||||
save_ram_file(g_extern.savefile_name_asrm, RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM);
|
||||
save_ram_file(g_extern.savefile_name_bsrm, RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
unsigned type = g_extern.savefiles->elems[i].attr.i;
|
||||
const char *path = g_extern.savefiles->elems[i].data;
|
||||
RARCH_LOG("Saving RAM type #%u to \"%s\".\n", type, path);
|
||||
save_ram_file(path, type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1727,54 +1690,29 @@ static void init_libretro_cbs(void)
|
||||
#if defined(HAVE_THREADS)
|
||||
void rarch_init_autosave(void)
|
||||
{
|
||||
int ram_types[2] = {-1, -1};
|
||||
const char *ram_paths[2] = {NULL, NULL};
|
||||
if (g_settings.autosave_interval < 1 || !g_extern.savefiles)
|
||||
return;
|
||||
|
||||
switch (g_extern.game_type)
|
||||
g_extern.autosave = (autosave_t**)calloc(g_extern.savefiles->size, sizeof(*g_extern.autosave));
|
||||
if (!g_extern.autosave)
|
||||
return;
|
||||
|
||||
g_extern.num_autosave = g_extern.savefiles->size;
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < g_extern.savefiles->size; i++)
|
||||
{
|
||||
case RARCH_CART_BSX:
|
||||
case RARCH_CART_BSX_SLOTTED:
|
||||
ram_types[0] = RETRO_MEMORY_SNES_BSX_RAM;
|
||||
ram_types[1] = RETRO_MEMORY_SNES_BSX_PRAM;
|
||||
ram_paths[0] = g_extern.savefile_name_srm;
|
||||
ram_paths[1] = g_extern.savefile_name_psrm;
|
||||
break;
|
||||
const char *path = g_extern.savefiles->elems[i].data;
|
||||
unsigned type = g_extern.savefiles->elems[i].attr.i;
|
||||
|
||||
case RARCH_CART_SUFAMI:
|
||||
ram_types[0] = RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM;
|
||||
ram_types[1] = RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM;
|
||||
ram_paths[0] = g_extern.savefile_name_asrm;
|
||||
ram_paths[1] = g_extern.savefile_name_bsrm;
|
||||
break;
|
||||
|
||||
case RARCH_CART_SGB:
|
||||
ram_types[0] = RETRO_MEMORY_SNES_GAME_BOY_RAM;
|
||||
ram_types[1] = RETRO_MEMORY_SNES_GAME_BOY_RTC;
|
||||
ram_paths[0] = g_extern.savefile_name_srm;
|
||||
ram_paths[1] = g_extern.savefile_name_rtc;
|
||||
break;
|
||||
|
||||
default:
|
||||
ram_types[0] = RETRO_MEMORY_SAVE_RAM;
|
||||
ram_types[1] = RETRO_MEMORY_RTC;
|
||||
ram_paths[0] = g_extern.savefile_name_srm;
|
||||
ram_paths[1] = g_extern.savefile_name_rtc;
|
||||
}
|
||||
|
||||
if (g_settings.autosave_interval > 0)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < sizeof(g_extern.autosave) / sizeof(g_extern.autosave[0]); i++)
|
||||
if (pretro_get_memory_size(type) > 0)
|
||||
{
|
||||
if (ram_paths[i] && *ram_paths[i] && pretro_get_memory_size(ram_types[i]) > 0)
|
||||
{
|
||||
g_extern.autosave[i] = autosave_new(ram_paths[i],
|
||||
pretro_get_memory_data(ram_types[i]),
|
||||
pretro_get_memory_size(ram_types[i]),
|
||||
g_settings.autosave_interval);
|
||||
if (!g_extern.autosave[i])
|
||||
RARCH_WARN("Could not initialize autosave.\n");
|
||||
}
|
||||
g_extern.autosave[i] = autosave_new(path,
|
||||
pretro_get_memory_data(type),
|
||||
pretro_get_memory_size(type),
|
||||
g_settings.autosave_interval);
|
||||
if (!g_extern.autosave[i])
|
||||
RARCH_WARN("Could not initialize autosave.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1782,12 +1720,11 @@ void rarch_init_autosave(void)
|
||||
void rarch_deinit_autosave(void)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < ARRAY_SIZE(g_extern.autosave); i++)
|
||||
{
|
||||
if (g_extern.autosave[i])
|
||||
autosave_free(g_extern.autosave[i]);
|
||||
g_extern.autosave[i] = NULL;
|
||||
}
|
||||
for (i = 0; i < g_extern.num_autosave; i++)
|
||||
autosave_free(g_extern.autosave[i]);
|
||||
free(g_extern.autosave);
|
||||
g_extern.autosave = NULL;
|
||||
g_extern.num_autosave = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1838,84 +1775,86 @@ static void set_savestate_auto_index(void)
|
||||
|
||||
static void fill_pathnames(void)
|
||||
{
|
||||
switch (g_extern.game_type)
|
||||
string_list_free(g_extern.savefiles);
|
||||
g_extern.savefiles = string_list_new();
|
||||
rarch_assert(g_extern.savefiles);
|
||||
|
||||
// For subsystems, we know exactly which RAM types are supported.
|
||||
if (*g_extern.subsystem)
|
||||
{
|
||||
case RARCH_CART_BSX:
|
||||
case RARCH_CART_BSX_SLOTTED:
|
||||
// BSX PSRM
|
||||
if (!g_extern.has_set_save_path)
|
||||
unsigned i;
|
||||
const struct retro_subsystem_info *info = libretro_find_subsystem_info(g_extern.system.special, g_extern.system.num_special, g_extern.subsystem);
|
||||
|
||||
// We'll handle this error gracefully later.
|
||||
unsigned num_roms = min(info ? info->num_roms : 0, g_extern.subsystem_fullpaths ? g_extern.subsystem_fullpaths->size : 0);
|
||||
|
||||
bool use_sram_dir = path_is_directory(g_extern.savefile_name);
|
||||
|
||||
for (i = 0; i < num_roms; i++)
|
||||
{
|
||||
unsigned j;
|
||||
for (j = 0; j < info->roms[i].num_memory; j++)
|
||||
{
|
||||
fill_pathname(g_extern.savefile_name_srm,
|
||||
g_extern.bsx_rom_path, ".srm", sizeof(g_extern.savefile_name_srm));
|
||||
const struct retro_subsystem_memory_info *mem = &info->roms[i].memory[j];
|
||||
union string_list_elem_attr attr;
|
||||
|
||||
char path[PATH_MAX];
|
||||
char ext[32];
|
||||
|
||||
snprintf(ext, sizeof(ext), ".%s", mem->extension);
|
||||
|
||||
if (use_sram_dir)
|
||||
{
|
||||
// Redirect ROM fullpath to save directory.
|
||||
strlcpy(path, g_extern.savefile_name, sizeof(path));
|
||||
fill_pathname_dir(path, g_extern.subsystem_fullpaths->elems[i].data, ext,
|
||||
sizeof(path));
|
||||
}
|
||||
else
|
||||
{
|
||||
fill_pathname(path, g_extern.subsystem_fullpaths->elems[i].data,
|
||||
ext, sizeof(path));
|
||||
}
|
||||
|
||||
attr.i = mem->type;
|
||||
string_list_append(g_extern.savefiles, path, attr);
|
||||
}
|
||||
}
|
||||
|
||||
fill_pathname(g_extern.savefile_name_psrm,
|
||||
g_extern.savefile_name_srm, ".psrm", sizeof(g_extern.savefile_name_psrm));
|
||||
// Let other relevant paths be inferred from the main SRAM location.
|
||||
if (!g_extern.has_set_save_path)
|
||||
fill_pathname_noext(g_extern.savefile_name, g_extern.basename, ".srm", sizeof(g_extern.savefile_name));
|
||||
if (path_is_directory(g_extern.savefile_name))
|
||||
{
|
||||
fill_pathname_dir(g_extern.savefile_name, g_extern.basename, ".srm", sizeof(g_extern.savefile_name));
|
||||
RARCH_LOG("Redirecting save file to \"%s\".\n", g_extern.savefile_name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
union string_list_elem_attr attr;
|
||||
attr.i = RETRO_MEMORY_SAVE_RAM;
|
||||
string_list_append(g_extern.savefiles, g_extern.savefile_name, attr);
|
||||
|
||||
if (!g_extern.has_set_state_path)
|
||||
{
|
||||
fill_pathname(g_extern.savestate_name,
|
||||
g_extern.bsx_rom_path, ".state", sizeof(g_extern.savestate_name));
|
||||
}
|
||||
break;
|
||||
|
||||
case RARCH_CART_SUFAMI:
|
||||
if (g_extern.has_set_save_path && *g_extern.sufami_rom_path[0] && *g_extern.sufami_rom_path[1])
|
||||
RARCH_WARN("Sufami Turbo SRAM paths will be inferred from their respective paths to avoid conflicts.\n");
|
||||
|
||||
// SUFAMI ARAM
|
||||
fill_pathname(g_extern.savefile_name_asrm,
|
||||
g_extern.sufami_rom_path[0], ".srm", sizeof(g_extern.savefile_name_asrm));
|
||||
|
||||
// SUFAMI BRAM
|
||||
fill_pathname(g_extern.savefile_name_bsrm,
|
||||
g_extern.sufami_rom_path[1], ".srm", sizeof(g_extern.savefile_name_bsrm));
|
||||
|
||||
if (!g_extern.has_set_state_path)
|
||||
{
|
||||
fill_pathname(g_extern.savestate_name,
|
||||
*g_extern.sufami_rom_path[0] ?
|
||||
g_extern.sufami_rom_path[0] : g_extern.sufami_rom_path[1],
|
||||
".state", sizeof(g_extern.savestate_name));
|
||||
}
|
||||
break;
|
||||
|
||||
case RARCH_CART_SGB:
|
||||
if (!g_extern.has_set_save_path)
|
||||
{
|
||||
fill_pathname(g_extern.savefile_name_srm,
|
||||
g_extern.gb_rom_path, ".srm", sizeof(g_extern.savefile_name_srm));
|
||||
}
|
||||
|
||||
if (!g_extern.has_set_state_path)
|
||||
{
|
||||
fill_pathname(g_extern.savestate_name,
|
||||
g_extern.gb_rom_path, ".state", sizeof(g_extern.savestate_name));
|
||||
}
|
||||
|
||||
fill_pathname(g_extern.savefile_name_rtc,
|
||||
g_extern.savefile_name_srm, ".rtc", sizeof(g_extern.savefile_name_rtc));
|
||||
break;
|
||||
|
||||
default:
|
||||
// Infer .rtc save path from save ram path.
|
||||
fill_pathname(g_extern.savefile_name_rtc,
|
||||
g_extern.savefile_name_srm, ".rtc", sizeof(g_extern.savefile_name_rtc));
|
||||
// Infer .rtc save path from save ram path.
|
||||
char savefile_name_rtc[PATH_MAX];
|
||||
attr.i = RETRO_MEMORY_RTC;
|
||||
fill_pathname(savefile_name_rtc,
|
||||
g_extern.savefile_name, ".rtc", sizeof(savefile_name_rtc));
|
||||
string_list_append(g_extern.savefiles, savefile_name_rtc, attr);
|
||||
}
|
||||
|
||||
#ifdef HAVE_BSV_MOVIE
|
||||
fill_pathname(g_extern.bsv.movie_path, g_extern.savefile_name_srm, "", sizeof(g_extern.bsv.movie_path));
|
||||
fill_pathname(g_extern.bsv.movie_path, g_extern.savefile_name, "", sizeof(g_extern.bsv.movie_path));
|
||||
#endif
|
||||
|
||||
if (*g_extern.basename)
|
||||
{
|
||||
if (!(*g_extern.ups_name))
|
||||
if (!*g_extern.ups_name)
|
||||
fill_pathname_noext(g_extern.ups_name, g_extern.basename, ".ups", sizeof(g_extern.ups_name));
|
||||
|
||||
if (!(*g_extern.bps_name))
|
||||
if (!*g_extern.bps_name)
|
||||
fill_pathname_noext(g_extern.bps_name, g_extern.basename, ".bps", sizeof(g_extern.bps_name));
|
||||
|
||||
if (!(*g_extern.ips_name))
|
||||
if (!*g_extern.ips_name)
|
||||
fill_pathname_noext(g_extern.ips_name, g_extern.basename, ".ips", sizeof(g_extern.ips_name));
|
||||
}
|
||||
}
|
||||
@ -2530,19 +2469,22 @@ void rarch_disk_control_append_image(const char *path)
|
||||
rarch_deinit_autosave();
|
||||
#endif
|
||||
|
||||
// Update paths for our new image.
|
||||
// If we actually use append_image,
|
||||
// we assume that we started out in a single disk case,
|
||||
// and that this way of doing it makes the most sense.
|
||||
set_paths(path);
|
||||
fill_pathnames();
|
||||
// TODO: Need to figure out what to do with subsystems case.
|
||||
if (!*g_extern.subsystem)
|
||||
{
|
||||
// Update paths for our new image.
|
||||
// If we actually use append_image,
|
||||
// we assume that we started out in a single disk case,
|
||||
// and that this way of doing it makes the most sense.
|
||||
set_paths(path);
|
||||
fill_pathnames();
|
||||
}
|
||||
|
||||
#if defined(HAVE_THREADS)
|
||||
rarch_init_autosave();
|
||||
#endif
|
||||
|
||||
rarch_disk_control_set_eject(false, false);
|
||||
|
||||
}
|
||||
|
||||
void rarch_disk_control_set_eject(bool new_state, bool log)
|
||||
@ -2874,7 +2816,6 @@ static void init_state(void)
|
||||
{
|
||||
g_extern.video_active = true;
|
||||
g_extern.audio_active = true;
|
||||
g_extern.game_type = RARCH_CART_NORMAL;
|
||||
}
|
||||
|
||||
static void init_state_first(void)
|
||||
@ -3007,19 +2948,18 @@ int rarch_main_init(int argc, char *argv[])
|
||||
|
||||
if (g_extern.libretro_no_rom && !g_extern.libretro_dummy)
|
||||
{
|
||||
if (!init_rom_file(g_extern.game_type))
|
||||
if (!init_rom_file())
|
||||
goto error;
|
||||
}
|
||||
else if (!g_extern.libretro_dummy)
|
||||
{
|
||||
fill_pathnames();
|
||||
|
||||
if (!init_rom_file(g_extern.game_type))
|
||||
if (!init_rom_file())
|
||||
goto error;
|
||||
|
||||
set_savestate_auto_index();
|
||||
|
||||
|
||||
if (!g_extern.sram_load_disable)
|
||||
load_save_files();
|
||||
else
|
||||
@ -3278,13 +3218,24 @@ void rarch_main_deinit(void)
|
||||
pretro_deinit();
|
||||
uninit_libretro_sym();
|
||||
|
||||
if (g_extern.rom_file_temporary)
|
||||
if (g_extern.temporary_roms)
|
||||
{
|
||||
RARCH_LOG("Removing temporary ROM file: %s.\n", g_extern.last_rom);
|
||||
if (remove(g_extern.last_rom) < 0)
|
||||
RARCH_ERR("Failed to remove temporary file: %s.\n", g_extern.last_rom);
|
||||
g_extern.rom_file_temporary = false;
|
||||
unsigned i;
|
||||
for (i = 0; i < g_extern.temporary_roms->size; i++)
|
||||
{
|
||||
const char *path = g_extern.temporary_roms->elems[i].data;
|
||||
RARCH_LOG("Removing temporary ROM file: %s.\n", path);
|
||||
if (remove(path) < 0)
|
||||
RARCH_ERR("Failed to remove temporary file: %s.\n", path);
|
||||
}
|
||||
}
|
||||
string_list_free(g_extern.temporary_roms);
|
||||
g_extern.temporary_roms = NULL;
|
||||
|
||||
string_list_free(g_extern.subsystem_fullpaths);
|
||||
string_list_free(g_extern.savefiles);
|
||||
g_extern.subsystem_fullpaths = NULL;
|
||||
g_extern.savefiles = NULL;
|
||||
|
||||
g_extern.main_is_init = false;
|
||||
}
|
||||
|
@ -8,6 +8,10 @@
|
||||
# This will be overridden by explicit command line options.
|
||||
# savestate_directory =
|
||||
|
||||
# If set to a directory, ROMs which are temporarily extracted
|
||||
# will be extracted to this directory.
|
||||
# extraction_directory =
|
||||
|
||||
# Automatically saves a savestate at the end of RetroArch's lifetime.
|
||||
# The path is $SRAM_PATH.auto.
|
||||
# RetroArch will automatically load any savestate with this path on startup if savestate_auto_load is set.
|
||||
|
@ -376,6 +376,7 @@ void config_set_defaults(void)
|
||||
*g_settings.cheat_settings_path = '\0';
|
||||
*g_settings.screenshot_directory = '\0';
|
||||
*g_settings.system_directory = '\0';
|
||||
*g_settings.extraction_directory = '\0';
|
||||
*g_settings.input.autoconfig_dir = '\0';
|
||||
*g_settings.input.overlay = '\0';
|
||||
*g_settings.content_directory = '\0';
|
||||
@ -929,6 +930,7 @@ bool config_load_file(const char *path, bool set_defaults)
|
||||
}
|
||||
}
|
||||
|
||||
CONFIG_GET_PATH(extraction_directory, "extraction_directory");
|
||||
CONFIG_GET_PATH(content_directory, "content_directory");
|
||||
if (!strcmp(g_settings.content_directory, "default"))
|
||||
*g_settings.content_directory = '\0';
|
||||
@ -1009,8 +1011,8 @@ bool config_load_file(const char *path, bool set_defaults)
|
||||
else if (path_is_directory(tmp_str))
|
||||
{
|
||||
strlcpy(g_extern.savefile_dir, tmp_str, sizeof(g_extern.savefile_dir));
|
||||
strlcpy(g_extern.savefile_name_srm, tmp_str, sizeof(g_extern.savefile_name_srm));
|
||||
fill_pathname_dir(g_extern.savefile_name_srm, g_extern.basename, ".srm", sizeof(g_extern.savefile_name_srm));
|
||||
strlcpy(g_extern.savefile_name, tmp_str, sizeof(g_extern.savefile_name));
|
||||
fill_pathname_dir(g_extern.savefile_name, g_extern.basename, ".srm", sizeof(g_extern.savefile_name));
|
||||
}
|
||||
else
|
||||
RARCH_WARN("savefile_directory is not a directory, ignoring ...\n");
|
||||
@ -1276,6 +1278,7 @@ bool config_save_file(const char *path)
|
||||
config_set_int(conf, "audio_out_rate", g_settings.audio.out_rate);
|
||||
|
||||
config_set_path(conf, "system_directory", *g_settings.system_directory ? g_settings.system_directory : "default");
|
||||
config_set_path(conf, "extraction_directory", g_settings.extraction_directory);
|
||||
config_set_string(conf, "audio_resampler", g_settings.audio.resampler);
|
||||
config_set_path(conf, "savefile_directory", *g_extern.savefile_dir ? g_extern.savefile_dir : "default");
|
||||
config_set_path(conf, "savestate_directory", *g_extern.savestate_dir ? g_extern.savestate_dir : "default");
|
||||
|
Loading…
Reference in New Issue
Block a user