1 /* vim:expandtab:ts=2 sw=2:
2 */
3 #include <stdlib.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <string.h>
7 #ifndef _MSC_VER
8 #include <unistd.h>
9 #endif
10 #if !defined(WIN32)
11 #include <limits.h>
12 #endif
13
14 #if defined(__APPLE__) && (MAC_OS_X_VERSION_MIN_REQUIRED < 1060)
15 #include "gfx2mem.h"
16 #endif
17
18 #if defined(__AROS__) || defined(__BEOS__) || defined(__MORPHOS__) || defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) || defined(__amigaos__) || defined(__SWITCH__)
19
20 #include "io.h"
21 #include "gfx2log.h"
22 #include "gfx2mem.h"
23 // These platforms don't have realpath().
24 // Our custom implementation uses chdir() and relies on
25 // errno == ENOTDIR when trying to change directory to a file
Realpath(const char * _path)26 char *Realpath(const char *_path)
27 {
28 char * rpath = NULL;
29 char * current_dir_save;
30
31 // backup current directory
32 current_dir_save = Get_current_directory(NULL, NULL, 0);
33 if (current_dir_save == NULL) {
34 // error
35 return NULL;
36 }
37
38 if (chdir(_path) < 0) {
39 if (errno == ENOTDIR) {
40 const char * position;
41 const char * filename;
42 char * directory;
43 position = Find_last_separator(_path);
44 if (position != NULL) {
45 size_t dirlen = position - _path;
46 filename = position + 1;
47 directory = GFX2_malloc(dirlen);
48 if (directory != NULL) {
49 memcpy(directory, _path, dirlen);
50 directory[dirlen] = '\0';
51 GFX2_Log(GFX2_DEBUG, "Directory : \"%s\", filename : \"%s\"\n", directory, filename);
52 if (chdir(directory) == 0) {
53 char * dirpart = Get_current_directory(NULL, NULL, 0);
54 if (dirpart != NULL) {
55 size_t len = strlen(dirpart) + strlen(filename) + 2;
56 rpath = GFX2_malloc(len);
57 if (rpath != NULL) {
58 snprintf(rpath, len, "%s%s%s", dirpart, PATH_SEPARATOR, filename);
59 }
60 free(dirpart);
61 }
62 } else {
63 GFX2_Log(GFX2_ERROR, "chdir(\"%s\") : %s\n", directory, strerror(errno));
64 }
65 free(directory);
66 }
67 }
68 } else {
69 GFX2_Log(GFX2_ERROR, "chdir(\"%s\") : %s\n", _path, strerror(errno));
70 }
71 } else {
72 // _path is a directory
73 rpath = Get_current_directory(NULL, NULL, 0);
74 }
75
76 // "restore" current directory
77 chdir(current_dir_save);
78 free(current_dir_save);
79 return rpath;
80 }
81
82 #elif defined(__WIN32__) || defined(WIN32)
83 // MSVC / Mingw has a working equivalent. It only has reversed arguments.
Realpath(const char * _path)84 char *Realpath(const char *_path)
85 {
86 return _fullpath(NULL, _path, 260);
87 }
88 #else
89
90 // Use the stdlib function.
Realpath(const char * _path)91 char *Realpath(const char *_path)
92 {
93 /// POSIX 2004 states :
94 /// If resolved_name is a null pointer, the behavior of realpath()
95 /// is implementation-defined.
96 ///
97 /// but POSIX 2008 :
98 /// If resolved_name is a null pointer, the generated pathname shall
99 /// be stored as a null-terminated string in a buffer allocated as if
100 /// by a call to malloc().
101 ///
102 /// So we assume all platforms now support passing NULL.
103 /// If you find a platform where this is not the case,
104 /// please add a new implementation with ifdef's.
105 char * resolved_path = NULL;
106 #if defined(__APPLE__) && (MAC_OS_X_VERSION_MIN_REQUIRED < 1060)
107 // realpath() accept NULL as 2nd argument since OSX 10.6
108 resolved_path = GFX2_malloc(PATH_MAX);
109 if (resolved_path == NULL)
110 return NULL;
111 #endif
112 return realpath(_path, resolved_path);
113 }
114 #endif
115