diff --git a/src/m_misc.h b/src/m_misc.h index 47db77bb77..8f375b9309 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -53,6 +53,7 @@ FString M_ZLibError(int zerrnum); #ifdef __unix__ FString GetUserFile (const char *path); // Prepends ~/.zdoom to path #endif +FString M_GetAppDataPath(bool create); FString M_GetCachePath(bool create); FString M_GetAutoexecPath(); FString M_GetCajunPath(const char *filename); diff --git a/src/posix/osx/i_specialpaths.mm b/src/posix/osx/i_specialpaths.mm index 843fb82d6c..fbb32cec69 100644 --- a/src/posix/osx/i_specialpaths.mm +++ b/src/posix/osx/i_specialpaths.mm @@ -39,6 +39,35 @@ #include "m_misc.h" #include "version.h" // for GAMENAME +//=========================================================================== +// +// M_GetAppDataPath macOS +// +// Returns the path for the AppData folder. +// +//=========================================================================== + +FString M_GetAppDataPath(bool create) +{ + FString path; + + char pathstr[PATH_MAX]; + FSRef folder; + + if (noErr == FSFindFolder(kUserDomain, kApplicationSupportFolderType, create ? kCreateFolder : 0, &folder) && + noErr == FSRefMakePath(&folder, (UInt8*)pathstr, PATH_MAX)) + { + path = pathstr; + } + else + { + path = progdir; + } + path += "/" GAMENAMELOWERCASE; + if (create) CreatePath(path); + return path; +} + //=========================================================================== // // M_GetCachePath macOS @@ -64,6 +93,7 @@ FString M_GetCachePath(bool create) path = progdir; } path += "/zdoom/cache"; + if (create) CreatePath(path); return path; } diff --git a/src/posix/unix/i_specialpaths.cpp b/src/posix/unix/i_specialpaths.cpp index 5dedba0578..581fda5d50 100644 --- a/src/posix/unix/i_specialpaths.cpp +++ b/src/posix/unix/i_specialpaths.cpp @@ -98,6 +98,26 @@ FString GetUserFile (const char *file) return path; } +//=========================================================================== +// +// M_GetAppDataPath Unix +// +// Returns the path for the AppData folder. +// +//=========================================================================== + +FString M_GetAppDataPath(bool create) +{ + // Don't use GAME_DIR and such so that ZDoom and its child ports can + // share the node cache. + FString path = NicePath("~/.config/" GAMENAMELOWERCASE); + if (create) + { + CreatePath(path); + } + return path; +} + //=========================================================================== // // M_GetCachePath Unix diff --git a/src/sound/mididevices/music_timiditypp_mididevice.cpp b/src/sound/mididevices/music_timiditypp_mididevice.cpp index d4c03534d4..42733ce385 100644 --- a/src/sound/mididevices/music_timiditypp_mididevice.cpp +++ b/src/sound/mididevices/music_timiditypp_mididevice.cpp @@ -43,6 +43,7 @@ #include "templates.h" #include "version.h" #include "tmpfileplus.h" +#include "m_misc.h" #ifndef _WIN32 #include @@ -82,7 +83,7 @@ public: protected: bool LaunchTimidity(); - char* DiskName; + FString DiskName; #ifdef _WIN32 HANDLE ReadWavePipe; HANDLE WriteWavePipe; @@ -165,8 +166,7 @@ CUSTOM_CVAR (Int, timidity_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // //========================================================================== -TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) - : DiskName(nullptr), +TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) : #ifdef _WIN32 ReadWavePipe(INVALID_HANDLE_VALUE), WriteWavePipe(INVALID_HANDLE_VALUE), ChildProcess(INVALID_HANDLE_VALUE), @@ -204,10 +204,9 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) TimidityPPMIDIDevice::~TimidityPPMIDIDevice () { - if (nullptr != DiskName) + if (DiskName.IsNotEmpty()) { remove(DiskName); - free(DiskName); } #if _WIN32 @@ -257,7 +256,10 @@ bool TimidityPPMIDIDevice::Preprocess(MIDIStreamer *song, bool looping) // Write MIDI song to temporary file song->CreateSMF(midi, looping ? 0 : 1); - f = tmpfileplus(nullptr, "zmid", &DiskName, 1); + FString path = M_GetAppDataPath(false); + path += "/tmp"; + CreatePath(path); + f = tmpfileplus(path, "zmid", &DiskName, 1); if (f == NULL) { Printf(PRINT_BOLD, "Could not open temp music file\n"); @@ -454,7 +456,7 @@ bool TimidityPPMIDIDevice::ValidateTimidity() bool TimidityPPMIDIDevice::LaunchTimidity () { - if (ExeName.IsEmpty() || nullptr == DiskName) + if (ExeName.IsEmpty() || DiskName.IsEmpty()) { return false; } @@ -565,7 +567,7 @@ bool TimidityPPMIDIDevice::LaunchTimidity () arglist.push_back("-"); arglist.push_back(outmodearg.c_str()); arglist.push_back(ifacearg.c_str()); - arglist.push_back(DiskName); + arglist.push_back(DiskName.GetChars()); DPrintf(DMSG_NOTIFY, "Timidity EXE: \x1cG%s\n", exename); int i = 1; diff --git a/src/tmpfileplus.cpp b/src/tmpfileplus.cpp index 0ebb23185b..bfe021dbb3 100644 --- a/src/tmpfileplus.cpp +++ b/src/tmpfileplus.cpp @@ -97,10 +97,9 @@ #include "m_random.h" #include "cmdlib.h" +#include "zstring.h" -#define FILE_SEPARATOR "/" - #define RANDCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" #define NRANDCHARS (sizeof(RANDCHARS) - 1) @@ -121,27 +120,13 @@ static char *set_randpart(char *s) return s; } -/** Call getenv and save a copy in buf */ -static char *getenv_save(const char *varname, char *buf, size_t bufsize) -{ - char *ptr = getenv(varname); - buf[0] = '\0'; - if (ptr) - { - strncpy(buf, ptr, bufsize); - buf[bufsize-1] = '\0'; - return buf; - } - return NULL; -} - /** * Try and create a randomly-named file in directory `tmpdir`. * If successful, allocate memory and set `tmpname_ptr` to full filepath, and return file pointer; * otherwise return NULL. * If `keep` is zero then create the file as temporary and it should not exist once closed. */ -static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmpname_ptr, int keep) +static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, FString *tmpname_ptr, int keep) /* PRE: * pfx is not NULL and points to a valid null-terminated string * tmpname_ptr is not NULL. @@ -150,9 +135,7 @@ static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmp FILE *fp; int fd; char randpart[] = "1234567890"; - size_t lentempname; int i; - char *tmpname = NULL; int oflag, pmode; /* In Windows, we use the _O_TEMPORARY flag with `open` to ensure the file is deleted when closed. @@ -176,18 +159,13 @@ static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmp return NULL; } - lentempname = strlen(tmpdir) + strlen(FILE_SEPARATOR) + strlen(pfx) + strlen(randpart); - tmpname = (char*)malloc(lentempname + 1); - if (!tmpname) - { - errno = ENOMEM; - return NULL; - } + FString tempname; + /* If we don't manage to create a file after 10 goes, there is something wrong... */ for (i = 0; i < 10; i++) { - sprintf(tmpname, "%s%s%s%s", tmpdir, FILE_SEPARATOR, pfx, set_randpart(randpart)); - fd = OPEN_(tmpname, oflag, pmode); + tempname.Format("%s/%s%s", tmpdir, pfx, set_randpart(randpart)); + fd = OPEN_(tempname, oflag, pmode); if (fd != -1) break; } if (fd != -1) @@ -205,13 +183,8 @@ static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmp { /* We failed */ fp = NULL; } - if (!fp) - { - free(tmpname); - tmpname = NULL; - } - *tmpname_ptr = tmpname; + if (tmpname_ptr) *tmpname_ptr = tempname; return fp; } @@ -219,47 +192,10 @@ static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmp /* EXPORTED FUNCTIONS */ /**********************/ -FILE *tmpfileplus(const char *dir, const char *prefix, char **pathname, int keep) +FILE *tmpfileplus(const char *dir, const char *prefix, FString *pathname, int keep) { - FILE *fp = NULL; - char *tmpname = NULL; - char *tmpdir = NULL; - const char *pfx = (prefix ? prefix : "tmp."); - char *tempdirs[12] = { 0 }; - char env1[FILENAME_MAX+1] = { 0 }; - char env2[FILENAME_MAX+1] = { 0 }; - char env3[FILENAME_MAX+1] = { 0 }; - int ntempdirs = 0; - int i; - - /* Set up a list of temp directories we will try in order */ - i = 0; - tempdirs[i++] = (char *)dir; -#ifdef _WIN32 - tempdirs[i++] = getenv_save("TMP", env1, sizeof(env1)); - tempdirs[i++] = getenv_save("TEMP", env2, sizeof(env2)); -#else - tempdirs[i++] = getenv_save("TMPDIR", env3, sizeof(env3)); - tempdirs[i++] = P_tmpdir; -#endif - tempdirs[i++] = "."; - ntempdirs = i; - - errno = 0; - - /* Work through list we set up before, and break once we are successful */ - for (i = 0; i < ntempdirs; i++) - { - tmpdir = tempdirs[i]; - fp = mktempfile_internal(tmpdir, pfx, &tmpname, keep); - if (fp) break; - } - /* If we succeeded and the user passed a pointer, set it to the alloc'd pathname: the user must free this */ - if (fp && pathname) - *pathname = tmpname; - else /* Otherwise, free the alloc'd memory */ - free(tmpname); - + FILE *fp = mktempfile_internal(dir, (prefix ? prefix : "tmp."), pathname, keep); + if (!fp && pathname) *pathname = ""; return fp; } diff --git a/src/tmpfileplus.h b/src/tmpfileplus.h index 07b5ca0d54..06219edd6f 100644 --- a/src/tmpfileplus.h +++ b/src/tmpfileplus.h @@ -23,6 +23,8 @@ #include +class FString; + /** Create a unique temporary file. @param dir (optional) directory to create file. If NULL use default TMP directory. @param prefix (optional) prefix for file name. If NULL use "tmp.". @@ -33,7 +35,7 @@ @return Pointer to stream opened in binary read/write (w+b) mode, or a null pointer on error. @exception ENOMEM Not enough memory to allocate filename. */ -FILE *tmpfileplus(const char *dir, const char *prefix, char **pathname, int keep); +FILE *tmpfileplus(const char *dir, const char *prefix, FString *pathname, int keep); #define TMPFILE_KEEP 1 diff --git a/src/win32/i_specialpaths.cpp b/src/win32/i_specialpaths.cpp index 58c87a8ca8..4a790798f1 100644 --- a/src/win32/i_specialpaths.cpp +++ b/src/win32/i_specialpaths.cpp @@ -153,6 +153,33 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create } } +//=========================================================================== +// +// M_GetAppDataPath Windows +// +// Returns the path for the AppData folder. +// +//=========================================================================== + +FString M_GetAppDataPath(bool create) +{ + FString path; + + if (!GetKnownFolder(CSIDL_LOCAL_APPDATA, FOLDERID_LocalAppData, create, path)) + { // Failed (e.g. On Win9x): use program directory + path = progdir; + } + // Don't use GAME_DIR and such so that ZDoom and its child ports can + // share the node cache. + path += "/" GAMENAMELOWERCASE; + path.Substitute("//", "/"); // needed because progdir ends with a slash. + if (create) + { + CreatePath(path); + } + return path; +} + //=========================================================================== // // M_GetCachePath Windows @@ -173,6 +200,10 @@ FString M_GetCachePath(bool create) // share the node cache. path += "/zdoom/cache"; path.Substitute("//", "/"); // needed because progdir ends with a slash. + if (create) + { + CreatePath(path); + } return path; }