mirror of
https://github.com/libretro/hatari.git
synced 2026-11-07 10:36:00 -10:00
Add hard disk and m3u support to retro core
This commit is contained in:
1 parent
7dd6a196cd
commit
56524ef6a5
7 files changed
+328
-14
No files matched your search
@@ -1,7 +1,7 @@
|
||||
|
||||
include_directories(. ../.. ../includes ../debug ../falcon)
|
||||
|
||||
add_library(UiRetro OBJECT audio.c disk_control.c joy_ui.c gui_event.c keymap.c main_retro.c
|
||||
microphone.c options.c screen.c statusbar.c timing.c)
|
||||
add_library(UiRetro OBJECT audio.c disk_control.c harddisk.c joy_ui.c gui_event.c keymap.c
|
||||
main_retro.c microphone.c options.c screen.c statusbar.c timing.c)
|
||||
target_include_directories(UiRetro PRIVATE ${LIBRETRO_INCLUDE_DIR})
|
||||
set_target_properties(UiRetro PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
|
||||
@@ -72,6 +72,115 @@ static void DiskControl_UpdateLabel(unsigned int idx)
|
||||
DiskImages[idx].label[sizeof(DiskImages[idx].label) - 1] = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if 'p' looks like an absolute path.
|
||||
*/
|
||||
static bool DiskControl_PathIsAbsolute(const char *p)
|
||||
{
|
||||
if (!p || !p[0])
|
||||
return false;
|
||||
if (p[0] == '/' || p[0] == '\\')
|
||||
return true;
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
if (p[1] == ':')
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a .m3u file
|
||||
*/
|
||||
static unsigned int DiskControl_ParseM3U(const char *m3u_path)
|
||||
{
|
||||
uint8_t *raw;
|
||||
long size = 0;
|
||||
char *text, *p;
|
||||
char dir[FILENAME_MAX], name[FILENAME_MAX], ext[FILENAME_MAX];
|
||||
|
||||
DiskImagesCount = 0;
|
||||
|
||||
raw = File_ReadAsIs(m3u_path, &size);
|
||||
if (!raw || size <= 0)
|
||||
{
|
||||
Log_Printf(LOG_ERROR, "DiskControl: could not read m3u file '%s'\n", m3u_path);
|
||||
free(raw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
text = malloc((size_t)size + 1);
|
||||
if (!text)
|
||||
{
|
||||
free(raw);
|
||||
return 0;
|
||||
}
|
||||
memcpy(text, raw, (size_t)size);
|
||||
text[size] = '\0';
|
||||
free(raw);
|
||||
|
||||
File_SplitPath(m3u_path, dir, name, ext);
|
||||
|
||||
p = text;
|
||||
while (*p)
|
||||
{
|
||||
char *line, *eol;
|
||||
char full[FILENAME_MAX];
|
||||
|
||||
while (*p == '\r' || *p == '\n')
|
||||
p++;
|
||||
if (!*p)
|
||||
break;
|
||||
|
||||
line = p;
|
||||
eol = strpbrk(p, "\r\n");
|
||||
if (eol)
|
||||
{
|
||||
*eol = '\0';
|
||||
p = eol + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
p += strlen(p);
|
||||
}
|
||||
|
||||
while (*line == ' ' || *line == '\t')
|
||||
line++;
|
||||
if (!*line || *line == '#')
|
||||
continue;
|
||||
|
||||
if (DiskControl_PathIsAbsolute(line))
|
||||
{
|
||||
strncpy(full, line, sizeof(full) - 1);
|
||||
full[sizeof(full) - 1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
char *built = File_MakePath(dir, line, NULL);
|
||||
if (!built)
|
||||
continue;
|
||||
strncpy(full, built, sizeof(full) - 1);
|
||||
full[sizeof(full) - 1] = '\0';
|
||||
free(built);
|
||||
}
|
||||
|
||||
if (!DiskControl_EnsureCapacity(DiskImagesCount + 1))
|
||||
break;
|
||||
|
||||
strncpy(DiskImages[DiskImagesCount].path, full,
|
||||
sizeof(DiskImages[DiskImagesCount].path) - 1);
|
||||
DiskImages[DiskImagesCount].path[sizeof(DiskImages[DiskImagesCount].path) - 1] = '\0';
|
||||
DiskControl_UpdateLabel(DiskImagesCount);
|
||||
DiskImagesCount++;
|
||||
}
|
||||
|
||||
free(text);
|
||||
|
||||
Log_Printf(LOG_INFO, "DiskControl: m3u '%s' parsed, %u file(s) found.\n",
|
||||
m3u_path, DiskImagesCount);
|
||||
|
||||
return DiskImagesCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* (Re-)insert the image at CurrentImageIndex into floppy drive A
|
||||
*/
|
||||
@@ -253,6 +362,26 @@ void DiskControl_NewGame(const char *path)
|
||||
}
|
||||
}
|
||||
|
||||
void DiskControl_NewGameM3U(const char *m3u_path)
|
||||
{
|
||||
unsigned int n;
|
||||
|
||||
bTrayEjected = false;
|
||||
|
||||
n = DiskControl_ParseM3U(m3u_path);
|
||||
if (n == 0)
|
||||
{
|
||||
DiskImagesCount = 0;
|
||||
CurrentImageIndex = 0;
|
||||
Floppy_SetDiskFileNameNone(0);
|
||||
Floppy_EjectDiskFromDrive(0);
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentImageIndex = 0;
|
||||
DiskControl_ApplyCurrentImage();
|
||||
}
|
||||
|
||||
void DiskControl_UnInit(void)
|
||||
{
|
||||
free(DiskImages);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
void DiskControl_Init(void);
|
||||
void DiskControl_NewGame(const char *path);
|
||||
void DiskControl_NewGameM3U(const char *m3u_path);
|
||||
void DiskControl_UnInit(void);
|
||||
|
||||
#endif /* HATARI_RETRO_DISK_CONTROL_H */
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
Hatari - harddisk.c
|
||||
|
||||
This file is distributed under the GNU General Public License, version 2
|
||||
or at your option any later version. Read the file gpl.txt for details.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <libretro.h>
|
||||
|
||||
#if HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#include "main.h"
|
||||
#include "main_retro.h"
|
||||
#include "harddisk.h"
|
||||
#include "configuration.h"
|
||||
#include "file.h"
|
||||
#include "floppy.h"
|
||||
#include "gemdos.h"
|
||||
#include "hdc.h"
|
||||
#include "ide.h"
|
||||
#include "log.h"
|
||||
#include "ncr5380.h"
|
||||
#include "reset.h"
|
||||
|
||||
/**
|
||||
* Insert a raw HD image into the IDE master slot and reboot so TOS
|
||||
* picks it up.
|
||||
*/
|
||||
void HardDisk_InsertIde(const char *path)
|
||||
{
|
||||
Ide_UnInit();
|
||||
|
||||
ConfigureParams.Ide[0].bUseDevice = true;
|
||||
ConfigureParams.Ide[0].nByteSwap = BYTESWAP_AUTO;
|
||||
ConfigureParams.Ide[0].nBlockSize = 512;
|
||||
strncpy(ConfigureParams.Ide[0].sDeviceFile, path,
|
||||
sizeof(ConfigureParams.Ide[0].sDeviceFile) - 1);
|
||||
ConfigureParams.Ide[0].sDeviceFile[sizeof(ConfigureParams.Ide[0].sDeviceFile) - 1] = '\0';
|
||||
File_MakeAbsoluteName(ConfigureParams.Ide[0].sDeviceFile);
|
||||
|
||||
Ide_Init();
|
||||
|
||||
Log_Printf(LOG_INFO, "HardDisk (%s) inserted into IDE master slot.\n", path);
|
||||
|
||||
Reset_Cold();
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a raw HD image into ACSI slot 0 and reboot so TOS picks it up.
|
||||
*/
|
||||
void HardDisk_InsertAcsi(const char *path)
|
||||
{
|
||||
HDC_UnInit();
|
||||
Ncr5380_UnInit();
|
||||
|
||||
ConfigureParams.Acsi[0].bUseDevice = true;
|
||||
ConfigureParams.Acsi[0].nBlockSize = 512;
|
||||
ConfigureParams.Acsi[0].nScsiVersion = 1;
|
||||
strncpy(ConfigureParams.Acsi[0].sDeviceFile, path,
|
||||
sizeof(ConfigureParams.Acsi[0].sDeviceFile) - 1);
|
||||
ConfigureParams.Acsi[0].sDeviceFile[sizeof(ConfigureParams.Acsi[0].sDeviceFile) - 1] = '\0';
|
||||
File_MakeAbsoluteName(ConfigureParams.Acsi[0].sDeviceFile);
|
||||
|
||||
HDC_Init();
|
||||
Ncr5380_Init();
|
||||
|
||||
Log_Printf(LOG_INFO, "HardDisk (%s) inserted into ACSI slot 0.\n", path);
|
||||
|
||||
Reset_Cold();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable GEMDOS HD directory emulation
|
||||
*/
|
||||
void HardDisk_SetGemdosDrive(const char *path)
|
||||
{
|
||||
char dir[FILENAME_MAX];
|
||||
size_t len = strlen(path);
|
||||
|
||||
if (len >= 4 && strcasecmp(path + len - 4, ".gem") == 0)
|
||||
len -= 4;
|
||||
if (len >= sizeof(dir))
|
||||
len = sizeof(dir) - 1;
|
||||
memcpy(dir, path, len);
|
||||
dir[len] = '\0';
|
||||
|
||||
GemDOS_UnInitDrives();
|
||||
|
||||
strncpy(ConfigureParams.HardDisk.szHardDiskDirectories[0], dir,
|
||||
sizeof(ConfigureParams.HardDisk.szHardDiskDirectories[0]) - 1);
|
||||
ConfigureParams.HardDisk.szHardDiskDirectories[0][sizeof(ConfigureParams.HardDisk.szHardDiskDirectories[0]) - 1] = '\0';
|
||||
File_CleanFileName(ConfigureParams.HardDisk.szHardDiskDirectories[0]);
|
||||
File_MakeAbsoluteName(ConfigureParams.HardDisk.szHardDiskDirectories[0]);
|
||||
ConfigureParams.HardDisk.bUseHardDiskDirectories = true;
|
||||
ConfigureParams.HardDisk.bBootFromHardDisk = true;
|
||||
|
||||
GemDOS_InitDrives();
|
||||
|
||||
Log_Printf(LOG_INFO, "GEMDOS HDD emulation set to '%s'.\n",
|
||||
ConfigureParams.HardDisk.szHardDiskDirectories[0]);
|
||||
|
||||
if (retro_system_directory && retro_system_directory[0])
|
||||
{
|
||||
char boot_path[FILENAME_MAX];
|
||||
|
||||
snprintf(boot_path, sizeof(boot_path), "%s%chatari%cBOOT.ST",
|
||||
retro_system_directory, PATHSEP, PATHSEP);
|
||||
|
||||
if (File_Exists(boot_path))
|
||||
{
|
||||
Floppy_SetDiskFileName(0, boot_path, NULL);
|
||||
Floppy_InsertDiskIntoDrive(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log_Printf(LOG_WARN, "GEMDOS HDD boot floppy '%s' not found, "
|
||||
"content may not autoboot.\n", boot_path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log_Printf(LOG_WARN, "GEMDOS HDD: no system directory available, "
|
||||
"cannot look for BOOT.ST helper floppy.\n");
|
||||
}
|
||||
|
||||
Reset_Cold();
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
Hatari - harddisk.h
|
||||
|
||||
This file is distributed under the GNU General Public License, version 2
|
||||
or at your option any later version. Read the file gpl.txt for details.
|
||||
*/
|
||||
#ifndef HATARI_RETRO_HARDDISK_H
|
||||
#define HATARI_RETRO_HARDDISK_H
|
||||
|
||||
void HardDisk_InsertIde(const char *path);
|
||||
void HardDisk_InsertAcsi(const char *path);
|
||||
void HardDisk_SetGemdosDrive(const char *path);
|
||||
|
||||
#endif /* HATARI_RETRO_HARDDISK_H */
|
||||
+51
-11
@@ -1,4 +1,5 @@
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -12,6 +13,7 @@
|
||||
#include "disk_control.h"
|
||||
#include "file.h"
|
||||
#include "floppy.h"
|
||||
#include "harddisk.h"
|
||||
#include "memorySnapShot.h"
|
||||
#include "m68000.h"
|
||||
#include "options.h"
|
||||
@@ -153,7 +155,7 @@ RETRO_API void retro_get_system_info(struct retro_system_info *info)
|
||||
info->library_name = "hatari";
|
||||
info->library_version = HATARI_VERSION;
|
||||
info->need_fullpath = true;
|
||||
info->valid_extensions = "st|msa|dim|stx";
|
||||
info->valid_extensions = "st|msa|dim|stx|ipf|m3u|ide|vhd|gem";
|
||||
}
|
||||
|
||||
RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info)
|
||||
@@ -294,18 +296,56 @@ RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code)
|
||||
|
||||
RETRO_API bool retro_load_game(const struct retro_game_info *game)
|
||||
{
|
||||
if (game)
|
||||
Floppy_SetDiskFileName(0, game->path, NULL);
|
||||
if (game && game->path)
|
||||
{
|
||||
const char *path = game->path;
|
||||
|
||||
if (File_DoesFileExtensionMatch(path, ".m3u"))
|
||||
{
|
||||
DiskControl_NewGameM3U(path);
|
||||
}
|
||||
else if (File_DoesFileExtensionMatch(path, ".ide"))
|
||||
{
|
||||
Floppy_SetDiskFileNameNone(0);
|
||||
DiskControl_NewGame(NULL);
|
||||
HardDisk_InsertIde(path);
|
||||
}
|
||||
else if (File_DoesFileExtensionMatch(path, ".vhd"))
|
||||
{
|
||||
Floppy_SetDiskFileNameNone(0);
|
||||
DiskControl_NewGame(NULL);
|
||||
HardDisk_InsertAcsi(path);
|
||||
}
|
||||
else if (File_DoesFileExtensionMatch(path, ".gem"))
|
||||
{
|
||||
DiskControl_NewGame(NULL);
|
||||
HardDisk_SetGemdosDrive(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef HAVE_CAPSIMAGE
|
||||
if (File_DoesFileExtensionMatch(path, ".ipf"))
|
||||
{
|
||||
Log_Printf(LOG_WARN, "IPF image '%s' requested, but this build "
|
||||
"was compiled without CAPSImage support.\n",
|
||||
path);
|
||||
}
|
||||
#endif
|
||||
Floppy_SetDiskFileName(0, path, NULL);
|
||||
Floppy_InsertDiskIntoDrive(0);
|
||||
|
||||
/* insert disk B also */
|
||||
if (ConfigureParams.DiskImage.szDiskFileName[1][0])
|
||||
Floppy_InsertDiskIntoDrive(1);
|
||||
|
||||
DiskControl_NewGame(path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Floppy_SetDiskFileNameNone(0);
|
||||
|
||||
Floppy_InsertDiskIntoDrive(0);
|
||||
|
||||
// insert disk B also
|
||||
if (ConfigureParams.DiskImage.szDiskFileName[1][0])
|
||||
Floppy_InsertDiskIntoDrive(1);
|
||||
|
||||
DiskControl_NewGame(game ? game->path : NULL);
|
||||
DiskControl_NewGame(NULL);
|
||||
}
|
||||
|
||||
Retro_SetInputDescriptors();
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
extern bool has_cpu_config_changed;
|
||||
|
||||
extern const char *retro_system_directory;
|
||||
extern retro_environment_t environment_cb;
|
||||
extern retro_video_refresh_t video_refresh_cb;
|
||||
extern retro_input_state_t input_state_cb;
|
||||
Reference in new issue
Block a user