1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #define _GNU_SOURCE 1
6 #include <fs/filesys.h>
7 #ifdef WINDOWS
8 //#define WIN32_LEAN_AND_MEAN
9 #include <windows.h>
10 #include <Shlobj.h>
11 #else
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <dirent.h>
18 #include <errno.h>
19 #endif
20 #ifdef MACOSX
21 #include <mach-o/dyld.h>
22 #include <copyfile.h>
23 #endif
24 #include <stdio.h>
25 // #include <fs/log.h>
26 #include <fs/base.h>
27 #include <fs/data.h>
28 #ifdef HAVE_SYS_TIME_H
29 #include <sys/time.h>
30 #endif
31 #ifdef USE_GLIB
32 // FIXME g_atomic_int_get / g_atomic_int_set
33 #include <glib.h>
34 #endif
35
fse_user_config_dir(void)36 const char *fse_user_config_dir(void)
37 {
38 #ifdef USE_GLIB
39 #ifdef MACOSX
40 static char *path = NULL;
41 if (path == NULL) {
42 path = g_build_filename(g_get_home_dir(), "Library", "Preferences",
43 NULL);
44 }
45 return path;
46 #else
47 return g_get_user_config_dir();
48 #endif
49 #else
50 #error not implemented
51 #endif
52 }
53
fse_user_data_dir(void)54 const char *fse_user_data_dir(void)
55 {
56 #ifdef USE_GLIB
57 return g_get_user_data_dir();
58 #else
59 #error not implemented
60 #endif
61 }
62
fs_get_data_file(const char * relative)63 char *fs_get_data_file(const char *relative)
64 {
65 static int initialized = 0;
66 static char executable_dir[PATH_MAX];
67 if (!initialized) {
68 fs_get_application_exe_dir(executable_dir, PATH_MAX);
69 initialized = 1;
70 }
71 char *path;
72 path = g_build_filename(executable_dir, "share", relative, NULL);
73 if (fs_path_exists(path)) {
74 return path;
75 }
76 g_free(path);
77 path = g_build_filename(executable_dir, "..", "share", relative, NULL);
78 if (fs_path_exists(path)) {
79 return path;
80 }
81 g_free(path);
82
83 #ifdef MACOSX
84 char buffer[FS_PATH_MAX];
85 fs_get_application_exe_dir(buffer, FS_PATH_MAX);
86 path = g_build_filename(buffer, "..", "Resources", relative, NULL);
87 if (fs_path_exists(path)) {
88 return path;
89 }
90 g_free(path);
91 #endif
92
93 #ifdef USE_GLIB
94 const char *user_dir = g_get_user_data_dir();
95 path = g_build_filename(user_dir, relative, NULL);
96 if (fs_path_exists(path)) {
97 return path;
98 }
99 g_free(path);
100
101 const char * const *dirs = g_get_system_data_dirs();
102 while(*dirs) {
103 path = g_build_filename(*dirs, relative, NULL);
104 if (fs_path_exists(path)) {
105 return path;
106 }
107 g_free(path);
108 dirs++;
109 }
110 #endif
111
112 return NULL;
113 }
114
115 static const char *g_data_dir;
116
fs_set_data_dir(const char * path)117 void fs_set_data_dir(const char *path)
118 {
119 g_data_dir = path;
120 }
121
fs_data_dir(void)122 const char *fs_data_dir(void)
123 {
124 g_assert(g_data_dir != NULL);
125 return g_data_dir;
126 }
127
fs_get_program_data_file(const char * relative)128 char *fs_get_program_data_file(const char *relative)
129 {
130 char *relative2 = g_build_filename(fs_get_prgname(), relative, NULL);
131 char *result = fs_get_data_file(relative2);
132 g_free(relative2);
133 return result;
134 }
135
fs_get_program_data(const char * relative,char ** data,int * size)136 int fs_get_program_data(const char *relative, char **data, int *size)
137 {
138 char *name = g_build_filename("share", fs_get_prgname(), relative, NULL);
139 int error = fs_data_file_content(name, data, size);
140 g_free(name);
141 return error;
142 }
143
fs_get_current_time(fs_time_val * result)144 void fs_get_current_time(fs_time_val *result)
145 {
146 if (result == NULL) {
147 return;
148 }
149 #ifdef USE_GLIB
150 GTimeVal result2;
151 g_get_current_time(&result2);
152 result->tv_sec = result2.tv_sec;
153 result->tv_usec = result2.tv_usec;
154 #else
155 #error not implemented
156 #endif
157 }
158
fs_get_real_time(void)159 int64_t fs_get_real_time(void)
160 {
161 fs_time_val tv;
162 fs_get_current_time(&tv);
163 return (((int64_t) tv.tv_sec) * 1000000) + tv.tv_usec;
164 }
165
fs_get_monotonic_time(void)166 int64_t fs_get_monotonic_time(void)
167 {
168 #ifdef USE_GLIB
169 return g_get_monotonic_time();
170 #else
171 #error not implemented
172 #endif
173 }
174
175 static char** g_argv = NULL;
176 static int g_argc = 0;
177
fs_set_argv(int argc,char * argv[])178 void fs_set_argv(int argc, char* argv[])
179 {
180 g_argc = argc;
181 g_argv = argv;
182 }
183
find_program_in_path(const char * prog)184 static char *find_program_in_path(const char *prog)
185 {
186 #ifdef USE_GLIB
187 return g_find_program_in_path(prog);
188 #else
189 const char* c = prog;
190 while(*c) {
191 if (*c++ == '/') {
192 /* path contains / - not started via PATH, it's either
193 * already an absolute path - or a relative path. */
194 return g_strdup(prog);
195 }
196 }
197
198 const char* env_path = getenv("PATH");
199 if (env_path == NULL) {
200 return NULL;
201 }
202 char *result = NULL;
203 char **dirs = g_strsplit(env_path, ":", 0);
204 char **dir = dirs;
205 while(*dir) {
206 if (*dir) {
207 char *abs = g_build_filename(*dir, prog, NULL);
208 if (fs_path_is_file(abs)) {
209 result = abs;
210 break;
211 }
212 g_free(abs);
213 }
214 dir++;
215 }
216 g_strfreev(dirs);
217 return result;
218 #endif
219 }
220
fs_get_application_exe_path(char * buffer,int size)221 int fs_get_application_exe_path(char *buffer, int size)
222 {
223 /* Possible sources:
224 * Mac OS X: _NSGetExecutablePath() (man 3 dyld)
225 * Linux: readlink /proc/self/exe
226 * Solaris: getexecname()
227 * FreeBSD: sysctl CTL_KERN KERN_PROC KERN_PROC_PATHNAME -1
228 * BSD with procfs: readlink /proc/curproc/file
229 * Windows: GetModuleFileName() with hModule = NULL
230 * or guess using argv[0] and PATH
231 */
232 if (size < 1) {
233 return 0;
234 }
235 buffer[0] = '\0';
236
237 #if defined(WINDOWS)
238
239 wchar_t * temp_buf = g_malloc(sizeof(wchar_t) * PATH_MAX);
240 /* len is the number of characters NOT including the terminating null
241 * character. */
242 int len = GetModuleFileNameW(NULL, temp_buf, PATH_MAX);
243 /* Specify size - 1 to reserve space for a null-terminating byte. */
244 int result = WideCharToMultiByte(CP_UTF8, 0, temp_buf, len,
245 buffer, size - 1, NULL, NULL);
246 g_free(temp_buf);
247 if (result == 0) {
248 return 0;
249 }
250 /* Since len does not include the null-terminator, WideCharToMultiByte
251 * does not null-terminate the buffer. */
252 buffer[result] = '\0';
253 return 1;
254
255 #elif defined(MACOSX)
256
257 unsigned int usize = size;
258 int result = _NSGetExecutablePath(buffer, &usize);
259 if (result == 0) {
260 return 1;
261 } else {
262 fs_log("_NSGetExecutablePath failed with result %d\n", result);
263 buffer[0] = '\0';
264 return 0;
265 }
266
267 #else
268
269 if (g_argc == 0 || g_argv == NULL) {
270 buffer[0] = '\0';
271 return 0;
272 }
273
274 char* result;
275 result = find_program_in_path(g_argv[0]);
276 if (result == NULL) {
277 buffer[0] = '\0';
278 return 0;
279 }
280
281 if (result[0] != '/') {
282 char* old_result = result;
283 char* current_dir = g_get_current_dir();
284 result = g_build_filename(current_dir, old_result, NULL);
285 g_free(old_result);
286 g_free(current_dir);
287 }
288
289 if (strlen(result) > size - 1) {
290 buffer[0] = '\0';
291 g_free(result);
292 return 0;
293 }
294
295 /* We have already checked that the buffer is big enough */
296 strcpy(buffer, result);
297 g_free(result);
298 return 1;
299
300 #endif
301 }
302
fs_get_application_exe_dir(char * buffer,int size)303 int fs_get_application_exe_dir(char *buffer, int size)
304 {
305 int result = fs_get_application_exe_path(buffer, size);
306 if (result == 0) {
307 return 0;
308 }
309 int pos = strlen(buffer) - 1;
310 while (pos >= 0) {
311 if (buffer[pos] == '\\' || buffer[pos] == '/') {
312 buffer[pos] = '\0';
313 return 1;
314 }
315 pos -= 1;
316 }
317 return 0;
318 }
319
320 #ifndef USE_GLIB
321 static char *g_prgname = "unnamed-program";
322 static char *g_application_name = "Unnamed Program";
323 #endif
324
fs_get_application_name(void)325 const char *fs_get_application_name(void)
326 {
327 #ifdef USE_GLIB
328 return g_get_application_name();
329 #else
330 return g_application_name;
331 #endif
332 }
333
fs_set_application_name(const char * application_name)334 void fs_set_application_name(const char *application_name)
335 {
336 #ifdef USE_GLIB
337 g_set_application_name(application_name);
338 #else
339 g_application_name = fs_strdup(application_name);
340 #endif
341 }
342
fs_get_prgname(void)343 const char *fs_get_prgname(void)
344 {
345 #ifdef USE_GLIB
346 return g_get_prgname();
347 #else
348 return g_prgname;
349 #endif
350 }
351
fs_set_prgname(const char * prgname)352 void fs_set_prgname(const char *prgname)
353 {
354 #ifdef USE_GLIB
355 g_set_prgname(prgname);
356 #else
357 g_prgname = fs_strdup(prgname);
358 #endif
359 }
360