1
2//
3// This source file is part of appleseed.
4// Visit http://appleseedhq.net/ for additional information and resources.
5//
6// This software is released under the MIT license.
7//
8// Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
9// Copyright (c) 2014-2017 Francois Beaune, The appleseedhq Organization
10//
11// Permission is hereby granted, free of charge, to any person obtaining a copy
12// of this software and associated documentation files (the "Software"), to deal
13// in the Software without restriction, including without limitation the rights
14// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15// copies of the Software, and to permit persons to whom the Software is
16// furnished to do so, subject to the following conditions:
17//
18// The above copyright notice and this permission notice shall be included in
19// all copies or substantial portions of the Software.
20//
21// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27// THE SOFTWARE.
28//
29
30// Interface header.
31#include "path.h"
32
33// appleseed.foundation headers.
34#ifdef __APPLE__
35#include "foundation/platform/types.h"
36#endif
37#include "foundation/utility/iterators.h"
38
39// Boost headers.
40#include "boost/filesystem/operations.hpp"
41
42// Standard headers.
43#include <cassert>
44#include <cstddef>
45#include <cstring>
46
47// Platform headers.
48#if defined __APPLE__
49#include <mach-o/dyld.h>
50#elif defined __linux__
51#include <sys/types.h>
52#include <pwd.h>
53#include <unistd.h>
54#elif defined __FreeBSD__
55#include <sys/sysctl.h>
56#include <pwd.h>
57#include <unistd.h>
58#endif
59
60using namespace std;
61namespace bf = boost::filesystem;
62
63namespace foundation
64{
65
66const char* get_executable_path()
67{
68 static char path[FOUNDATION_MAX_PATH_LENGTH + 1];
69 static bool path_initialized = false;
70
71 if (!path_initialized)
72 {
73// Windows.
74#if defined _WIN32
75
76 const DWORD result =
77 GetModuleFileName(
78 GetModuleHandle(NULL),
79 path,
80 sizeof(path));
81 assert(result != 0);
82
83// OS X.
84#elif defined __APPLE__
85
86 uint32 path_len = MAXPATHLEN;
87 const int result = _NSGetExecutablePath(path, &path_len);
88 assert(result == 0);
89
90// Linux.
91#elif defined __linux__
92
93 const ssize_t result = readlink("/proc/self/exe", path, sizeof(path) - 1);
94 assert(result > 0);
95 path[result] = '\0';
96
97// FreeBSD.
98#elif defined __FreeBSD__
99
100 const int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
101 size_t len = sizeof(path);
102 const int result = sysctl(mib, 4, path, &len, 0x0, 0);
103 assert(result == 0);
104
105// Other platforms.
106#else
107
108 #error Unsupported platform.
109
110#endif
111
112 path_initialized = true;
113 }
114
115 return path;
116}
117
118const char* get_executable_directory()
119{
120 static char path[FOUNDATION_MAX_PATH_LENGTH + 1];
121 static bool path_initialized = false;
122
123 if (!path_initialized)
124 {
125 bf::path executable_path(get_executable_path());
126
127 assert(executable_path.has_filename());
128 executable_path.remove_filename();
129
130 assert(executable_path.string().size() <= FOUNDATION_MAX_PATH_LENGTH);
131 strncpy(path, executable_path.string().c_str(), sizeof(path) - 1);
132 path[sizeof(path) - 1] = '\0';
133
134 path_initialized = true;
135 }
136
137 return path;
138}
139
140const char* get_home_directory()
141{
142 static char path[FOUNDATION_MAX_PATH_LENGTH + 1];
143 static bool path_initialized = false;
144
145 if (!path_initialized)
146 {
147// Windows.
148#if defined _WIN32
149
150 return 0;
151
152// OS X.
153#elif defined __APPLE__
154
155 return 0;
156
157// Other Unices.
158#elif defined __linux__ || defined __FreeBSD__
159
160 const char* home_dir = getenv("HOME");
161
162 if (home_dir == 0)
163 home_dir = getpwuid(getuid())->pw_dir;
164
165 strncpy(path, home_dir, FOUNDATION_MAX_PATH_LENGTH);
166 path[FOUNDATION_MAX_PATH_LENGTH] = '\0';
167
168// Other platforms.
169#else
170
171 #error Unsupported platform.
172
173#endif
174
175 path_initialized = true;
176 }
177
178 return path;
179}
180
181void split_paths(
182 const bf::path& p1,
183 const bf::path& p2,
184 bf::path& common,
185 bf::path& r1,
186 bf::path& r2)
187{
188 assert(common.empty());
189 assert(r1.empty());
190 assert(r2.empty());
191
192 bf::path::const_iterator i1 = p1.begin();
193 bf::path::const_iterator i2 = p2.begin();
194
195 while (i1 != p1.end() && i2 != p2.end())
196 {
197 if (*i1 != *i2)
198 break;
199
200 if ((p1.has_filename() && succ(i1) == p1.end()) ||
201 (p2.has_filename() && succ(i2) == p2.end()))
202 break;
203
204 common /= *i1;
205
206 ++i1, ++i2;
207 }
208
209 while (i1 != p1.end())
210 r1 /= *i1++;
211
212 while (i2 != p2.end())
213 r2 /= *i2++;
214}
215
216} // namespace foundation
217