1
0
Fork 0

Use the XDG Base Directory Specification for storing game files

This commit is contained in:
John Zaitseff 2021-01-07 23:19:41 +11:00
parent 88dc3b54a5
commit b132686a63
4 changed files with 113 additions and 20 deletions

8
NEWS
View File

@ -25,6 +25,14 @@ __ https://www.zap.org.au/
Version 7.15 (not yet released)
-------------------------------
Changed the default location where game files are saved from `~/.trader`
to `~/.local/share/trader`, so as to follow the `XDG Base Directory
Specification`__. If set, the ``XDG_DATA_HOME`` environment variable
will override this location. If the `~/.trader` directory is already
present, it will continue to be used. Updated the manual page to suit.
__ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
Updated to GNU Gettext 0.20 or later. Updated to the latest snapshot of
the Gnulib GNU Portability Library. Also updated the `INSTALL` file to
list the latest tested versions of operating systems, including a new

View File

@ -154,6 +154,15 @@ Or, if you prefer the old amber screens of yesteryear:
.\" *********************************************************************
.SH ENVIRONMENT
.TP
.BR XDG_DATA_HOME ", " HOME
If \fBXDG_DATA_HOME\fR is set to an absolute pathname (that is, a path
that starts with \*(lq\fI/\fR\*(rq), Star Traders will use that
directory, with a subdirectory \fItrader\fR, to store game files. If
this environment variable is not set or does not start with
\*(lq\fI/\fR\*(rq, \fI\(ti/.local/share/trader\fR will be used instead,
where \*(lq\fI\(ti\fR\*(rq represents your home directory, as contained
in the \fBHOME\fR environment variable.
.TP
.BR LINES ", " COLUMNS
Star Traders uses the Curses library for displaying text on the screen.
As such, it will access these two environment variables if the underlying
@ -177,11 +186,17 @@ manual pages for more details on locale settings.
.\" *********************************************************************
.SH FILES
.TP
.IB \(ti/.local/share/trader/game N
Star Traders stores saved game files in the \fI.local/share/trader\fR
subdirectory in your home directory (unless overriden by the
\fBXDG_DATA_HOME\fR environment variable). \fIN\fR is a number between
\fB1\fR and \fB9\fR inclusive. The game file is scrambled to prevent you
or others from casually cheating!
.TP
.IB \(ti/.trader/game N
Star Traders stores saved game files in the \fI.trader\fR subdirectory in
your home directory. \fIN\fR is a number between \fB1\fR and \fB9\fR
inclusive. The game file is scrambled to prevent you or others from
casually cheating!
If the \fI\(ti/.trader\fR directory exists, game files will be read from
and saved to this location instead. This is for compatibility with
versions of Star Traders prior to version 7.15.
.\" *********************************************************************
.SH BUGS
None yet known...

View File

@ -53,6 +53,10 @@ wchar_t *mon_thousands_sep; // Locale's monetary thousands separator
* Module-specific constants and macros *
************************************************************************/
#define DIRSEP "/" // Directory separator
#define HIDDEN_PATH "." // Hidden file start char
#define XDG_DATA_DEFAULT ".local" DIRSEP "share"
#define GAME_FILENAME_PROTO "game%d"
#define GAME_FILENAME_BUFSIZE 16
@ -306,10 +310,15 @@ void init_program_name (const char *argv0)
/* This implementation assumes a POSIX environment with an ASCII-safe
character encoding (such as ASCII or UTF-8). */
const char *dirsep = DIRSEP;
assert(strlen(dirsep) == 1);
if (argv0 == NULL || *argv0 == '\0') {
program_name = PACKAGE;
} else {
char *p = strrchr(argv0, '/');
char *p = strrchr(argv0, dirsep[0]);
if (p != NULL && *++p != '\0') {
program_name = xstrdup(p);
@ -343,21 +352,74 @@ const char *home_directory (void)
const char *data_directory (void)
{
/* This implementation assumes a POSIX environment by using "/" as
/* This implementation assumes a POSIX environment by using DIRSEP as
the directory separator. It also assumes a dot-starting directory
name is permissible (again, true on POSIX systems) and that the
character encoding is ASCII-safe. */
const char *dirsep = DIRSEP;
const char *dirsep_hiddenpath = DIRSEP HIDDEN_PATH;
const char *datahome_part = DIRSEP XDG_DATA_DEFAULT DIRSEP;
struct stat statbuf;
assert(strlen(dirsep) == 1);
if (data_directory_str == NULL) {
const char *home = home_directory();
const char *xdg_data_home = getenv("XDG_DATA_HOME");
if (program_name != NULL && home != NULL) {
char *p = xmalloc(strlen(home) + strlen(program_name) + 3);
if (program_name != NULL) {
int len_program_name = strlen(program_name);
strcpy(p, home);
strcat(p, "/.");
strcat(p, program_name);
data_directory_str = p;
if (home != NULL) {
char *p = xmalloc(strlen(home) + strlen(dirsep_hiddenpath)
+ len_program_name + 1);
strcpy(p, home);
strcat(p, dirsep_hiddenpath);
strcat(p, program_name);
if (stat(p, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
// Directory "$HOME/.trader" exists: use that
data_directory_str = p;
} else {
free(p);
}
}
if (data_directory_str == NULL && xdg_data_home != NULL
&& *xdg_data_home != '\0' && *xdg_data_home == dirsep[0]) {
// Use directory "$XDG_DATA_HOME/trader"
/* Note that the XDG Base Directory Specification v0.7
requires XDG_DATA_HOME to contain an absolute path:
the variable must be ignored if it does not start with
the directory separator DIRSEP ("/") */
char *p = xmalloc(strlen(xdg_data_home) + strlen(DIRSEP)
+ len_program_name + 1);
strcpy(p, xdg_data_home);
strcat(p, dirsep);
strcat(p, program_name);
data_directory_str = p;
}
if (data_directory_str == NULL && home != NULL) {
// Use directory "$HOME/.local/share/trader"
char *p = xmalloc(strlen(home) + strlen(datahome_part)
+ len_program_name + 1);
strcpy(p, home);
strcat(p, datahome_part);
strcat(p, program_name);
data_directory_str = p;
}
}
}
@ -373,6 +435,8 @@ char *game_filename (int gamenum)
/* This implementation assumes a POSIX environment and an ASCII-safe
character encoding. */
const char *dirsep = DIRSEP;
char buf[GAME_FILENAME_BUFSIZE]; // Buffer for part of filename
const char *dd; // Data directory
@ -387,10 +451,10 @@ char *game_filename (int gamenum)
if (dd == NULL) {
return xstrdup(buf);
} else {
char *p = xmalloc(strlen(dd) + strlen(buf) + 2);
char *p = xmalloc(strlen(dd) + strlen(dirsep) + strlen(buf) + 1);
strcpy(p, dd);
strcat(p, "/");
strcat(p, dirsep);
strcat(p, buf);
return p;
}

View File

@ -99,12 +99,18 @@ extern const char *home_directory (void);
Parameters: (none)
Returns: const char * - Pointer to data directory
This function returns the full pathname to a potentially-writable
subdirectory within the user's home directory. Essentially, this
function returns home_directory() + "/." + program_name. Note that
this path is NOT created by this function, nor is the ability to write
to this path checked. NULL is returned if this path cannot be
determined.
This function returns the full pathname to a potentially-writable data
directory, usually within the user's home directory.
Assuming program_name is set to "trader", if "$HOME/.trader" exists,
that directory is returned as the data directory. Otherwise, if the
environment variable XDG_DATA_HOME is set and contains an absolute
pathname, "$XDG_DATA_HOME/trader" is returned. Otherwise,
"$HOME/.local/share/trader" is returned.
Note that the returned path is NOT created by this function, nor is the
ability to read from or write to this path checked. NULL is returned
if the path cannot be determined.
*/
extern const char *data_directory (void);