1 /*
2    Copyright (C) 2009/2010 Kai Sterker <kai.sterker@gmail.com>
3    Part of the Adonthell Project  <http://adonthell.nongnu.org>
4 
5    Dlgedit is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9 
10    Dlgedit is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with Dlgedit.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /**
20  * @file common/util.cc
21  *
22  * @author Kai Sterker
23  * @brief Helper methods.
24  */
25 
26 #include <sys/param.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <libgen.h>
31 #include <unistd.h>
32 #include "game.h"
33 
34 #ifdef WIN32
35 #define realpath(N,R) _fullpath((R),(N),_MAX_PATH)
36 #undef PATH_MAX
37 #define PATH_MAX _MAX_PATH
38 #endif
39 
40 #include "util.h"
41 
42 // get path relative to data directory
get_relative_path(const std::string & path,const std::string & target_dir)43 std::string util::get_relative_path (const std::string & path, const std::string & target_dir)
44 {
45     std::string base_path = MK_UNIX_PATH (game::user_data_dir());
46     std::string rel_path = path;
47 
48     // make sure to use path relative to (user defined) data directory
49     if (base_path == "" || !remove_common_path (rel_path, base_path))
50     {
51         // fallback to builtin data dir if that doesn't seem to work
52         base_path = MK_UNIX_PATH (game::game_data_dir());
53         if (!remove_common_path (rel_path, base_path))
54         {
55             // if everything fails, try locating target_dir in the path and use
56             // that as relative path
57             size_t pos = rel_path.rfind (target_dir);
58             if (pos != std::string::npos)
59             {
60                 rel_path = rel_path.substr (pos);
61                 if (rel_path[0] == '/')
62                 {
63                     rel_path = rel_path.substr (1);
64                 }
65             }
66         }
67     }
68 
69     return rel_path;
70 }
71 
72 // try to make path relative to base path
remove_common_path(std::string & path,const std::string & base_path)73 bool util::remove_common_path (std::string & path, const std::string & base_path)
74 {
75     // make canonical base path
76     char canonical_path[PATH_MAX];
77     if (realpath(base_path.c_str(), canonical_path))
78     {
79         std::string c_base_path = canonical_path;
80         if (realpath(path.c_str(), canonical_path))
81         {
82             path = MK_UNIX_PATH (canonical_path);
83             if (path.compare (0, c_base_path.size(), c_base_path) == 0)
84             {
85                 path = path.substr (c_base_path.length());
86                 if (path[0] == '/')
87                 {
88                     path = path.substr (1);
89                 }
90                 return true;
91             }
92         }
93     }
94 
95     return false;
96 }
97 
98 // convert windows directory separators to unix style
to_unix_path(const std::string & path)99 std::string util::to_unix_path (const std::string & path)
100 {
101 	std::string result = path;
102 	for (std::string::iterator i = result.begin(); i != result.end(); i++)
103 	{
104 		if (*i == '\\') *i = '/';
105 	}
106 	return result;
107 }
108 
109 // convert relative path to absolute path
get_absolute_path(const std::string & path)110 std::string util::get_absolute_path (const std::string & path)
111 {
112     std::string result = path;
113 
114     if (result[0] != '/')
115     {
116         char *oldwd = getcwd (NULL, 0);
117         if (chdir (dirname ((char*) result.c_str())))
118         {
119             return path;
120         }
121 
122         // get absolute pathname
123         char *cpath = getcwd (NULL, 0);
124         char *bname = strdup (path.c_str());
125         result = std::string(cpath) + "/" + basename (bname);
126 
127         // restore working directory
128         chdir (oldwd);
129 
130         // cleanup
131         free (oldwd);
132         free (cpath);
133         free (bname);
134     }
135 
136     return result;
137 }
138