Added PHYSFS_getPrefDir().
This commit is contained in:
parent
584119a4a0
commit
24d6a925d1
|
@ -6,11 +6,6 @@ Some might be dupes, some might be done already, some might be bad ideas.
|
|||
|
||||
From http://icculus.org/pipermail/physfs/2009-March/000698.html ...
|
||||
|
||||
- Add an API to find the "pref path" ... this is the directory where an
|
||||
app's configuration data is supposed to go...which is usually somewhere
|
||||
under the user directory, but not always. As it is platform-dependent,
|
||||
platform-version dependent and sometimes even user-dependent, this should be
|
||||
handled by the library and not the app.
|
||||
- Archives formats provided by the implementation.
|
||||
- Write support for various archives. I haven't decided how to do this yet,
|
||||
but I'd like to.
|
||||
|
@ -50,7 +45,6 @@ From old TODO.txt...
|
|||
- Use __cdecl in physfs.h?
|
||||
- Look for FIXMEs (many marked with "!!!" in comments).
|
||||
- Find some way to relax or remove the security model for external tools.
|
||||
- OSX shouldn't use ~/.app for userdir.
|
||||
- fscanf and fprintf support in extras dir.
|
||||
- Why do we call it openArchive and dirClose?
|
||||
- Sanity check byte order at runtime.
|
||||
|
|
|
@ -91,6 +91,7 @@
|
|||
%rename(unmount) PHYSFS_unmount;
|
||||
%rename(mountMemory) PHYSFS_mountMemory;
|
||||
%rename(mountHandle) PHYSFS_mountHandle;
|
||||
%rename(getPrefDir) PHYSFS_getPrefDir;
|
||||
#endif
|
||||
|
||||
%include "../src/physfs.h"
|
||||
|
|
54
src/physfs.c
54
src/physfs.c
|
@ -135,6 +135,7 @@ static FileHandle *openWriteList = NULL;
|
|||
static FileHandle *openReadList = NULL;
|
||||
static char *baseDir = NULL;
|
||||
static char *userDir = NULL;
|
||||
static char *prefDir = NULL;
|
||||
static int allowSymLinks = 0;
|
||||
|
||||
/* mutexes ... */
|
||||
|
@ -1312,6 +1313,12 @@ int PHYSFS_deinit(void)
|
|||
userDir = NULL;
|
||||
} /* if */
|
||||
|
||||
if (prefDir != NULL)
|
||||
{
|
||||
allocator.Free(prefDir);
|
||||
prefDir = NULL;
|
||||
} /* if */
|
||||
|
||||
allowSymLinks = 0;
|
||||
initialized = 0;
|
||||
|
||||
|
@ -1370,15 +1377,60 @@ void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback callback, void *data)
|
|||
} /* PHYSFS_getCdRomDirsCallback */
|
||||
|
||||
|
||||
const char *PHYSFS_getPrefDir(const char *org, const char *app)
|
||||
{
|
||||
const char dirsep = __PHYSFS_platformDirSeparator;
|
||||
char *ptr = NULL;
|
||||
PHYSFS_Stat statbuf;
|
||||
int exists = 0;
|
||||
|
||||
BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0);
|
||||
BAIL_IF_MACRO(!org, PHYSFS_ERR_INVALID_ARGUMENT, NULL);
|
||||
BAIL_IF_MACRO(*org == '\0', PHYSFS_ERR_INVALID_ARGUMENT, NULL);
|
||||
BAIL_IF_MACRO(!app, PHYSFS_ERR_INVALID_ARGUMENT, NULL);
|
||||
BAIL_IF_MACRO(*app == '\0', PHYSFS_ERR_INVALID_ARGUMENT, NULL);
|
||||
|
||||
allocator.Free(prefDir);
|
||||
prefDir = __PHYSFS_platformCalcPrefDir(org, app);
|
||||
BAIL_IF_MACRO(!prefDir, ERRPASS, NULL);
|
||||
|
||||
#if !PHYSFS_PLATFORM_WINDOWS /* Windows guarantees the dir exists here. */
|
||||
if (__PHYSFS_platformStat(prefDir, &exists, &statbuf))
|
||||
return prefDir;
|
||||
|
||||
for (ptr = strchr(prefDir, dirsep); ptr; ptr = strchr(ptr+1, dirsep))
|
||||
{
|
||||
*ptr = '\0';
|
||||
__PHYSFS_platformMkDir(prefDir);
|
||||
*ptr = dirsep;
|
||||
} /* for */
|
||||
|
||||
if (!__PHYSFS_platformMkDir(prefDir))
|
||||
{
|
||||
allocator.Free(prefDir);
|
||||
prefDir = NULL;
|
||||
} /* if */
|
||||
#endif
|
||||
|
||||
return prefDir;
|
||||
} /* PHYSFS_getPrefDir */
|
||||
|
||||
|
||||
const char *PHYSFS_getBaseDir(void)
|
||||
{
|
||||
return baseDir; /* this is calculated in PHYSFS_init()... */
|
||||
} /* PHYSFS_getBaseDir */
|
||||
|
||||
|
||||
const char *PHYSFS_getUserDir(void)
|
||||
const char *__PHYSFS_getUserDir(void) /* not deprecated internal version. */
|
||||
{
|
||||
return userDir; /* this is calculated in PHYSFS_init()... */
|
||||
} /* __PHYSFS_getUserDir */
|
||||
|
||||
|
||||
const char *PHYSFS_getUserDir(void)
|
||||
{
|
||||
return __PHYSFS_getUserDir();
|
||||
} /* PHYSFS_getUserDir */
|
||||
|
||||
|
||||
|
|
81
src/physfs.h
81
src/physfs.h
|
@ -111,7 +111,7 @@
|
|||
* use the base dir for both searching and writing. There is a helper
|
||||
* function (PHYSFS_setSaneConfig()) that puts together a basic configuration
|
||||
* for you, based on a few parameters. Also see the comments on
|
||||
* PHYSFS_getBaseDir(), and PHYSFS_getUserDir() for info on what those
|
||||
* PHYSFS_getBaseDir(), and PHYSFS_getPrefDir() for info on what those
|
||||
* are and how they can help you determine an optimal search path.
|
||||
*
|
||||
* PhysicsFS 2.0 adds the concept of "mounting" archives to arbitrary points
|
||||
|
@ -765,7 +765,7 @@ PHYSFS_DECL char **PHYSFS_getCdRomDirs(void);
|
|||
*
|
||||
* \return READ ONLY string of base dir in platform-dependent notation.
|
||||
*
|
||||
* \sa PHYSFS_getUserDir
|
||||
* \sa PHYSFS_getPrefDir
|
||||
*/
|
||||
PHYSFS_DECL const char *PHYSFS_getBaseDir(void);
|
||||
|
||||
|
@ -774,6 +774,8 @@ PHYSFS_DECL const char *PHYSFS_getBaseDir(void);
|
|||
* \fn const char *PHYSFS_getUserDir(void)
|
||||
* \brief Get the path where user's home directory resides.
|
||||
*
|
||||
* \deprecated As of PhysicsFS 2.1, you probably want PHYSFS_getPrefDir().
|
||||
*
|
||||
* Helper function.
|
||||
*
|
||||
* Get the "user dir". This is meant to be a suggestion of where a specific
|
||||
|
@ -783,14 +785,12 @@ PHYSFS_DECL const char *PHYSFS_getBaseDir(void);
|
|||
* where "username" will either be the login name, or "default" if the
|
||||
* platform doesn't support multiple users, either.
|
||||
*
|
||||
* You should probably use the user dir as the basis for your write dir, and
|
||||
* also put it near the beginning of your search path.
|
||||
*
|
||||
* \return READ ONLY string of user dir in platform-dependent notation.
|
||||
*
|
||||
* \sa PHYSFS_getBaseDir
|
||||
* \sa PHYSFS_getPrefDir
|
||||
*/
|
||||
PHYSFS_DECL const char *PHYSFS_getUserDir(void);
|
||||
PHYSFS_DECL const char *PHYSFS_getUserDir(void) PHYSFS_DEPRECATED;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -3230,6 +3230,75 @@ PHYSFS_DECL const char *PHYSFS_getErrorByCode(PHYSFS_ErrorCode code);
|
|||
*/
|
||||
PHYSFS_DECL void PHYSFS_setErrorCode(PHYSFS_ErrorCode code);
|
||||
|
||||
|
||||
/**
|
||||
* \fn const char *PHYSFS_getPrefDir(const char *org, const char *app)
|
||||
* \brief Get the user-and-app-specific path where files can be written.
|
||||
*
|
||||
* Helper function.
|
||||
*
|
||||
* Get the "pref dir". This is meant to be where users can write personal
|
||||
* files (preferences and save games, etc) that are specific to your
|
||||
* application. This directory is unique per user, per application.
|
||||
*
|
||||
* This function will decide the appropriate location in the native filesystem,
|
||||
* create the directory if necessary, and return a string in
|
||||
* platform-dependent notation, suitable for passing to PHYSFS_setWriteDir().
|
||||
*
|
||||
* On Windows, this might look like:
|
||||
* "C:\\Users\\bob\\AppData\\Roaming\\My Company\\My Program Name"
|
||||
*
|
||||
* On Linux, this might look like:
|
||||
* "/home/bob/.local/share/My Program Name"
|
||||
*
|
||||
* On Mac OS X, this might look like:
|
||||
* "/Users/bob/Library/Application Support/My Program Name"
|
||||
*
|
||||
* (etc.)
|
||||
*
|
||||
* You should probably use the pref dir for your write dir, and also put it
|
||||
* near the beginning of your search path. Older versions of PhysicsFS
|
||||
* offered only PHYSFS_getUserDir() and left you to figure out where the
|
||||
* files should go under that tree. This finds the correct location
|
||||
* for whatever platform, which not only changes between operating systems,
|
||||
* but also versions of the same operating system.
|
||||
*
|
||||
* You specify the name of your organization (if it's not a real organization,
|
||||
* your name or an Internet domain you own might do) and the name of your
|
||||
* application. These should be proper names.
|
||||
*
|
||||
* Both the (org) and (app) strings may become part of a directory name, so
|
||||
* please follow these rules:
|
||||
*
|
||||
* - Try to use the same org string (including case-sensitivity) for
|
||||
* all your applications that use this function.
|
||||
* - Always use a unique app string for each one, and make sure it never
|
||||
* changes for an app once you've decided on it.
|
||||
* - Unicode characters are legal, as long as it's UTF-8 encoded, but...
|
||||
* - ...only use letters, numbers, and spaces. Avoid punctuation like
|
||||
* "Game Name 2: Bad Guy's Revenge!" ... "Game Name 2" is sufficient.
|
||||
*
|
||||
* The pointer returned by this function remains valid until you call this
|
||||
* function again, or call PHYSFS_deinit(). This is not necessarily a fast
|
||||
* call, though, so you should call this once at startup and copy the string
|
||||
* if you need it.
|
||||
*
|
||||
* You should assume the path returned by this function is the only safe
|
||||
* place to write files (and that PHYSFS_getUserDir() and PHYSFS_getBaseDir(),
|
||||
* while they might be writable, or even parents of the returned path, aren't
|
||||
* where you should be writing things).
|
||||
*
|
||||
* \param org The name of your organization.
|
||||
* \param app The name of your application.
|
||||
* \return READ ONLY string of user dir in platform-dependent notation. NULL
|
||||
* if there's a problem (creating directory failed, etc).
|
||||
*
|
||||
* \sa PHYSFS_getBaseDir
|
||||
* \sa PHYSFS_getUserDir
|
||||
*/
|
||||
PHYSFS_DECL const char *PHYSFS_getPrefDir(const char *org, const char *app);
|
||||
|
||||
|
||||
/* Everything above this line is part of the PhysicsFS 2.1 API. */
|
||||
|
||||
|
||||
|
|
|
@ -633,13 +633,26 @@ char *__PHYSFS_platformCalcBaseDir(const char *argv0);
|
|||
*/
|
||||
char *__PHYSFS_platformGetUserName(void);
|
||||
|
||||
/*
|
||||
/* !!! FIXME: should this be CalcUserDir, to match CalcBaseDir?
|
||||
* Get the platform-specific user dir.
|
||||
* Caller will allocator.Free() the retval if it's not NULL. If it's NULL,
|
||||
* the userdir will default to basedir/username.
|
||||
*/
|
||||
char *__PHYSFS_platformGetUserDir(void);
|
||||
|
||||
|
||||
/* This is the cached version from PHYSFS_init(). This is a fast call. */
|
||||
const char *__PHYSFS_getUserDir(void); /* not deprecated internal version. */
|
||||
|
||||
/*
|
||||
* Get the platform-specific pref dir.
|
||||
* Caller will allocator.Free() the retval if it's not NULL. If it's NULL,
|
||||
* it's a total failure. Caller will make missing directories if necessary;
|
||||
* this just reports the final path.
|
||||
*/
|
||||
char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app);
|
||||
|
||||
|
||||
/*
|
||||
* Return a pointer that uniquely identifies the current thread.
|
||||
* On a platform without threading, (0x1) will suffice. These numbers are
|
||||
|
|
|
@ -183,6 +183,19 @@ char *__PHYSFS_platformCalcBaseDir(const char *argv0)
|
|||
} /* __PHYSFS_platformCalcBaseDir */
|
||||
|
||||
|
||||
char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
|
||||
{
|
||||
/* !!! FIXME: there's a real API to determine this */
|
||||
const char *userdir = __PHYSFS_getUserDir();
|
||||
const char *append = "config/settings/";
|
||||
const size_t len = strlen(userdir) + strlen(append) + strlen(app) + 1;
|
||||
char *retval = allocator.Malloc(len);
|
||||
BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
|
||||
snprintf(retval, len, "%s%s%s", userdir, append, app);
|
||||
return retval;
|
||||
} /* __PHYSFS_platformCalcPrefDir */
|
||||
|
||||
|
||||
void *__PHYSFS_platformGetThreadID(void)
|
||||
{
|
||||
return (void *) find_thread(NULL);
|
||||
|
|
|
@ -289,6 +289,19 @@ char *__PHYSFS_platformCalcBaseDir(const char *argv0)
|
|||
} /* __PHYSFS_platformCalcBaseDir */
|
||||
|
||||
|
||||
char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
|
||||
{
|
||||
/* !!! FIXME: there's a real API to determine this */
|
||||
const char *userdir = __PHYSFS_getUserDir();
|
||||
const char *append = "Library/Application Support/";
|
||||
const size_t len = strlen(userdir) + strlen(append) + strlen(app) + 1;
|
||||
char *retval = allocator.Malloc(len);
|
||||
BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
|
||||
snprintf(retval, len, "%s%s%s", userdir, append, app);
|
||||
return retval;
|
||||
} /* __PHYSFS_platformCalcPrefDir */
|
||||
|
||||
|
||||
/* Platform allocator uses default CFAllocator at PHYSFS_init() time. */
|
||||
|
||||
static CFAllocatorRef cfallocdef = NULL;
|
||||
|
|
|
@ -293,6 +293,36 @@ char *__PHYSFS_platformCalcBaseDir(const char *argv0)
|
|||
} /* __PHYSFS_platformCalcBaseDir */
|
||||
|
||||
|
||||
char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
|
||||
{
|
||||
/*
|
||||
* We use XDG's base directory spec, even if you're not on Linux.
|
||||
* This isn't strictly correct, but the results are relatively sane
|
||||
* in any case.
|
||||
*
|
||||
* http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
*/
|
||||
const char *envr = getenv("XDG_DATA_HOME");
|
||||
const char *append = "/";
|
||||
char *retval = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
if (!envr)
|
||||
{
|
||||
/* You end up with "$HOME/.local/share/Game Name 2" */
|
||||
envr = __PHYSFS_getUserDir();
|
||||
BAIL_IF_MACRO(!envr, ERRPASS, NULL); /* oh well. */
|
||||
append = ".local/share/";
|
||||
} /* if */
|
||||
|
||||
len = strlen(envr) + strlen(append) + strlen(app) + 1;
|
||||
retval = (char *) allocator.Malloc(len);
|
||||
BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
|
||||
snprintf(retval, len, "%s%s%s", envr, append, app);
|
||||
return retval;
|
||||
} /* __PHYSFS_platformCalcPrefDir */
|
||||
|
||||
|
||||
int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
|
||||
{
|
||||
return 0; /* just use malloc() and friends. */
|
||||
|
|
|
@ -88,6 +88,7 @@ typedef struct
|
|||
} WinApiFile;
|
||||
|
||||
|
||||
/* !!! FIXME: we cache userDir in physfs.c during PHYSFS_init(), too. */
|
||||
static char *userDir = NULL;
|
||||
static HANDLE libUserEnv = NULL;
|
||||
static HANDLE detectCDThreadHandle = NULL;
|
||||
|
@ -441,6 +442,22 @@ char *__PHYSFS_platformCalcBaseDir(const char *argv0)
|
|||
} /* __PHYSFS_platformCalcBaseDir */
|
||||
|
||||
|
||||
char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
|
||||
{
|
||||
// Vista and later has a new API for this, but SHGetFolderPath works there,
|
||||
// and apparently just wraps the new API. This is the new way to do it:
|
||||
// SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_CREATE,
|
||||
// NULL, &wszPath);
|
||||
|
||||
WCHAR path[MAX_PATH];
|
||||
if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE,
|
||||
NULL, 0, path)))
|
||||
BAIL_MACRO(PHYSFS_ERR_OS_ERROR, NULL);
|
||||
|
||||
return unicodeToUtf8Heap(path);
|
||||
} /* __PHYSFS_platformCalcPrefDir */
|
||||
|
||||
|
||||
char *__PHYSFS_platformGetUserName(void)
|
||||
{
|
||||
DWORD bufsize = 0;
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
|
||||
#include <time.h>
|
||||
|
||||
/* Define this, so the compiler doesn't complain about using old APIs. */
|
||||
#define PHYSFS_DEPRECATED
|
||||
|
||||
#include "physfs.h"
|
||||
|
||||
#define TEST_VERSION_MAJOR 2
|
||||
|
@ -386,6 +389,19 @@ static int cmd_getuserdir(char *args)
|
|||
} /* cmd_getuserdir */
|
||||
|
||||
|
||||
static int cmd_getprefdir(char *args)
|
||||
{
|
||||
char *org;
|
||||
char *appName;
|
||||
char *ptr = args;
|
||||
|
||||
org = ptr;
|
||||
ptr = strchr(ptr, ' '); *ptr = '\0'; ptr++; appName = ptr;
|
||||
printf("Pref dir is [%s].\n", PHYSFS_getPrefDir(org, appName));
|
||||
return 1;
|
||||
} /* cmd_getprefdir */
|
||||
|
||||
|
||||
static int cmd_getwritedir(char *args)
|
||||
{
|
||||
printf("Write dir is [%s].\n", PHYSFS_getWriteDir());
|
||||
|
@ -1130,6 +1146,7 @@ static const command_info commands[] =
|
|||
{ "getsearchpath", cmd_getsearchpath, 0, NULL },
|
||||
{ "getbasedir", cmd_getbasedir, 0, NULL },
|
||||
{ "getuserdir", cmd_getuserdir, 0, NULL },
|
||||
{ "getprefdir", cmd_getprefdir, 2, "<org> <app>" },
|
||||
{ "getwritedir", cmd_getwritedir, 0, NULL },
|
||||
{ "setwritedir", cmd_setwritedir, 1, "<newWriteDir>" },
|
||||
{ "permitsymlinks", cmd_permitsyms, 1, "<1or0>" },
|
||||
|
|
|
@ -11,6 +11,7 @@ physfs::init("$0") or die("physfs::init('$0'): ".physfs::getLastError()."\n");
|
|||
|
||||
print "user dir: ", physfs::getUserDir(), "\n";
|
||||
print "base dir: ", physfs::getBaseDir(), "\n";
|
||||
print "pref dir: ", physfs::getPrefDir("icculus.org", "test_physfs"), "\n";
|
||||
|
||||
print "deinit...\n";
|
||||
physfs::deinit();
|
||||
|
|
|
@ -9,6 +9,7 @@ Physfs.init($0)
|
|||
|
||||
puts "user dir: " + Physfs.getUserDir()
|
||||
puts "base dir: " + Physfs.getBaseDir()
|
||||
puts "pref dir: " + Physfs.getPrefDir("icculus.org", "test_physfs")
|
||||
|
||||
puts "deinit..."
|
||||
Physfs.deinit()
|
||||
|
|
Loading…
Reference in New Issue