summaryrefslogtreecommitdiff
path: root/src/fileio.cpp
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2007-06-17 15:48:57 +0000
committerrubidium <rubidium@openttd.org>2007-06-17 15:48:57 +0000
commit347c28b71ac754aee20f8eeeae1df1a3b9a49d10 (patch)
tree8bc2a050b44170ed785af66e6e9045d429c789db /src/fileio.cpp
parent5fdde681c2aff0976eef8cea59422332527b3a65 (diff)
downloadopenttd-347c28b71ac754aee20f8eeeae1df1a3b9a49d10.tar.xz
(svn r10182) -Codechange: rewrite most part of the file loading/searching to be more flexible.
-Codechange: add support for personal directories on Windows. -Fix [FS#153, FS#193, FS#502, FS#816, FS#854]: fix issues related to fixed names, fixed places of files/directories and application bundles.
Diffstat (limited to 'src/fileio.cpp')
-rw-r--r--src/fileio.cpp221
1 files changed, 155 insertions, 66 deletions
diff --git a/src/fileio.cpp b/src/fileio.cpp
index f8173ab86..e79f54984 100644
--- a/src/fileio.cpp
+++ b/src/fileio.cpp
@@ -11,7 +11,9 @@
#include "variables.h"
#include "debug.h"
#include "fios.h"
-#ifndef WIN32
+#ifdef WIN32
+#include <windows.h>
+#else
#include <pwd.h>
#include <unistd.h>
#include <sys/stat.h>
@@ -189,52 +191,122 @@ void FioOpenFile(int slot, const char *filename)
FioSeekToFile(slot << 24);
}
+const char *_subdirs[NUM_SUBDIRS] = {
+ "",
+ "save" PATHSEP,
+ "save" PATHSEP "autosave" PATHSEP,
+ "scenario" PATHSEP,
+ "scenario" PATHSEP "heightmap" PATHSEP,
+ "gm" PATHSEP,
+ "data" PATHSEP,
+ "lang" PATHSEP
+};
+
+const char *_searchpaths[NUM_SEARCHPATHS];
+
/**
* Check whether the given file exists
* @param filename the file to try for existance
+ * @param subdir the subdirectory to look in
* @return true if and only if the file can be opened
*/
-bool FioCheckFileExists(const char *filename)
+bool FioCheckFileExists(const char *filename, Subdirectory subdir)
{
- FILE *f = FioFOpenFile(filename);
+ FILE *f = FioFOpenFile(filename, "rb", subdir);
if (f == NULL) return false;
fclose(f);
return true;
}
-/**
- * Opens the file with the given name
- * @param filename the file to open (in either data_dir or second_data_dir)
- * @return the opened file or NULL when it failed.
- */
-FILE *FioFOpenFile(const char *filename)
+char *FioGetFullPath(char *buf, size_t buflen, Searchpath sp, Subdirectory subdir, const char *filename)
{
- FILE *f;
+ assert(subdir < NUM_SUBDIRS);
+ assert(sp < NUM_SEARCHPATHS);
+
+ snprintf(buf, buflen, "%s%s" PATHSEP "%s", _searchpaths[sp], _subdirs[subdir], filename);
+ return buf;
+}
+
+char *FioFindFullPath(char *buf, size_t buflen, Subdirectory subdir, const char *filename)
+{
+ Searchpath sp;
+ assert(subdir < NUM_SUBDIRS);
+
+ FOR_ALL_SEARCHPATHS(sp) {
+ FioGetFullPath(buf, buflen, sp, subdir, filename);
+ if (FileExists(buf)) break;
+ }
+
+ return buf;
+}
+
+char *FioAppendDirectory(char *buf, size_t buflen, Searchpath sp, Subdirectory subdir)
+{
+ assert(subdir < NUM_SUBDIRS);
+ assert(sp < NUM_SEARCHPATHS);
+
+ snprintf(buf, buflen, "%s%s", _searchpaths[sp], _subdirs[subdir]);
+ return buf;
+}
+
+char *FioGetDirectory(char *buf, size_t buflen, Subdirectory subdir)
+{
+ Searchpath sp;
+
+ /* Find and return the first valid directory */
+ FOR_ALL_SEARCHPATHS(sp) {
+ char *ret = FioAppendDirectory(buf, buflen, sp, subdir);
+ if (FileExists(buf)) return ret;
+ }
+
+ /* Could not find the directory, fall back to a base path */
+ ttd_strlcpy(buf, _personal_dir, buflen);
+
+ return buf;
+}
+
+FILE *FioFOpenFileSp(const char *filename, const char *mode, Searchpath sp, Subdirectory subdir)
+{
+#if defined(WIN32) && defined(UNICODE)
+ /* fopen is implemented as a define with ellipses for
+ * Unicode support (prepend an L). As we are not sending
+ * a string, but a variable, it 'renames' the variable,
+ * so make that variable to makes it compile happily */
+ wchar_t Lmode[5];
+ MultiByteToWideChar(CP_ACP, 0, mode, -1, Lmode, lengthof(Lmode));
+#endif
+ FILE *f = NULL;
char buf[MAX_PATH];
- if (filename[0] == PATHSEPCHAR || filename[1] == ':') {
+ if (subdir == BASE_DIR) {
ttd_strlcpy(buf, filename, lengthof(buf));
} else {
- snprintf(buf, lengthof(buf), "%s%s", _paths.data_dir, filename);
+ snprintf(buf, lengthof(buf), "%s%s%s", _searchpaths[sp], _subdirs[subdir], filename);
}
- f = fopen(buf, "rb");
+ f = fopen(buf, mode);
#if !defined(WIN32)
if (f == NULL) {
- strtolower(strrchr(buf, PATHSEPCHAR));
- f = fopen(buf, "rb");
-
-#if defined SECOND_DATA_DIR
- /* tries in the 2nd data directory */
- if (f == NULL) {
- snprintf(buf, lengthof(buf), "%s%s", _paths.second_data_dir, filename);
- strtolower(buf + strlen(_paths.second_data_dir) - 1);
- f = fopen(buf, "rb");
- }
-#endif
+ strtolower(buf + strlen(_searchpaths[sp]) - 1);
+ f = fopen(buf, mode);
}
#endif
+ return f;
+}
+
+/** Opens OpenTTD files somewhere in a personal or global directory */
+FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir)
+{
+ FILE *f = NULL;
+ Searchpath sp;
+
+ assert(subdir < NUM_SUBDIRS);
+
+ FOR_ALL_SEARCHPATHS(sp) {
+ f = FioFOpenFileSp(filename, mode, sp, subdir);
+ if (f != NULL || subdir == 0) break;
+ }
return f;
}
@@ -299,7 +371,8 @@ char *BuildWithFullPath(const char *dir)
#if defined(WIN32) || defined(WINCE)
/**
* Determine the base (personal dir and game data dir) paths
- * @param exe the path to the executable
+ * @param exe the path from the current path to the executable
+ * @note defined in the OS related files (os2.cpp, win32.cpp, unix.cpp etc)
*/
extern void DetermineBasePaths(const char *exe);
#else /* defined(WIN32) || defined(WINCE) */
@@ -336,70 +409,86 @@ void ChangeWorkingDirectory(const char *exe)
*/
void DetermineBasePaths(const char *exe)
{
- /* Change the working directory to enable doubleclicking in UIs */
- ChangeWorkingDirectory(exe);
-
- _paths.game_data_dir = BuildWithFullPath(GAME_DATA_DIR);
-#if defined(SECOND_DATA_DIR)
- _paths.second_data_dir = BuildWithFullPath(SECOND_DATA_DIR);
-#else
- _paths.second_data_dir = NULL;
-#endif
-
-#if defined(USE_HOMEDIR)
+ char tmp[MAX_PATH];
+#ifdef WITH_PERSONAL_DIR
const char *homedir = getenv("HOME");
if (homedir == NULL) {
const struct passwd *pw = getpwuid(getuid());
- if (pw != NULL) homedir = pw->pw_dir;
+ homedir = (pw == NULL) ? "" : pw->pw_dir;
}
- _paths.personal_dir = str_fmt("%s" PATHSEP "%s", homedir, PERSONAL_DIR);
- AppendPathSeparator(_paths.personal_dir, MAX_PATH);
-#else /* not defined(USE_HOMEDIR) */
- _paths.personal_dir = BuildWithFullPath(PERSONAL_DIR);
-#endif /* defined(USE_HOMEDIR) */
+ snprintf(tmp, MAX_PATH, "%s" PATHSEP "%s", homedir, PERSONAL_DIR);
+ AppendPathSeparator(tmp, MAX_PATH);
+
+ _searchpaths[SP_PERSONAL_DIR] = strdup(tmp);
+#else
+ _searchpaths[SP_PERSONAL_DIR] = NULL;
+#endif
+ _searchpaths[SP_SHARED_DIR] = NULL;
+
+ getcwd(tmp, MAX_PATH);
+ AppendPathSeparator(tmp, MAX_PATH);
+ _searchpaths[SP_WORKING_DIR] = strdup(tmp);
+
+ /* Change the working directory to that one of the executable */
+ ChangeWorkingDirectory((char*)exe);
+ getcwd(tmp, MAX_PATH);
+ AppendPathSeparator(tmp, MAX_PATH);
+ _searchpaths[SP_BINARY_DIR] = strdup(tmp);
+
+ snprintf(tmp, MAX_PATH, "%s", GLOBAL_DATA_DIR);
+ AppendPathSeparator(tmp, MAX_PATH);
+ _searchpaths[SP_INSTALLATION_DIR] = strdup(tmp);
+#ifdef WITH_COCOA
+extern void cocoaSetApplicationBundleDir();
+ cocoaSetApplicationBundleDir();
+#else
+ _searchpaths[SP_APPLICATION_BUNDLE_DIR] = NULL;
+#endif
}
#endif /* defined(WIN32) || defined(WINCE) */
+char *_personal_dir;
+
/**
* Acquire the base paths (personal dir and game data dir),
* fill all other paths (save dir, autosave dir etc) and
* make the save and scenario directories.
- * @param exe the path to the executable
- * @todo for save_dir, autosave_dir, scenario_dir and heightmap_dir the
- * assumption is that there is no path separator, however for gm_dir
- * lang_dir and data_dir that assumption is made.
- * This inconsistency should be resolved.
+ * @param exe the path from the current path to the executable
*/
void DeterminePaths(const char *exe)
{
DetermineBasePaths(exe);
- _paths.save_dir = str_fmt("%ssave" PATHSEP, _paths.personal_dir);
- _paths.autosave_dir = str_fmt("%s" PATHSEP "autosave" PATHSEP, _paths.save_dir);
- _paths.scenario_dir = str_fmt("%sscenario" PATHSEP, _paths.personal_dir);
- _paths.heightmap_dir = str_fmt("%s" PATHSEP "heightmap" PATHSEP, _paths.scenario_dir);
- _paths.gm_dir = str_fmt("%sgm" PATHSEP, _paths.game_data_dir);
- _paths.data_dir = str_fmt("%sdata" PATHSEP, _paths.game_data_dir);
-#if defined(CUSTOM_LANG_DIR)
- _paths.lang_dir = BuildWithFullPath(CUSTOM_LANG_DIR);
-#else
- _paths.lang_dir = str_fmt("%slang" PATHSEP, _paths.game_data_dir);
-#endif
+ Searchpath sp;
+ FOR_ALL_SEARCHPATHS(sp) DEBUG(misc, 4, "%s added as search path", _searchpaths[sp]);
+
+ /* Search for the first search path, as that will be the closest to
+ * the personal directory. */
+ FOR_ALL_SEARCHPATHS(sp) {
+ _personal_dir = strdup(_searchpaths[sp]);
+ DEBUG(misc, 3, "%s found as personal directory", _searchpaths[sp]);
+ break;
+ }
if (_config_file == NULL) {
- _config_file = str_fmt("%sopenttd.cfg", _paths.personal_dir);
+ _config_file = str_fmt("%sopenttd.cfg", _personal_dir);
}
- _highscore_file = str_fmt("%shs.dat", _paths.personal_dir);
- _log_file = str_fmt("%sopenttd.log", _paths.personal_dir);
+ _highscore_file = str_fmt("%shs.dat", _personal_dir);
+ _log_file = str_fmt("%sopenttd.log", _personal_dir);
+
+ char *save_dir = str_fmt("%s%s", _personal_dir, FioGetSubdirectory(SAVE_DIR));
+ char *autosave_dir = str_fmt("%s%s", _personal_dir, FioGetSubdirectory(AUTOSAVE_DIR));
+
+ /* Make the necessary folders */
+ FioCreateDirectory(_personal_dir);
+ FioCreateDirectory(save_dir);
+ FioCreateDirectory(autosave_dir);
- /* Make (auto)save and scenario folder */
- FioCreateDirectory(_paths.save_dir);
- FioCreateDirectory(_paths.autosave_dir);
- FioCreateDirectory(_paths.scenario_dir);
- FioCreateDirectory(_paths.heightmap_dir);
+ free(save_dir);
+ free(autosave_dir);
}
/**