about summary refs log tree commit diff
path: root/pkgs/games/gog/albion/xdg-paths.patch
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/games/gog/albion/xdg-paths.patch')
-rw-r--r--pkgs/games/gog/albion/xdg-paths.patch259
1 files changed, 259 insertions, 0 deletions
diff --git a/pkgs/games/gog/albion/xdg-paths.patch b/pkgs/games/gog/albion/xdg-paths.patch
new file mode 100644
index 00000000..13ba4a1c
--- /dev/null
+++ b/pkgs/games/gog/albion/xdg-paths.patch
@@ -0,0 +1,259 @@
+diff --git a/games/Albion/SR-Main/virtualfs.c b/games/Albion/SR-Main/virtualfs.c
+index 34e0544..7d3acec 100644
+--- a/games/Albion/SR-Main/virtualfs.c
++++ b/games/Albion/SR-Main/virtualfs.c
+@@ -22,7 +22,9 @@
+  *
+  */
+ 
++#define _GNU_SOURCE
+ #define _FILE_OFFSET_BITS 64
++#include <fcntl.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <malloc.h>
+@@ -283,6 +285,177 @@ void vfs_visit_dir(file_entry *vdir)
+     vdir->dir_visited = 1;
+ }
+ 
++#define CONCAT_ENV(path) \
++    if (asprintf(&result, "%s/%s", env, path) == -1) { \
++        perror("asprintf"); \
++        exit(1); \
++    }
++
++#define DEFINE_XDG_GETTER(fun_name, envar, fallback) \
++    static char *fun_name(void) { \
++        const char *env; \
++        static char *result = NULL; \
++        if (result == NULL) { \
++            if ((env = getenv(envar)) != NULL) { \
++                CONCAT_ENV("albion"); \
++            } else if ((env = getenv("HOME")) != NULL) { \
++                CONCAT_ENV(fallback "/albion"); \
++            } else { \
++                fputs("Unable to determine " envar " or HOME.\n", stderr); \
++                exit(1); \
++            } \
++        } \
++        return result; \
++    }
++
++DEFINE_XDG_GETTER(getDataDir, "XDG_DATA_HOME", ".local/share");
++DEFINE_XDG_GETTER(getConfigDir, "XDG_CONFIG_HOME", ".config");
++
++static int makeDirs(const char *path)
++{
++    char *buf, *p;
++
++    if (*path == '\0')
++        return 1;
++
++    if ((buf = strdup(path)) == NULL)
++        return 1;
++
++    for (p = buf + 1; *p != '\0'; p++) {
++        if (*p != '/') continue;
++        *p = '\0';
++        mkdir(buf, 0777);
++        *p = '/';
++    }
++
++    mkdir(buf, 0777);
++
++    free(buf);
++    return 0;
++}
++
++typedef struct {
++    file_entry *dir;
++    const char *root;
++} unix_dir_cache_t;
++
++unix_dir_cache_t *unixDirCache[100];
++
++static void setUnixDir(const char *root, file_entry **dir)
++{
++    int i;
++    file_entry *newdir;
++
++    if (dir == NULL)
++        return;
++
++    for (i = 0; unixDirCache[i] != NULL; ++i) {
++        if (strcmp(unixDirCache[i]->root, root) == 0) {
++            *dir = unixDirCache[i]->dir;
++            return;
++        }
++    }
++
++    if ((newdir = (file_entry *)malloc(sizeof(file_entry))) == NULL)
++        return;
++
++    memset(newdir, 0, sizeof(file_entry));
++
++    newdir->dos_name[0] = 'X';
++    newdir->dos_name[1] = ':';
++    newdir->dos_name[2] = '\0';
++
++    newdir->real_name[0] = '.';
++    newdir->real_name[1] = '\0';
++
++    newdir->dos_fullname = strdup(newdir->dos_name);
++    newdir->real_fullname = strdup(root);
++
++    newdir->attributes = 1;
++    newdir->dir_visited = 0;
++
++    newdir->parent = newdir;
++    newdir->next = NULL;
++    newdir->prev = NULL;
++    newdir->first_child = NULL;
++    *dir = newdir;
++
++    unixDirCache[i] = (unix_dir_cache_t*)malloc(sizeof(unix_dir_cache_t));
++    if (unixDirCache[i] != NULL) {
++        makeDirs(root);
++        unixDirCache[i]->root = strdup(root);
++        unixDirCache[i]->dir = newdir;
++    }
++}
++
++static const char *manglePath(const char *xdg_path, const char *subdir,
++                              const char *path, file_entry **dir)
++{
++    char *buf;
++
++    if (*path == '/' || *path == '\\')
++        path++;
++
++    if (subdir == NULL) {
++        setUnixDir(xdg_path, dir);
++        return path;
++    }
++
++    if (asprintf(&buf, "%s/%s", xdg_path, subdir) == -1)
++        return NULL;
++
++    setUnixDir(buf, dir);
++    free(buf);
++    return path;
++}
++
++#define MANGLE_PATH(xdgpath, subdir, off) \
++    origdosname = manglePath(xdgpath, subdir, origdosname + off, &parse_dir)
++
++static void maybeCreateSetupIni()
++{
++    char *buf;
++    int fd_in, fd_out;
++    static int done = 0;
++
++    if (done) return;
++
++    if (asprintf(&buf, "%s/%s", getConfigDir(), "setup.ini") == -1) {
++        return;
++    }
++
++    if (access(buf, F_OK) == 0) {
++        done = 1;
++        free(buf);
++        return;
++    }
++
++    makeDirs(getConfigDir());
++
++    fd_out = open(buf, O_WRONLY | O_CREAT, 0666);
++    free(buf);
++
++    if (fd_out == -1)
++        return;
++
++    if ((fd_in = open("@SETUP_INI_PATH@", O_RDONLY)) == -1) {
++        close(fd_out);
++        return;
++    }
++
++    buf = malloc(8192);
++
++    while (1) {
++        ssize_t result = read(fd_in, buf, 8192);
++        if (result == -1 || result == 0) break;
++        if (write(fd_out, buf, result) != result) break;
++    }
++
++    close(fd_in);
++    close(fd_out);
++    done = 1;
++}
++
+ /*
+ return value:
+ 0 - dos path found (realdir = found entry)
+@@ -292,9 +465,20 @@ return value:
+ int vfs_get_real_name(const char *origdosname, char *buf, file_entry **realdir)
+ {
+     char upperdosname[MAX_PATH], *dosname, *backslash;
+-    file_entry *parse_dir, *new_parse_dir;
++    file_entry *parse_dir = NULL, *new_parse_dir;
+     int ret;
+ 
++    if (strncasecmp(origdosname, "xldlibs\\current", 15) == 0) {
++        MANGLE_PATH(getDataDir(), "chars", 15);
++    } else if (strncasecmp(origdosname, "saves", 5) == 0) {
++        MANGLE_PATH(getDataDir(), "saves", 5);
++    } else if (strncasecmp(origdosname, "setup.ini", 10) == 0) {
++        maybeCreateSetupIni();
++        MANGLE_PATH(getConfigDir(), NULL, 0);
++    } else if (strncasecmp(origdosname, "setup.tmp", 10) == 0) {
++        MANGLE_PATH(getConfigDir(), NULL, 0);
++    }
++
+     // convert dos name to uppercase
+     {
+         int i;
+@@ -316,28 +500,30 @@ int vfs_get_real_name(const char *origdosname, char *buf, file_entry **realdir)
+ 
+ 
+     // find initial directory for parsing
+-    if (dosname[0] == '\\')
+-    {
+-        parse_dir = &Game_CDir;
+-        dosname++;
+-    }
+-    else if (dosname[0] == 'C' && dosname[1] == ':')
+-    {
+-        if (dosname[2] == '\\')
++    if (parse_dir == NULL) {
++        if (dosname[0] == '\\')
+         {
+             parse_dir = &Game_CDir;
+-            dosname+=3;
++            dosname++;
++        }
++        else if (dosname[0] == 'C' && dosname[1] == ':')
++        {
++            if (dosname[2] == '\\')
++            {
++                parse_dir = &Game_CDir;
++                dosname+=3;
++            }
++            else
++            {
++                parse_dir = Game_Current_Dir;
++                dosname+=2;
++            }
+         }
+         else
+         {
+             parse_dir = Game_Current_Dir;
+-            dosname+=2;
+         }
+     }
+-    else
+-    {
+-        parse_dir = Game_Current_Dir;
+-    }
+ 
+     // find directory
+     for (backslash = strchr(dosname, '\\'); backslash != NULL; backslash = strchr(dosname, '\\'))