blob: 86e6a92db5fbd6924cb6823f19c100af9c0e1464 [file] [log] [blame]
Lingfeng Yangc02cb032020-10-26 14:21:25 -07001// Copyright 2020 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma once
16
17#include <stddef.h> // for size_t
18#include <string> // for string, basic_string
19#include <utility> // for move, forward
20#include <vector> // for vector
21
22#include "base/Optional.h" // for Optional
23
24#ifdef __APPLE__
25
26#define LIBSUFFIX ".dylib"
27
28#else
29
30#ifdef _WIN32
31#include "base/Win32UnicodeString.h"
32#define LIBSUFFIX ".dll"
33
34#else
35
36#define LIBSUFFIX ".so"
37
38#endif // !_WIN32 (linux)
39
40#endif // !__APPLE__
41
42namespace android {
43namespace base {
44
45// Utility functions to manage file paths. None of these should touch the
46// file system. All methods must be static.
47class PathUtils {
48public:
49 // An enum listing the supported host file system types.
50 // HOST_POSIX means a Posix-like file system.
51 // HOST_WIN32 means a Windows-like file system.
52 // HOST_TYPE means the current host type (one of the above).
53 // NOTE: If you update this list, modify kHostTypeCount below too.
54 enum HostType {
55 HOST_POSIX = 0,
56 HOST_WIN32 = 1,
57#ifdef _WIN32
58 HOST_TYPE = HOST_WIN32,
59#else
60 HOST_TYPE = HOST_POSIX,
61#endif
62 };
63
64 // The number of distinct items in the HostType enumeration above.
65 static const int kHostTypeCount = 2;
66
67 // Suffixes for an executable file (.exe on Windows, empty otherwise)
68 static const char* const kExeNameSuffixes[kHostTypeCount];
69
70 // Suffixe for an executable file on the current platform
71 static const char* const kExeNameSuffix;
72
73 // Returns the executable name for a base name |baseName|
74 static std::string toExecutableName(const char* baseName, HostType hostType);
75
76 static std::string toExecutableName(const char* baseName) {
77 return toExecutableName(baseName, HOST_TYPE);
78 }
79
80 // Return true if |ch| is a directory separator for a given |hostType|.
81 static bool isDirSeparator(int ch, HostType hostType);
82
83 // Return true if |ch| is a directory separator for the current platform.
84 static bool isDirSeparator(int ch) {
85 return isDirSeparator(ch, HOST_TYPE);
86 }
87
88 // Return true if |ch| is a path separator for a given |hostType|.
89 static bool isPathSeparator(int ch, HostType hostType);
90
91 // Return true if |ch| is a path separator for the current platform.
92 static bool isPathSeparator(int ch) {
93 return isPathSeparator(ch, HOST_TYPE);
94 }
95
96 // Return the directory separator character for a given |hostType|
97 static char getDirSeparator(HostType hostType) {
98 return (hostType == HOST_WIN32) ? '\\' : '/';
99 }
100
101 // Remove trailing separators from a |path| string, for a given |hostType|.
102 static std::string removeTrailingDirSeparator(const char* path,
103 HostType hostType);
104
105 // Remove trailing separators from a |path| string for the current host.
106 static std::string removeTrailingDirSeparator(const char* path) {
107 return removeTrailingDirSeparator(path, HOST_TYPE);
108 }
109
110 // Add a trailing separator if needed.
Lingfeng Yang0e6868f2020-11-03 12:32:59 -0800111 static std::string addTrailingDirSeparator(const std::string& path,
112 HostType hostType);
Lingfeng Yangc02cb032020-10-26 14:21:25 -0700113 static std::string addTrailingDirSeparator(const char* path,
114 HostType hostType);
115
116 // Add a trailing separator if needed.
Lingfeng Yang0e6868f2020-11-03 12:32:59 -0800117 static std::string addTrailingDirSeparator(const std::string& path) {
Lingfeng Yangc02cb032020-10-26 14:21:25 -0700118 return addTrailingDirSeparator(path, HOST_TYPE);
119 }
120
121 // If |path| starts with a root prefix, return its size in bytes, or
122 // 0 otherwise. The definition of valid root prefixes depends on the
123 // value of |hostType|. For HOST_POSIX, it's any path that begins
124 // with a slash (/). For HOST_WIN32, the following prefixes are
125 // recognized:
126 // <drive>:
127 // <drive>:<sep>
128 // <sep><sep>volumeName<sep>
129 static size_t rootPrefixSize(const std::string& path, HostType hostType);
130
131 // Return the root prefix for the current platform. See above for
132 // documentation.
133 static size_t rootPrefixSize(const char* path) {
134 return rootPrefixSize(path, HOST_TYPE);
135 }
136
137 // Return true iff |path| is an absolute path for a given |hostType|.
138 static bool isAbsolute(const char* path, HostType hostType);
139
140 // Return true iff |path| is an absolute path for the current host.
141 static bool isAbsolute(const char* path) {
142 return isAbsolute(path, HOST_TYPE);
143 }
144
145 // Split |path| into a directory name and a file name. |dirName| and
146 // |baseName| are optional pointers to strings that will receive the
147 // corresponding components on success. |hostType| is a host type.
148 // Return true on success, or false on failure.
149 // Note that unlike the Unix 'basename' command, the command will fail
150 // if |path| ends with directory separator or is a single root prefix.
151 // Windows root prefixes are fully supported, which means the following:
152 //
153 // / -> error.
154 // /foo -> '/' + 'foo'
155 // foo -> '.' + 'foo'
156 // <drive>: -> error.
157 // <drive>:foo -> '<drive>:' + 'foo'
158 // <drive>:\foo -> '<drive>:\' + 'foo'
159 //
160 static bool split(const char* path,
161 HostType hostType,
162 const char** dirName,
163 const char** baseName);
164
165 // A variant of split() for the current process' host type.
166 static bool split(const char* path,
167 const char** dirName,
168 const char** baseName) {
169 return split(path, HOST_TYPE, dirName, baseName);
170 }
171
172 // Join two path components together. Note that if |path2| is an
173 // absolute path, this function returns a copy of |path2|, otherwise
174 // the result will be the concatenation of |path1| and |path2|, if
175 // |path1| doesn't end with a directory separator, a |hostType| specific
176 // one will be inserted between the two paths in the result.
177 static std::string join(const std::string& path1,
178 const std::string& path2,
179 HostType hostType);
180
181 // A variant of join() for the current process' host type.
182 static std::string join(const std::string& path1, const std::string& path2) {
183 return join(path1, path2, HOST_TYPE);
184 }
185
186 // A convenience function to join a bunch of paths at once
187 template <class... Paths>
188 static std::string join(const std::string& path1,
189 const std::string& path2,
190 Paths&&... paths) {
191 return join(path1, join(path2, std::forward<Paths>(paths)...));
192 }
193
194 // Decompose |path| into individual components. If |path| has a root
195 // prefix, it will always be the first component. I.e. for Posix
196 // systems this will be '/' (for absolute paths). For Win32 systems,
197 // it could be 'C:" (for a path relative to a root volume) or "C:\"
198 // for an absolute path from volume C).,
199 // On success, return true and sets |out| to a vector of strings,
200 // each one being a path component (prefix or subdirectory or file
201 // name). Directory separators do not appear in components, except
202 // for the root prefix, if any.
203 static std::vector<std::string> decompose(std::string&& path,
204 HostType hostType);
Lingfeng Yang0e6868f2020-11-03 12:32:59 -0800205 static std::vector<std::string> decompose(const std::string& path,
206 HostType hostType);
Lingfeng Yangc02cb032020-10-26 14:21:25 -0700207
208 template <class String>
209 static std::vector<String> decompose(const String& path,
210 HostType hostType);
211
212 // Decompose |path| into individual components for the host platform.
213 // See comments above for more details.
214 static std::vector<std::string> decompose(std::string&& path) {
215 return decompose(std::move(path), HOST_TYPE);
216 }
217
Lingfeng Yang0e6868f2020-11-03 12:32:59 -0800218 static std::vector<std::string> decompose(const std::string& path) {
219 return decompose(path, HOST_TYPE);
220 }
221
Lingfeng Yangc02cb032020-10-26 14:21:25 -0700222 // Recompose a path from individual components into a file path string.
223 // |components| is a vector of strings, and |hostType| the target
224 // host type to use. Return a new file path string. Note that if the
225 // first component is a root prefix, it will be kept as is, i.e.:
226 // [ 'C:', 'foo' ] -> 'C:foo' on Win32, but not Posix where it will
227 // be 'C:/foo'.
228 static std::string recompose(const std::vector<std::string>& components,
229 HostType hostType);
230 template <class String>
231 static std::string recompose(const std::vector<String>& components,
232 HostType hostType);
233
234 // Recompose a path from individual components into a file path string
235 // for the current host. |components| is a vector os strings.
236 // Returns a new file path string.
237 template <class String>
238 static std::string recompose(const std::vector<String>& components) {
239 return PathUtils::recompose(components, HOST_TYPE);
240 }
241
242 // Given a list of components returned by decompose(), simplify it
243 // by removing instances of '.' and '..' when that makes sense.
244 // Note that it is not possible to simplify initial instances of
245 // '..', i.e. "foo/../../bar" -> "../bar"
246 static void simplifyComponents(std::vector<std::string>* components);
247 template <class String>
248 static void simplifyComponents(std::vector<String>* components);
249
250 // Returns a version of |path| that is relative to |base|.
251 // This can be useful for converting absolute paths to
252 // relative paths given |base|.
253 // Example:
254 // |base|: C:\Users\foo
255 // |path|: C:\Users\foo\AppData\Local\Android\Sdk
256 // would give
257 // AppData\Local\Android\Sdk.
258 // If |base| is not a prefix of |path|, fails by returning
259 // the original |path| unmodified.
260 static std::string relativeTo(const char* base, const char* path, HostType hostType);
261 static std::string relativeTo(const char* base, const char* path) {
262 return relativeTo(base, path, HOST_TYPE);
263 }
264
265 static Optional<std::string> pathWithoutDirs(const char* name);
266 static Optional<std::string> pathToDir(const char* name);
267
268 // Replaces the entries ${xx} with the value of the environment variable
269 // xx if it exists. Returns kNullopt if the environment variable is
270 // not set or empty.
271 static Optional<std::string> pathWithEnvSubstituted(const char* path);
272
273 // Replaces the entries ${xx} with the value of the environment variable
274 // xx if it exists. Returns kNullopt if the environment variable is
275 // not set or empty.
276 static Optional<std::string> pathWithEnvSubstituted(std::vector<std::string> decomposedPath);
277
278#ifdef _WIN32
279 static Win32UnicodeString asUnicodePath(const char* path) { return Win32UnicodeString(path); }
280#else
281 static std::string asUnicodePath(const char* path) { return path; }
282#endif
283};
284
285// Useful shortcuts to avoid too much typing.
286static const PathUtils::HostType kHostPosix = PathUtils::HOST_POSIX;
287static const PathUtils::HostType kHostWin32 = PathUtils::HOST_WIN32;
288static const PathUtils::HostType kHostType = PathUtils::HOST_TYPE;
289
290template <class... Paths>
291std::string pj(const std::string& path1,
292 const std::string& path2,
293 Paths&&... paths) {
294 return PathUtils::join(path1,
295 pj(path2, std::forward<Paths>(paths)...));
296}
297
298std::string pj(const std::string& path1, const std::string& path2);
299
300std::string pj(const std::vector<std::string>& paths);
301
302bool pathExists(const char* path);
303
304} // namespace base
305} // namespace android