From 1ae743b1f67e225d74fa08839dc794630c1f8e7c Mon Sep 17 00:00:00 2001
From: notaz <notasas@gmail.com>
Date: Sun, 11 May 2025 21:27:12 +0300
Subject: [PATCH] frontend: use more traditional profile dir

With backward compatibility to working dir, also can set 'HOME=' env var
for the old behavior.

notaz/pcsx_rearmed#375
---
 Makefile            |   2 +-
 frontend/main.c     | 189 +++++++++++++++++++++++++++-----------------
 frontend/main.h     |  27 ++++---
 frontend/menu.c     |  41 ++++------
 frontend/plat_sdl.c |  12 ++-
 libpcsxcore/sio.c   |   4 +-
 6 files changed, 165 insertions(+), 110 deletions(-)

diff --git a/Makefile b/Makefile
index f56ca1a5..784ef19f 100644
--- a/Makefile
+++ b/Makefile
@@ -388,8 +388,8 @@ OBJS += frontend/libpicofe/linux/fbdev.o frontend/libpicofe/linux/xenv.o
 OBJS += frontend/libpicofe/linux/in_evdev.o
 OBJS += frontend/plat_pandora.o frontend/plat_omap.o
 frontend/main.o frontend/menu.o: CFLAGS += -include frontend/pandora/ui_feat.h
+frontend/main.o frontend/plugin_lib.o: CFLAGS += -DPANDORA
 frontend/libpicofe/linux/plat.o: CFLAGS += -DPANDORA
-frontend/plugin_lib.o: CFLAGS += -DPANDORA
 USE_PLUGIN_LIB = 1
 USE_FRONTEND = 1
 CFLAGS += -gdwarf-3
diff --git a/frontend/main.c b/frontend/main.c
index 2aa6fbd7..6f581a8b 100644
--- a/frontend/main.c
+++ b/frontend/main.c
@@ -46,6 +46,7 @@
 #endif
 
 #ifndef NO_FRONTEND
+#include <sys/stat.h>
 #include "libpicofe/input.h"
 #include "libpicofe/plat.h"
 #include "libpicofe/readpng.h"
@@ -53,6 +54,11 @@
 static void toggle_fast_forward(int force_off);
 static void check_profile(void);
 static void check_memcards(void);
+static int get_gameid_filename(char *buf, int size, const char *fmt, int i);
+static const char *get_home_dir(void);
+#define MAKE_PATH(buf, dir, fname) \
+	emu_make_path(buf, sizeof(buf), dir, fname)
+
 #endif
 #ifndef BOOT_MSG
 #define BOOT_MSG "Booting up..."
@@ -70,33 +76,6 @@ enum sched_action emu_action, emu_action_old;
 char hud_msg[64];
 int hud_new_msg;
 
-static inline void make_path(char *buf, size_t size, const char *dir, const char *fname)
-{
-	if (fname)
-		snprintf(buf, size, ".%s%s", dir, fname);
-	else
-		snprintf(buf, size, ".%s", dir);
-}
-#define MAKE_PATH(buf, dir, fname) \
-	make_path(buf, sizeof(buf), dir, fname)
-
-static int get_gameid_filename(char *buf, int size, const char *fmt, int i) {
-	char trimlabel[33];
-	int j;
-
-	strncpy(trimlabel, CdromLabel, 32);
-	trimlabel[32] = 0;
-	for (j = 31; j >= 0; j--)
-		if (trimlabel[j] == ' ')
-			trimlabel[j] = 0;
-		else
-			continue;
-
-	snprintf(buf, size, fmt, trimlabel, CdromId, i);
-
-	return 0;
-}
-
 void set_cd_image(const char *fname)
 {
 	SetIsoFile(fname);
@@ -105,13 +84,23 @@ void set_cd_image(const char *fname)
 static void set_default_paths(void)
 {
 #ifndef NO_FRONTEND
-	snprintf(Config.PatchesDir, sizeof(Config.PatchesDir), "." PATCHES_DIR);
+	const char *home = get_home_dir();
+	struct stat st;
+	MAKE_PATH(Config.PatchesDir, PATCHES_DIR, NULL);
 	MAKE_PATH(Config.Mcd1, MEMCARD_DIR, "card1.mcd");
 	MAKE_PATH(Config.Mcd2, MEMCARD_DIR, "card2.mcd");
-	strcpy(Config.BiosDir, "bios");
+	MAKE_PATH(Config.BiosDir, BIOS_DIR, NULL);
+
+	emu_make_data_path(Config.PluginsDir, "plugins", sizeof(Config.PluginsDir));
+
+	// prefer bios in working dir for compatibility
+	if (!strcmp(home, ".") && !stat("bios", &st))
+		strcpy(Config.BiosDir, "bios");
+
+	SysPrintf("dirs: profile=%s" PCSX_DOT_DIR ", bios=%s, plugins=%s\n",
+		home, Config.BiosDir, Config.PluginsDir);
 #endif
 
-	strcpy(Config.PluginsDir, "plugins");
 	strcpy(Config.Gpu, "builtin_gpu");
 	strcpy(Config.Spu, "builtin_spu");
 }
@@ -246,12 +235,14 @@ do_state_slot:
 
 			scrbuf = pl_prepare_screenshot(&w, &h, &bpp);
 			get_gameid_filename(buf, sizeof(buf),
-				"screenshots/%.32s-%.9s.%d.png", ti);
-			ret = -1;
+				"%s" SCREENSHOTS_DIR "%.32s-%.9s.%d.png", ti);
+			ret = -2;
 			if (scrbuf != 0 && bpp == 16)
 				ret = writepng(buf, scrbuf, w, h);
 			if (ret == 0)
 				snprintf(hud_msg, sizeof(hud_msg), "SCREENSHOT TAKEN");
+			else
+				SysPrintf("writepng %s: %d\n", buf, ret);
 			break;
 		}
 	case SACTION_VOLUME_UP:
@@ -508,6 +499,45 @@ void emu_core_ask_exit(void)
 #include <sys/stat.h>
 #include <sys/types.h>
 
+static const char *get_home_dir(void)
+{
+#if defined(PANDORA) || !defined(__unix__)
+	return ".";
+#else
+	static const char *home = NULL;
+	struct stat st;
+	if (home)
+		return home;
+	// for compatibility with older versions, look for .pcsx in the working dir
+	if (stat(PCSX_DOT_DIR + 1, &st) != 0)
+		home = getenv("HOME");
+	if (home == NULL)
+		home = ".";
+	return home;
+#endif
+}
+
+void emu_make_path(char *buf, size_t size, const char *dir, const char *fname)
+{
+	const char *home = get_home_dir();
+	if (fname)
+		snprintf(buf, size, "%s%s%s", home, dir, fname);
+	else
+		snprintf(buf, size, "%s%s", home, dir);
+}
+
+void emu_make_data_path(char *buff, const char *end, int size)
+{
+	int pos, end_len;
+
+	end_len = strlen(end);
+	pos = plat_get_root_dir(buff, size);
+	strncpy(buff + pos, end, size - pos);
+	buff[size - 1] = 0;
+	if (pos + end_len > size - 1)
+		printf("Warning: path truncated: %s\n", buff);
+}
+
 static void create_profile_dir(const char *directory) {
 	char path[MAXPATHLEN];
 
@@ -522,12 +552,10 @@ static void check_profile(void) {
 	create_profile_dir(BIOS_DIR);
 	create_profile_dir(MEMCARD_DIR);
 	create_profile_dir(STATES_DIR);
-	create_profile_dir(PLUGINS_DIR);
-	create_profile_dir(PLUGINS_CFG_DIR);
 	create_profile_dir(CHEATS_DIR);
 	create_profile_dir(PATCHES_DIR);
-	create_profile_dir(PCSX_DOT_DIR "cfg");
-	create_profile_dir("/screenshots/");
+	create_profile_dir(CFG_DIR);
+	create_profile_dir(SCREENSHOTS_DIR);
 }
 
 static void check_memcards(void)
@@ -537,7 +565,8 @@ static void check_memcards(void)
 	int i;
 
 	for (i = 1; i <= 9; i++) {
-		snprintf(buf, sizeof(buf), ".%scard%d.mcd", MEMCARD_DIR, i);
+		snprintf(buf, sizeof(buf), "%s%scard%d.mcd",
+			get_home_dir(), MEMCARD_DIR, i);
 
 		f = fopen(buf, "rb");
 		if (f == NULL) {
@@ -639,7 +668,8 @@ int main(int argc, char *argv[])
 		// FIXME: this recovery doesn't work, just delete bad config and bail out
 		// SysMessage("could not load plugins, retrying with defaults\n");
 		set_default_paths();
-		snprintf(path, sizeof(path), "." PCSX_DOT_DIR "%s", cfgfile_basename);
+		snprintf(path, sizeof(path), "%s" PCSX_DOT_DIR "%s",
+			get_home_dir(), cfgfile_basename);
 		remove(path);
 		SysMessage("Failed loading plugins!");
 		return 1;
@@ -749,52 +779,32 @@ static void toggle_fast_forward(int force_off)
 }
 
 static void SignalExit(int sig) {
+	SysPrintf("got signal %d\n", sig);
 	// only to restore framebuffer/resolution on some devices
 	plat_finish();
 	_exit(1);
 }
-#endif
-
-void SysRunGui() {
-        printf("SysRunGui\n");
-}
-
-static void CALLBACK dummy_lace(void)
-{
-}
-
-void SysReset() {
-	// rearmed hack: EmuReset() runs some code when real BIOS is used,
-	// but we usually do reset from menu while GPU is not open yet,
-	// so we need to prevent updateLace() call..
-	void *real_lace = GPU_updateLace;
-	GPU_updateLace = dummy_lace;
-	g_emu_resetting = 1;
-
-	// reset can run code, timing must be set
-	pl_timing_prepare(Config.PsxType);
 
-	EmuReset();
-
-	GPU_updateLace = real_lace;
-	g_emu_resetting = 0;
-}
+static int get_gameid_filename(char *buf, int size, const char *fmt, int i) {
+	char trimlabel[33];
+	int j;
 
-void SysClose() {
-	EmuShutdown();
-	ReleasePlugins();
+	strncpy(trimlabel, CdromLabel, 32);
+	trimlabel[32] = 0;
+	for (j = 31; j >= 0; j--)
+		if (trimlabel[j] == ' ')
+			trimlabel[j] = 0;
+		else
+			continue;
 
-	StopDebugger();
+	snprintf(buf, size, fmt, get_home_dir(), trimlabel, CdromId, i);
 
-	if (emuLog != NULL && emuLog != stdout && emuLog != stderr) {
-		fclose(emuLog);
-		emuLog = NULL;
-	}
+	return 0;
 }
 
 int get_state_filename(char *buf, int size, int i) {
 	return get_gameid_filename(buf, size,
-		"." STATES_DIR "%.32s-%.9s.%3.3d", i);
+		"%s" STATES_DIR "%.32s-%.9s.%3.3d", i);
 }
 
 int emu_check_state(int slot)
@@ -841,6 +851,41 @@ int emu_load_state(int slot)
 	return LoadState(fname);
 }
 
+#endif // NO_FRONTEND
+
+static void CALLBACK dummy_lace(void)
+{
+}
+
+void SysReset() {
+	// rearmed hack: EmuReset() runs some code when real BIOS is used,
+	// but we usually do reset from menu while GPU is not open yet,
+	// so we need to prevent updateLace() call..
+	void *real_lace = GPU_updateLace;
+	GPU_updateLace = dummy_lace;
+	g_emu_resetting = 1;
+
+	// reset can run code, timing must be set
+	pl_timing_prepare(Config.PsxType);
+
+	EmuReset();
+
+	GPU_updateLace = real_lace;
+	g_emu_resetting = 0;
+}
+
+void SysClose() {
+	EmuShutdown();
+	ReleasePlugins();
+
+	StopDebugger();
+
+	if (emuLog != NULL && emuLog != stdout && emuLog != stderr) {
+		fclose(emuLog);
+		emuLog = NULL;
+	}
+}
+
 #ifndef HAVE_LIBRETRO
 #ifndef ANDROID
 
diff --git a/frontend/main.h b/frontend/main.h
index 1c249354..3c17f8c5 100644
--- a/frontend/main.h
+++ b/frontend/main.h
@@ -19,18 +19,24 @@
 #ifndef __FRONTEND_MAIN_H__
 #define __FRONTEND_MAIN_H__
 
+#include <stdlib.h>
 #include "config.h"
 
-#define DEFAULT_MEM_CARD_1 "/.pcsx/memcards/card1.mcd"
-#define DEFAULT_MEM_CARD_2 "/.pcsx/memcards/card2.mcd"
-#define MEMCARD_DIR "/.pcsx/memcards/"
-#define PLUGINS_DIR "/.pcsx/plugins/"
-#define PLUGINS_CFG_DIR "/.pcsx/plugins/cfg/"
 #define PCSX_DOT_DIR "/.pcsx/"
-#define STATES_DIR "/.pcsx/sstates/"
-#define CHEATS_DIR "/.pcsx/cheats/"
-#define PATCHES_DIR "/.pcsx/patches/"
-#define BIOS_DIR "/bios/"
+#define DEFAULT_MEM_CARD_1 PCSX_DOT_DIR "memcards/card1.mcd"
+#define DEFAULT_MEM_CARD_2 PCSX_DOT_DIR "memcards/card2.mcd"
+#define MEMCARD_DIR        PCSX_DOT_DIR "memcards/"
+#define STATES_DIR         PCSX_DOT_DIR "sstates/"
+#define CHEATS_DIR         PCSX_DOT_DIR "cheats/"
+#define PATCHES_DIR        PCSX_DOT_DIR "patches/"
+#define CFG_DIR            PCSX_DOT_DIR "cfg/"
+#ifndef PANDORA
+#define BIOS_DIR           PCSX_DOT_DIR "bios/"
+#define SCREENSHOTS_DIR    PCSX_DOT_DIR "screenshots/"
+#else
+#define BIOS_DIR           "/bios/"
+#define SCREENSHOTS_DIR    "/screenshots/"
+#endif
 
 extern char cfgfile_basename[MAXPATHLEN];
 
@@ -46,6 +52,9 @@ void emu_core_ask_exit(void);
 void emu_set_default_config(void);
 void emu_on_new_cd(int show_hud_msg);
 
+void emu_make_path(char *buf, size_t size, const char *dir, const char *fname);
+void emu_make_data_path(char *buff, const char *end, int size);
+
 int get_state_filename(char *buf, int size, int i);
 int emu_check_state(int slot);
 int emu_save_state(int slot);
diff --git a/frontend/menu.c b/frontend/menu.c
index a5ffb7b4..0c4ebcea 100644
--- a/frontend/menu.c
+++ b/frontend/menu.c
@@ -132,7 +132,6 @@ static const char *memcards[32];
 static int bios_sel, gpu_plugsel, spu_plugsel;
 
 #ifndef UI_FEATURES_H
-#define MENU_BIOS_PATH "bios/"
 #define MENU_SHOW_VOUTMODE 1
 #define MENU_SHOW_SCALER2 0
 #define MENU_SHOW_NUBS_BTNS 0
@@ -152,18 +151,6 @@ static int bios_sel, gpu_plugsel, spu_plugsel;
 static int min(int x, int y) { return x < y ? x : y; }
 static int max(int x, int y) { return x > y ? x : y; }
 
-void emu_make_path(char *buff, const char *end, int size)
-{
-	int pos, end_len;
-
-	end_len = strlen(end);
-	pos = plat_get_root_dir(buff, size);
-	strncpy(buff + pos, end, size - pos);
-	buff[size - 1] = 0;
-	if (pos + end_len > size - 1)
-		printf("Warning: path truncated: %s\n", buff);
-}
-
 static int emu_check_save_file(int slot, int *time)
 {
 	char fname[MAXPATHLEN];
@@ -508,10 +495,14 @@ static char *get_cd_label(void)
 
 static void make_cfg_fname(char *buf, size_t size, int is_game)
 {
-	if (is_game)
-		snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
+	char id_buf[64];
+	if (is_game) {
+		snprintf(id_buf, sizeof(id_buf), "%.32s-%.9s.cfg",
+			get_cd_label(), CdromId);
+		emu_make_path(buf, size, CFG_DIR, id_buf);
+	}
 	else
-		snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
+		emu_make_path(buf, size, PCSX_DOT_DIR, cfgfile_basename);
 }
 
 static void keys_write_all(FILE *f);
@@ -577,7 +568,7 @@ static int menu_do_last_cd_img(int is_get)
 	FILE *f;
 	int i, ret = -1;
 
-	snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
+	emu_make_path(path, sizeof(path), PCSX_DOT_DIR, "lastcdimg.txt");
 	f = fopen(path, is_get ? "r" : "w");
 	if (f == NULL) {
 		ret = -1;
@@ -1905,10 +1896,10 @@ static void handle_memcard_sel(void)
 {
 	strcpy(Config.Mcd1, "none");
 	if (memcard1_sel != 0)
-		snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
+		emu_make_path(Config.Mcd1, sizeof(Config.Mcd1), MEMCARD_DIR, memcards[memcard1_sel]);
 	strcpy(Config.Mcd2, "none");
 	if (memcard2_sel != 0)
-		snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
+		emu_make_path(Config.Mcd2, sizeof(Config.Mcd2), MEMCARD_DIR, memcards[memcard2_sel]);
 	LoadMcds(Config.Mcd1, Config.Mcd2);
 	draw_mc_bg();
 }
@@ -2005,8 +1996,7 @@ static void menu_bios_warn(void)
 	int inp;
 	static const char msg[] =
 		"You don't seem to have copied any BIOS\n"
-		"files to\n"
-		MENU_BIOS_PATH "\n\n"
+		"files to\n%s\n\n"
 
 		"While many games work fine with fake\n"
 		"(HLE) BIOS, others (like MGS and FF8)\n"
@@ -2020,7 +2010,7 @@ static void menu_bios_warn(void)
 		"Press %s or %s to continue";
 	char tmp_msg[sizeof(msg) + 64];
 
-	snprintf(tmp_msg, sizeof(tmp_msg), msg,
+	snprintf(tmp_msg, sizeof(tmp_msg), msg, Config.BiosDir,
 		in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
 	while (1)
 	{
@@ -2607,7 +2597,8 @@ do_plugins:
 #endif
 
 do_memcards:
-	dir = opendir("." MEMCARD_DIR);
+	emu_make_path(fname, sizeof(fname), MEMCARD_DIR, NULL);
+	dir = opendir(fname);
 	if (dir == NULL) {
 		perror("scan_bios_plugins memcards opendir");
 		return;
@@ -2627,7 +2618,7 @@ do_memcards:
 		if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
 			continue;
 
-		snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
+		emu_make_path(fname, sizeof(fname), MEMCARD_DIR, ent->d_name);
 		if (stat(fname, &st) != 0) {
 			printf("bad memcard file: %s\n", ent->d_name);
 			continue;
@@ -2671,7 +2662,7 @@ void menu_init(void)
 		exit(1);
 	}
 
-	emu_make_path(buff, "skin/background.png", sizeof(buff));
+	emu_make_data_path(buff, "skin/background.png", sizeof(buff));
 	readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
 
 	i = plat_target.cpu_clock_set != NULL
diff --git a/frontend/plat_sdl.c b/frontend/plat_sdl.c
index 3529d979..4c397194 100644
--- a/frontend/plat_sdl.c
+++ b/frontend/plat_sdl.c
@@ -665,10 +665,18 @@ void plat_video_menu_leave(void)
   centered_clear();
 }
 
-/* unused stuff */
 void *plat_prepare_screenshot(int *w, int *h, int *bpp)
 {
-  return 0;
+  if (plat_sdl_screen && !SDL_MUSTLOCK(plat_sdl_screen) &&
+      plat_sdl_overlay == NULL && !plat_sdl_gl_active)
+  {
+    *w = plat_sdl_screen->pitch / 2;
+    *h = plat_sdl_screen->h;
+    *bpp = 16;
+    return plat_sdl_screen->pixels;
+  }
+  fprintf(stderr, "screenshot not implemented in current mode\n");
+  return NULL;
 }
 
 void plat_trigger_vibrate(int pad, int low, int high)
diff --git a/libpcsxcore/sio.c b/libpcsxcore/sio.c
index 0bc763ca..c28c0554 100644
--- a/libpcsxcore/sio.c
+++ b/libpcsxcore/sio.c
@@ -455,8 +455,10 @@ void CreateMcd(char *mcd) {
 	int i = 0, j;
 
 	f = fopen(mcd, "wb");
-	if (f == NULL)
+	if (f == NULL) {
+		SysPrintf("CreateMcd: couldn't open %s\n", mcd);
 		return;
+	}
 
 	if (stat(mcd, &buf) != -1) {
 		if ((buf.st_size == MCD_SIZE + 3904) || strstr(mcd, ".gme")) {
-- 
2.39.5