|
|
1.1 root 1: /*
2: Hatari - paths.c
3:
1.1.1.9 root 4: This file is distributed under the GNU General Public License, version 2
5: or at your option any later version. Read the file gpl.txt for details.
1.1 root 6:
7: Set up the various path strings.
8: */
1.1.1.4 root 9: const char Paths_fileid[] = "Hatari paths.c : " __DATE__ " " __TIME__;
1.1 root 10:
11: #include <unistd.h>
12: #include <sys/stat.h>
13: #include <sys/types.h>
14:
15: #include "main.h"
16: #include "file.h"
17: #include "paths.h"
1.1.1.11 root 18: #include "str.h"
1.1 root 19:
1.1.1.5 root 20: #if defined(WIN32) && !defined(mkdir)
1.1.1.2 root 21: #define mkdir(name,mode) mkdir(name)
22: #endif /* WIN32 */
23:
1.1.1.10 root 24: #if defined(__MACOSX__)
25: #define HATARI_HOME_DIR "Library/Application Support/Hatari"
1.1.1.12 root 26: #elif defined(WIN32)
27: #define HATARI_HOME_DIR "AppData\\Local\\Hatari"
1.1.1.10 root 28: #else
1.1.1.12 root 29: #define HATARI_HOME_DIR ".config/hatari"
1.1.1.10 root 30: #endif
31:
1.1.1.14! root 32: static char *sWorkingDir; /* Working directory */
! 33: static char *sDataDir; /* Directory where data files of Hatari can be found */
! 34: static char *sUserHomeDir; /* User's home directory ($HOME) */
! 35: static char *sHatariHomeDir; /* Hatari's home directory ($HOME/.hatari/) */
! 36: static char *sScreenShotDir; /* Directory to use for screenshots */
1.1 root 37:
38: /**
39: * Return pointer to current working directory string
40: */
41: const char *Paths_GetWorkingDir(void)
42: {
43: return sWorkingDir;
44: }
45:
46: /**
47: * Return pointer to data directory string
48: */
49: const char *Paths_GetDataDir(void)
50: {
51: return sDataDir;
52: }
53:
54: /**
55: * Return pointer to user's home directory string
56: */
57: const char *Paths_GetUserHome(void)
58: {
59: return sUserHomeDir;
60: }
61:
62: /**
63: * Return pointer to Hatari's home directory string
64: */
65: const char *Paths_GetHatariHome(void)
66: {
67: return sHatariHomeDir;
68: }
69:
1.1.1.14! root 70: /**
! 71: * Return pointer to screenshot directory string
! 72: */
! 73: const char *Paths_GetScreenShotDir(void)
! 74: {
! 75: return sScreenShotDir;
! 76: }
! 77:
1.1 root 78:
79: /**
80: * Explore the PATH environment variable to see where our executable is
81: * installed.
82: */
1.1.1.3 root 83: static void Paths_GetExecDirFromPATH(const char *argv0, char *pExecDir, int nMaxLen)
1.1 root 84: {
85: char *pPathEnv;
86: char *pAct;
87: char *pTmpName;
88: const char *pToken;
89:
90: /* Get the PATH environment string */
91: pPathEnv = getenv("PATH");
92: if (!pPathEnv)
93: return;
94: /* Duplicate the string because strtok destroys it later */
95: pPathEnv = strdup(pPathEnv);
96: if (!pPathEnv)
97: return;
98:
99: pTmpName = malloc(FILENAME_MAX);
100: if (!pTmpName)
1.1.1.10 root 101: {
102: perror("Paths_GetExecDirFromPATH");
103: free(pPathEnv);
1.1 root 104: return;
1.1.1.10 root 105: }
1.1 root 106:
107: /* If there is a semicolon in the PATH, we assume it is the PATH
108: * separator token (like on Windows), otherwise we use a colon. */
109: if (strchr((pPathEnv), ';'))
110: pToken = ";";
111: else
112: pToken = ":";
113:
114: pAct = strtok (pPathEnv, pToken);
115: while (pAct)
116: {
117: snprintf(pTmpName, FILENAME_MAX, "%s%c%s",
118: pAct, PATHSEP, argv0);
119: if (File_Exists(pTmpName))
120: {
121: /* Found the executable - so use the corresponding path: */
1.1.1.11 root 122: strlcpy(pExecDir, pAct, nMaxLen);
1.1 root 123: break;
124: }
1.1.1.12 root 125: pAct = strtok (NULL, pToken);
1.1 root 126: }
127:
128: free(pPathEnv);
129: free(pTmpName);
130: }
131:
132:
133: /**
134: * Locate the directory where the hatari executable resides
135: */
1.1.1.3 root 136: static char *Paths_InitExecDir(const char *argv0)
1.1 root 137: {
138: char *psExecDir; /* Path string where the hatari executable can be found */
139:
140: /* Allocate memory for storing the path string of the executable */
141: psExecDir = malloc(FILENAME_MAX);
142: if (!psExecDir)
143: {
144: fprintf(stderr, "Out of memory (Paths_Init)\n");
145: exit(-1);
146: }
147:
148: /* Determine the bindir...
149: * Start with empty string, then try to use OS specific functions,
150: * and finally analyze the PATH variable if it has not been found yet. */
151: psExecDir[0] = '\0';
152:
153: #if defined(__linux__)
154: {
155: int i;
156: /* On Linux, we can analyze the symlink /proc/self/exe */
1.1.1.11 root 157: i = readlink("/proc/self/exe", psExecDir, FILENAME_MAX-1);
1.1 root 158: if (i > 0)
159: {
160: char *p;
161: psExecDir[i] = '\0';
162: p = strrchr(psExecDir, '/'); /* Search last slash */
163: if (p)
164: *p = 0; /* Strip file name from path */
165: }
166: }
167: //#elif defined(WIN32) || defined(__CEGCC__)
168: // /* On Windows we can use GetModuleFileName for getting the exe path */
169: // GetModuleFileName(NULL, psExecDir, FILENAME_MAX);
170: #endif
171:
172: /* If we do not have the execdir yet, analyze argv[0] and the PATH: */
173: if (psExecDir[0] == 0)
174: {
1.1.1.12 root 175: if (strchr(argv0, PATHSEP) == NULL)
1.1 root 176: {
177: /* No separator in argv[0], we have to explore PATH... */
178: Paths_GetExecDirFromPATH(argv0, psExecDir, FILENAME_MAX);
179: }
180: else
181: {
182: /* There was a path separator in argv[0], so let's assume a
183: * relative or absolute path to the current directory in argv[0] */
184: char *p;
1.1.1.11 root 185: strlcpy(psExecDir, argv0, FILENAME_MAX);
1.1 root 186: p = strrchr(psExecDir, PATHSEP); /* Search last slash */
187: if (p)
188: *p = 0; /* Strip file name from path */
189: }
190: }
191:
192: return psExecDir;
193: }
194:
195:
196: /**
197: * Initialize the users home directory string
198: * and Hatari's home directory (~/.hatari)
199: */
200: static void Paths_InitHomeDirs(void)
201: {
202: char *psHome;
203:
204: psHome = getenv("HOME");
1.1.1.8 root 205: if (psHome)
1.1.1.14! root 206: {
! 207: sUserHomeDir = Str_Dup(psHome);
! 208: }
1.1.1.8 root 209: #if defined(WIN32)
210: else
1.1 root 211: {
1.1.1.8 root 212: char *psDrive;
213: int len = 0;
1.1.1.6 root 214: /* Windows home path? */
1.1.1.8 root 215: psDrive = getenv("HOMEDRIVE");
216: if (psDrive)
217: len = strlen(psDrive);
1.1.1.14! root 218: psHome = getenv("HOMEPATH");
1.1.1.8 root 219: if (psHome)
1.1.1.14! root 220: len += strlen(psHome);
! 221: if (len > 0)
! 222: {
! 223: sUserHomeDir = Str_Alloc(len);
! 224: if (psDrive)
! 225: strcpy(sUserHomeDir, psDrive);
! 226: if (psHome)
! 227: strcat(sUserHomeDir, psHome);
! 228: }
1.1.1.6 root 229: }
1.1.1.8 root 230: #endif
1.1.1.14! root 231: if (!sUserHomeDir)
1.1.1.6 root 232: {
1.1 root 233: /* $HOME not set, so let's use current working dir as home */
1.1.1.14! root 234: sUserHomeDir = Str_Dup(sWorkingDir);
! 235: sHatariHomeDir = Str_Dup(sWorkingDir);
1.1.1.12 root 236: return;
1.1 root 237: }
1.1.1.12 root 238:
1.1.1.14! root 239: sHatariHomeDir = Str_Alloc(strlen(sUserHomeDir) + 1 + strlen(HATARI_HOME_DIR));
1.1.1.12 root 240:
241: /* Try to use a private hatari directory in the users home directory */
1.1.1.14! root 242: sprintf(sHatariHomeDir, "%s%c%s", sUserHomeDir, PATHSEP, HATARI_HOME_DIR);
1.1.1.12 root 243: if (File_DirExists(sHatariHomeDir))
1.1 root 244: {
1.1.1.12 root 245: return;
246: }
247: /* Try legacy location ~/.hatari */
1.1.1.14! root 248: sprintf(sHatariHomeDir, "%s%c.hatari", sUserHomeDir, PATHSEP);
1.1.1.12 root 249: if (File_DirExists(sHatariHomeDir))
250: {
251: return;
252: }
1.1 root 253:
1.1.1.12 root 254: /* Hatari home directory does not exists yet...
255: * ... so let's try to create it: */
256: #if !defined(__MACOSX__) && !defined(WIN32)
1.1.1.14! root 257: sprintf(sHatariHomeDir, "%s%c.config", sUserHomeDir, PATHSEP);
1.1.1.12 root 258: if (!File_DirExists(sHatariHomeDir))
259: {
260: /* ~/.config does not exist yet, create it first */
1.1.1.13 root 261: if (mkdir(sHatariHomeDir, 0700) != 0)
262: {
263: perror("Failed to create ~/.config directory");
264: }
1.1.1.12 root 265: }
266: #endif
1.1.1.14! root 267: sprintf(sHatariHomeDir, "%s%c%s", sUserHomeDir, PATHSEP, HATARI_HOME_DIR);
1.1.1.12 root 268: if (mkdir(sHatariHomeDir, 0750) != 0)
269: {
270: /* Failed to create, so use user's home dir instead */
271: strcpy(sHatariHomeDir, sUserHomeDir);
1.1 root 272: }
273: }
274:
275:
276: /**
277: * Initialize directory names
278: *
279: * The datadir will be initialized relative to the bindir (where the executable
280: * has been installed to). This means a lot of additional effort since we first
281: * have to find out where the executable is. But thanks to this effort, we get
282: * a relocatable package (we don't have any absolute path names in the program)!
283: */
1.1.1.3 root 284: void Paths_Init(const char *argv0)
1.1 root 285: {
286: char *psExecDir; /* Path string where the hatari executable can be found */
287:
288: /* Init working directory string */
1.1.1.14! root 289: sWorkingDir = malloc(FILENAME_MAX);
! 290: if (!sWorkingDir || getcwd(sWorkingDir, FILENAME_MAX) == NULL)
1.1.1.5 root 291: {
292: /* This should never happen... just in case... */
1.1.1.14! root 293: sWorkingDir = Str_Dup(".");
1.1.1.5 root 294: }
1.1 root 295:
296: /* Init the user's home directory string */
297: Paths_InitHomeDirs();
298:
1.1.1.14! root 299: /* Init screenshot directory string */
! 300: #if !defined(__MACOSX__)
! 301: sScreenShotDir = Str_Dup(sWorkingDir);
! 302: #else
! 303: sScreenShotDir = Paths_GetMacScreenShotDir();
! 304: if (!sScreenShotDir)
! 305: {
! 306: /* Failsafe, but should not be able to happen */
! 307: sScreenShotDir = Str_Dup(sWorkingDir);
! 308: }
! 309: #endif
! 310:
1.1 root 311: /* Get the directory where the executable resides */
312: psExecDir = Paths_InitExecDir(argv0);
313:
314: /* Now create the datadir path name from the bindir path name: */
1.1.1.14! root 315: sDataDir = Str_Alloc(FILENAME_MAX);
1.1 root 316: if (psExecDir && strlen(psExecDir) > 0)
317: {
1.1.1.14! root 318: sprintf(sDataDir, "%s%c%s", psExecDir, PATHSEP, BIN2DATADIR);
1.1 root 319: }
320: else
321: {
322: /* bindir could not be determined, let's assume datadir is relative
323: * to current working directory... */
324: strcpy(sDataDir, BIN2DATADIR);
325: }
326:
327: /* And finally make a proper absolute path out of datadir: */
328: File_MakeAbsoluteName(sDataDir);
329:
330: free(psExecDir);
331:
1.1.1.14! root 332: /* fprintf(stderr, " WorkingDir = %s\n DataDir = %s\n UserHomeDir = %s\n HatariHomeDir = %s\n ScrenShotDir = %s\n",
! 333: sWorkingDir, sDataDir, sUserHomeDir, sHatariHomeDir, sScreenShotDir); */
! 334: }
! 335:
! 336: void Paths_UnInit(void)
! 337: {
! 338: Str_Free(sWorkingDir);
! 339: Str_Free(sDataDir);
! 340: Str_Free(sUserHomeDir);
! 341: Str_Free(sHatariHomeDir);
! 342: Str_Free(sScreenShotDir);
1.1 root 343: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.