blob: 728f036023094ec5c21159fd8906796f7bceb129 [file] [log] [blame]
Michael J. Spencerdffde992010-11-29 22:28:51 +00001//===-- PathV2.cpp - Implement OS Path Concept ------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the operating system PathV2 API.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/Support/PathV2.h"
Michael J. Spencerbee0c382010-12-01 19:32:01 +000015#include "llvm/Support/FileSystem.h"
Michael J. Spencerdffde992010-11-29 22:28:51 +000016#include "llvm/Support/ErrorHandling.h"
17#include <cctype>
18
19namespace {
20 using llvm::StringRef;
21
22 bool is_separator(const char value) {
23 switch(value) {
24#ifdef LLVM_ON_WIN32
25 case '\\': // fall through
26#endif
27 case '/': return true;
28 default: return false;
29 }
30 }
31
32#ifdef LLVM_ON_WIN32
33 const StringRef separators = "\\/";
Michael J. Spencerca3a3392010-12-07 03:57:48 +000034 const char prefered_separator = '\\';
Michael J. Spencerdffde992010-11-29 22:28:51 +000035#else
36 const StringRef separators = "/";
37 const char prefered_separator = '/';
38#endif
39
Michael J. Spencer470ae132010-12-04 00:32:40 +000040 const llvm::error_code success;
41
Michael J. Spencerdffde992010-11-29 22:28:51 +000042 StringRef find_first_component(const StringRef &path) {
43 // Look for this first component in the following order.
44 // * empty (in this case we return an empty string)
45 // * either C: or {//,\\}net.
46 // * {/,\}
47 // * {.,..}
48 // * {file,directory}name
49
50 if (path.empty())
51 return path;
52
Michael J. Spencerca3a3392010-12-07 03:57:48 +000053#ifdef LLVM_ON_WIN32
Michael J. Spencerdffde992010-11-29 22:28:51 +000054 // C:
55 if (path.size() >= 2 && std::isalpha(path[0]) && path[1] == ':')
56 return StringRef(path.begin(), 2);
Michael J. Spencerca3a3392010-12-07 03:57:48 +000057#endif
Michael J. Spencerdffde992010-11-29 22:28:51 +000058
59 // //net
60 if ((path.size() > 2) &&
Michael J. Spencerca3a3392010-12-07 03:57:48 +000061 is_separator(path[0]) &&
62 path[0] == path[1] &&
63 !is_separator(path[2])) {
Michael J. Spencerdffde992010-11-29 22:28:51 +000064 // Find the next directory separator.
Michael J. Spencerca3a3392010-12-07 03:57:48 +000065 size_t end = path.find_first_of(separators, 2);
Michael J. Spencerdffde992010-11-29 22:28:51 +000066 if (end == StringRef::npos)
67 return path;
68 else
69 return StringRef(path.begin(), end);
70 }
71
72 // {/,\}
Michael J. Spencerca3a3392010-12-07 03:57:48 +000073 if (is_separator(path[0]))
Michael J. Spencerdffde992010-11-29 22:28:51 +000074 return StringRef(path.begin(), 1);
75
76 if (path.startswith(".."))
77 return StringRef(path.begin(), 2);
78
79 if (path[0] == '.')
80 return StringRef(path.begin(), 1);
81
82 // * {file,directory}name
Michael J. Spencerca3a3392010-12-07 03:57:48 +000083 size_t end = path.find_first_of(separators, 2);
Michael J. Spencerdffde992010-11-29 22:28:51 +000084 if (end == StringRef::npos)
85 return path;
86 else
87 return StringRef(path.begin(), end);
88
89 return StringRef();
90 }
Michael J. Spencera42cf732010-11-30 23:28:07 +000091
92 size_t filename_pos(const StringRef &str) {
93 if (str.size() == 2 &&
94 is_separator(str[0]) &&
Michael J. Spencerca3a3392010-12-07 03:57:48 +000095 str[0] == str[1])
Michael J. Spencera42cf732010-11-30 23:28:07 +000096 return 0;
97
98 if (str.size() > 0 && is_separator(str[str.size() - 1]))
99 return str.size() - 1;
100
101 size_t pos = str.find_last_of(separators, str.size() - 1);
102
103#ifdef LLVM_ON_WIN32
104 if (pos == StringRef::npos)
105 pos = str.find_last_of(':', str.size() - 2);
106#endif
107
108 if (pos == StringRef::npos ||
109 (pos == 1 && is_separator(str[0])))
110 return 0;
111
112 return pos + 1;
113 }
114
115 size_t root_dir_start(const StringRef &str) {
116 // case "c:/"
117#ifdef LLVM_ON_WIN32
118 if (str.size() > 2 &&
119 str[1] == ':' &&
120 is_separator(str[2]))
121 return 2;
122#endif
123
124 // case "//"
125 if (str.size() == 2 &&
126 is_separator(str[0]) &&
127 str[0] == str[1])
128 return StringRef::npos;
129
130 // case "//net"
131 if (str.size() > 3 &&
132 is_separator(str[0]) &&
133 str[0] == str[1] &&
134 !is_separator(str[2])) {
135 return str.find_first_of(separators, 2);
136 }
137
138 // case "/"
139 if (str.size() > 0 && is_separator(str[0]))
140 return 0;
141
142 return StringRef::npos;
143 }
144
145 size_t parent_path_end(const StringRef &path) {
146 size_t end_pos = filename_pos(path);
147
148 bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos]);
149
150 // Skip separators except for root dir.
151 size_t root_dir_pos = root_dir_start(StringRef(path.begin(), end_pos));
152
153 while(end_pos > 0 &&
154 (end_pos - 1) != root_dir_pos &&
155 is_separator(path[end_pos - 1]))
156 --end_pos;
157
158 if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep)
159 return StringRef::npos;
160
161 return end_pos;
162 }
Michael J. Spencerdffde992010-11-29 22:28:51 +0000163}
164
165namespace llvm {
166namespace sys {
167namespace path {
168
169const_iterator begin(const StringRef &path) {
170 const_iterator i;
171 i.Path = path;
172 i.Component = find_first_component(path);
173 i.Position = 0;
174 return i;
175}
176
177const_iterator end(const StringRef &path) {
178 const_iterator i;
179 i.Path = path;
180 i.Position = path.size();
181 return i;
182}
183
Michael J. Spencerdffde992010-11-29 22:28:51 +0000184const_iterator &const_iterator::operator++() {
185 assert(Position < Path.size() && "Tried to increment past end!");
186
187 // Increment Position to past the current component
188 Position += Component.size();
189
190 // Check for end.
191 if (Position == Path.size()) {
192 Component = StringRef();
193 return *this;
194 }
195
196 // Both POSIX and Windows treat paths that begin with exactly two separators
197 // specially.
198 bool was_net = Component.size() > 2 &&
199 is_separator(Component[0]) &&
200 Component[1] == Component[0] &&
201 !is_separator(Component[2]);
202
203 // Handle separators.
204 if (is_separator(Path[Position])) {
205 // Root dir.
206 if (was_net
207#ifdef LLVM_ON_WIN32
208 // c:/
209 || Component.endswith(":")
210#endif
211 ) {
212 Component = StringRef(Path.begin() + Position, 1);
213 return *this;
214 }
215
216 // Skip extra separators.
217 while (Position != Path.size() &&
218 is_separator(Path[Position])) {
219 ++Position;
220 }
221
222 // Treat trailing '/' as a '.'.
223 if (Position == Path.size()) {
224 --Position;
225 Component = ".";
226 return *this;
227 }
228 }
229
230 // Find next component.
231 size_t end_pos = Path.find_first_of(separators, Position);
232 if (end_pos == StringRef::npos)
233 end_pos = Path.size();
234 Component = StringRef(Path.begin() + Position, end_pos - Position);
235
236 return *this;
237}
238
Michael J. Spencera42cf732010-11-30 23:28:07 +0000239const_iterator &const_iterator::operator--() {
240 // If we're at the end and the previous char was a '/', return '.'.
241 if (Position == Path.size() &&
242 Path.size() > 1 &&
243 is_separator(Path[Position - 1])
244#ifdef LLVM_ON_WIN32
245 && Path[Position - 2] != ':'
246#endif
247 ) {
248 --Position;
249 Component = ".";
250 return *this;
251 }
252
253 // Skip separators unless it's the root directory.
254 size_t root_dir_pos = root_dir_start(Path);
255 size_t end_pos = Position;
256
257 while(end_pos > 0 &&
258 (end_pos - 1) != root_dir_pos &&
259 is_separator(Path[end_pos - 1]))
260 --end_pos;
261
262 // Find next separator.
263 size_t start_pos = filename_pos(StringRef(Path.begin(), end_pos));
264 Component = StringRef(Path.begin() + start_pos, end_pos - start_pos);
265 Position = start_pos;
266 return *this;
267}
268
Michael J. Spencerdffde992010-11-29 22:28:51 +0000269bool const_iterator::operator==(const const_iterator &RHS) const {
270 return Path.begin() == RHS.Path.begin() &&
271 Position == RHS.Position;
272}
273
274bool const_iterator::operator!=(const const_iterator &RHS) const {
275 return !(*this == RHS);
276}
277
Michael J. Spencera42cf732010-11-30 23:28:07 +0000278ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const {
279 return Position - RHS.Position;
280}
281
Michael J. Spencer936671b2010-12-07 03:57:37 +0000282void root_path(const StringRef &path, StringRef &result) {
Michael J. Spencerdffde992010-11-29 22:28:51 +0000283 const_iterator b = begin(path),
284 pos = b,
285 e = end(path);
286 if (b != e) {
287 bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
288 bool has_drive =
289#ifdef LLVM_ON_WIN32
290 b->endswith(":");
291#else
292 false;
293#endif
294
295 if (has_net || has_drive) {
296 if ((++pos != e) && is_separator((*pos)[0])) {
297 // {C:/,//net/}, so get the first two components.
298 result = StringRef(path.begin(), b->size() + pos->size());
Michael J. Spencer936671b2010-12-07 03:57:37 +0000299 return;
Michael J. Spencerdffde992010-11-29 22:28:51 +0000300 } else {
301 // just {C:,//net}, return the first component.
302 result = *b;
Michael J. Spencer936671b2010-12-07 03:57:37 +0000303 return;
Michael J. Spencerdffde992010-11-29 22:28:51 +0000304 }
305 }
306
307 // POSIX style root directory.
308 if (is_separator((*b)[0])) {
309 result = *b;
Michael J. Spencer936671b2010-12-07 03:57:37 +0000310 return;
Michael J. Spencerdffde992010-11-29 22:28:51 +0000311 }
Michael J. Spencerdffde992010-11-29 22:28:51 +0000312 }
313
Michael J. Spencerdffde992010-11-29 22:28:51 +0000314 result = StringRef();
Michael J. Spencerdffde992010-11-29 22:28:51 +0000315}
316
Michael J. Spencer936671b2010-12-07 03:57:37 +0000317void root_name(const StringRef &path, StringRef &result) {
Michael J. Spencerdffde992010-11-29 22:28:51 +0000318 const_iterator b = begin(path),
319 e = end(path);
320 if (b != e) {
321 bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
322 bool has_drive =
323#ifdef LLVM_ON_WIN32
324 b->endswith(":");
325#else
326 false;
327#endif
328
329 if (has_net || has_drive) {
330 // just {C:,//net}, return the first component.
331 result = *b;
Michael J. Spencer936671b2010-12-07 03:57:37 +0000332 return;
Michael J. Spencerdffde992010-11-29 22:28:51 +0000333 }
334 }
335
336 // No path or no name.
337 result = StringRef();
Michael J. Spencer936671b2010-12-07 03:57:37 +0000338 return;
Michael J. Spencerdffde992010-11-29 22:28:51 +0000339}
340
Michael J. Spencer936671b2010-12-07 03:57:37 +0000341void root_directory(const StringRef &path, StringRef &result) {
Michael J. Spencerdffde992010-11-29 22:28:51 +0000342 const_iterator b = begin(path),
343 pos = b,
344 e = end(path);
345 if (b != e) {
346 bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
347 bool has_drive =
348#ifdef LLVM_ON_WIN32
349 b->endswith(":");
350#else
351 false;
352#endif
353
354 if ((has_net || has_drive) &&
355 // {C:,//net}, skip to the next component.
356 (++pos != e) && is_separator((*pos)[0])) {
357 result = *pos;
Michael J. Spencer936671b2010-12-07 03:57:37 +0000358 return;
Michael J. Spencerdffde992010-11-29 22:28:51 +0000359 }
360
361 // POSIX style root directory.
362 if (!has_net && is_separator((*b)[0])) {
363 result = *b;
Michael J. Spencer936671b2010-12-07 03:57:37 +0000364 return;
Michael J. Spencerdffde992010-11-29 22:28:51 +0000365 }
366 }
367
368 // No path or no root.
369 result = StringRef();
Michael J. Spencer936671b2010-12-07 03:57:37 +0000370 return;
Michael J. Spencerdffde992010-11-29 22:28:51 +0000371}
372
Michael J. Spencer936671b2010-12-07 03:57:37 +0000373void relative_path(const StringRef &path, StringRef &result) {
Michael J. Spencerdffde992010-11-29 22:28:51 +0000374 StringRef root;
Michael J. Spencer936671b2010-12-07 03:57:37 +0000375 root_path(path, root);
Michael J. Spencerdffde992010-11-29 22:28:51 +0000376 result = StringRef(path.begin() + root.size(), path.size() - root.size());
Michael J. Spencer936671b2010-12-07 03:57:37 +0000377 return;
Michael J. Spencerdffde992010-11-29 22:28:51 +0000378}
379
Michael J. Spencer936671b2010-12-07 03:57:37 +0000380void append(SmallVectorImpl<char> &path, const Twine &a,
381 const Twine &b,
382 const Twine &c,
383 const Twine &d) {
Michael J. Spencerdffde992010-11-29 22:28:51 +0000384 SmallString<32> a_storage;
385 SmallString<32> b_storage;
386 SmallString<32> c_storage;
387 SmallString<32> d_storage;
388
389 SmallVector<StringRef, 4> components;
390 if (!a.isTriviallyEmpty()) components.push_back(a.toStringRef(a_storage));
391 if (!b.isTriviallyEmpty()) components.push_back(b.toStringRef(b_storage));
392 if (!c.isTriviallyEmpty()) components.push_back(c.toStringRef(c_storage));
393 if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage));
394
395 for (SmallVectorImpl<StringRef>::const_iterator i = components.begin(),
396 e = components.end();
397 i != e; ++i) {
398 bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1]);
399 bool component_has_sep = !i->empty() && is_separator((*i)[0]);
Bill Wendlinga6091be2010-12-04 20:20:34 +0000400 bool is_root_name = false;
Michael J. Spencer936671b2010-12-07 03:57:37 +0000401 has_root_name(*i, is_root_name);
Michael J. Spencerdffde992010-11-29 22:28:51 +0000402
403 if (path_has_sep) {
404 // Strip separators from beginning of component.
405 size_t loc = i->find_first_not_of(separators);
406 StringRef c = StringRef(i->begin() + loc, i->size() - loc);
407
408 // Append it.
409 path.append(c.begin(), c.end());
410 continue;
411 }
412
Michael J. Spencerf150e762010-12-06 04:28:23 +0000413 if (!component_has_sep && !(path.empty() || is_root_name)) {
Michael J. Spencerdffde992010-11-29 22:28:51 +0000414 // Add a separator.
415 path.push_back(prefered_separator);
416 }
417
418 path.append(i->begin(), i->end());
419 }
Michael J. Spencerdffde992010-11-29 22:28:51 +0000420}
421
Michael J. Spencer936671b2010-12-07 03:57:37 +0000422void parent_path(const StringRef &path, StringRef &result) {
Michael J. Spencera42cf732010-11-30 23:28:07 +0000423 size_t end_pos = parent_path_end(path);
424 if (end_pos == StringRef::npos)
425 result = StringRef();
426 else
427 result = StringRef(path.data(), end_pos);
Michael J. Spencera42cf732010-11-30 23:28:07 +0000428}
429
Michael J. Spencer936671b2010-12-07 03:57:37 +0000430void remove_filename(SmallVectorImpl<char> &path) {
Michael J. Spencerdbfb56b2010-12-01 00:52:28 +0000431 size_t end_pos = parent_path_end(StringRef(path.begin(), path.size()));
Michael J. Spencer936671b2010-12-07 03:57:37 +0000432 if (end_pos != StringRef::npos)
433 path.set_size(end_pos);
Michael J. Spencerdbfb56b2010-12-01 00:52:28 +0000434}
435
Michael J. Spencer936671b2010-12-07 03:57:37 +0000436void replace_extension(SmallVectorImpl<char> &path,
Michael J. Spencer52ed8672010-12-01 00:52:55 +0000437 const Twine &extension) {
438 StringRef p(path.begin(), path.size());
439 SmallString<32> ext_storage;
440 StringRef ext = extension.toStringRef(ext_storage);
441
442 // Erase existing extension.
443 size_t pos = p.find_last_of('.');
444 if (pos != StringRef::npos && pos >= filename_pos(p))
445 path.set_size(pos);
446
447 // Append '.' if needed.
448 if (ext.size() > 0 && ext[0] != '.')
449 path.push_back('.');
450
451 // Append extension.
452 path.append(ext.begin(), ext.end());
Michael J. Spencer52ed8672010-12-01 00:52:55 +0000453}
454
Michael J. Spencer936671b2010-12-07 03:57:37 +0000455void native(const Twine &path, SmallVectorImpl<char> &result) {
Michael J. Spencer722d5ad2010-12-01 02:48:27 +0000456 // Clear result.
Michael J. Spencerfbd1bbd2010-12-07 01:23:19 +0000457 result.clear();
Michael J. Spencer722d5ad2010-12-01 02:48:27 +0000458#ifdef LLVM_ON_WIN32
459 SmallString<128> path_storage;
460 StringRef p = path.toStringRef(path_storage);
461 result.reserve(p.size());
462 for (StringRef::const_iterator i = p.begin(),
463 e = p.end();
464 i != e;
465 ++i) {
466 if (*i == '/')
467 result.push_back('\\');
468 else
469 result.push_back(*i);
470 }
471#else
472 path.toVector(result);
473#endif
Michael J. Spencer722d5ad2010-12-01 02:48:27 +0000474}
475
Michael J. Spencer936671b2010-12-07 03:57:37 +0000476void filename(const StringRef &path, StringRef &result) {
Michael J. Spencera9793552010-12-01 03:18:17 +0000477 result = *(--end(path));
Michael J. Spencera9793552010-12-01 03:18:17 +0000478}
479
Michael J. Spencer936671b2010-12-07 03:57:37 +0000480void stem(const StringRef &path, StringRef &result) {
Michael J. Spencer34ab1f62010-12-01 03:18:33 +0000481 StringRef fname;
Michael J. Spencer936671b2010-12-07 03:57:37 +0000482 filename(path, fname);
Michael J. Spencer34ab1f62010-12-01 03:18:33 +0000483 size_t pos = fname.find_last_of('.');
484 if (pos == StringRef::npos)
485 result = fname;
486 else
487 if ((fname.size() == 1 && fname == ".") ||
488 (fname.size() == 2 && fname == ".."))
489 result = fname;
490 else
491 result = StringRef(fname.begin(), pos);
Michael J. Spencer34ab1f62010-12-01 03:18:33 +0000492}
493
Michael J. Spencer936671b2010-12-07 03:57:37 +0000494void extension(const StringRef &path, StringRef &result) {
Michael J. Spencer5265f222010-12-01 03:37:41 +0000495 StringRef fname;
Michael J. Spencer936671b2010-12-07 03:57:37 +0000496 filename(path, fname);
Michael J. Spencer5265f222010-12-01 03:37:41 +0000497 size_t pos = fname.find_last_of('.');
498 if (pos == StringRef::npos)
499 result = StringRef();
500 else
501 if ((fname.size() == 1 && fname == ".") ||
502 (fname.size() == 2 && fname == ".."))
503 result = StringRef();
504 else
505 result = StringRef(fname.begin() + pos, fname.size() - pos);
Michael J. Spencer5265f222010-12-01 03:37:41 +0000506}
507
Michael J. Spencer936671b2010-12-07 03:57:37 +0000508void has_root_name(const Twine &path, bool &result) {
Michael J. Spencerae180082010-12-01 06:03:50 +0000509 SmallString<128> path_storage;
510 StringRef p = path.toStringRef(path_storage);
511
Michael J. Spencer936671b2010-12-07 03:57:37 +0000512 root_name(p, p);
Michael J. Spencerae180082010-12-01 06:03:50 +0000513
514 result = !p.empty();
Michael J. Spencerae180082010-12-01 06:03:50 +0000515}
516
Michael J. Spencer936671b2010-12-07 03:57:37 +0000517void has_root_directory(const Twine &path, bool &result) {
Michael J. Spencerae180082010-12-01 06:03:50 +0000518 SmallString<128> path_storage;
519 StringRef p = path.toStringRef(path_storage);
520
Michael J. Spencer936671b2010-12-07 03:57:37 +0000521 root_directory(p, p);
Michael J. Spencerae180082010-12-01 06:03:50 +0000522
523 result = !p.empty();
Michael J. Spencerae180082010-12-01 06:03:50 +0000524}
525
Michael J. Spencer936671b2010-12-07 03:57:37 +0000526void has_root_path(const Twine &path, bool &result) {
Michael J. Spencerae180082010-12-01 06:03:50 +0000527 SmallString<128> path_storage;
528 StringRef p = path.toStringRef(path_storage);
529
Michael J. Spencer936671b2010-12-07 03:57:37 +0000530 root_path(p, p);
Michael J. Spencerae180082010-12-01 06:03:50 +0000531
532 result = !p.empty();
Michael J. Spencerae180082010-12-01 06:03:50 +0000533}
534
Michael J. Spencer936671b2010-12-07 03:57:37 +0000535void has_filename(const Twine &path, bool &result) {
Michael J. Spencerae180082010-12-01 06:03:50 +0000536 SmallString<128> path_storage;
537 StringRef p = path.toStringRef(path_storage);
538
Michael J. Spencer936671b2010-12-07 03:57:37 +0000539 filename(p, p);
Michael J. Spencerae180082010-12-01 06:03:50 +0000540
541 result = !p.empty();
Michael J. Spencerae180082010-12-01 06:03:50 +0000542}
543
Michael J. Spencer936671b2010-12-07 03:57:37 +0000544void has_parent_path(const Twine &path, bool &result) {
Michael J. Spencerae180082010-12-01 06:03:50 +0000545 SmallString<128> path_storage;
546 StringRef p = path.toStringRef(path_storage);
547
Michael J. Spencer936671b2010-12-07 03:57:37 +0000548 parent_path(p, p);
Michael J. Spencerae180082010-12-01 06:03:50 +0000549
550 result = !p.empty();
Michael J. Spencerae180082010-12-01 06:03:50 +0000551}
552
Michael J. Spencer936671b2010-12-07 03:57:37 +0000553void has_stem(const Twine &path, bool &result) {
Michael J. Spencerae180082010-12-01 06:03:50 +0000554 SmallString<128> path_storage;
555 StringRef p = path.toStringRef(path_storage);
556
Michael J. Spencer936671b2010-12-07 03:57:37 +0000557 stem(p, p);
Michael J. Spencerae180082010-12-01 06:03:50 +0000558
559 result = !p.empty();
Michael J. Spencerae180082010-12-01 06:03:50 +0000560}
561
Michael J. Spencer936671b2010-12-07 03:57:37 +0000562void has_extension(const Twine &path, bool &result) {
Michael J. Spencerae180082010-12-01 06:03:50 +0000563 SmallString<128> path_storage;
564 StringRef p = path.toStringRef(path_storage);
565
Michael J. Spencer936671b2010-12-07 03:57:37 +0000566 extension(p, p);
Michael J. Spencerae180082010-12-01 06:03:50 +0000567
568 result = !p.empty();
Michael J. Spencerae180082010-12-01 06:03:50 +0000569}
570
Michael J. Spencer936671b2010-12-07 03:57:37 +0000571void is_absolute(const Twine &path, bool &result) {
Michael J. Spencerce2b68f2010-12-01 06:21:53 +0000572 SmallString<128> path_storage;
573 StringRef p = path.toStringRef(path_storage);
574
575 bool rootDir = false,
576 rootName = false;
Michael J. Spencer936671b2010-12-07 03:57:37 +0000577 has_root_directory(p, rootDir);
Michael J. Spencerce2b68f2010-12-01 06:21:53 +0000578#ifdef LLVM_ON_WIN32
Michael J. Spencer936671b2010-12-07 03:57:37 +0000579 has_root_name(p, rootName);
Michael J. Spencerce2b68f2010-12-01 06:21:53 +0000580#else
581 rootName = true;
582#endif
583
584 result = rootDir && rootName;
Michael J. Spencerce2b68f2010-12-01 06:21:53 +0000585}
586
Michael J. Spencer936671b2010-12-07 03:57:37 +0000587void is_relative(const Twine &path, bool &result) {
Michael J. Spencerce2b68f2010-12-01 06:21:53 +0000588 bool res;
Michael J. Spencer936671b2010-12-07 03:57:37 +0000589 is_absolute(path, res);
Michael J. Spencerce2b68f2010-12-01 06:21:53 +0000590 result = !res;
Michael J. Spencerce2b68f2010-12-01 06:21:53 +0000591}
592
Michael J. Spencerbee0c382010-12-01 19:32:01 +0000593} // end namespace path
594
595namespace fs {
596
Michael J. Spenceree271d82010-12-07 03:57:17 +0000597error_code make_absolute(SmallVectorImpl<char> &path) {
598 StringRef p(path.data(), path.size());
599
600 bool rootName = false, rootDirectory = false;
Michael J. Spencer936671b2010-12-07 03:57:37 +0000601 path::has_root_name(p, rootName);
602 path::has_root_directory(p, rootDirectory);
Michael J. Spenceree271d82010-12-07 03:57:17 +0000603
604 // Already absolute.
605 if (rootName && rootDirectory)
606 return success;
607
608 // All of the following conditions will need the current directory.
609 SmallString<128> current_dir;
610 if (error_code ec = current_path(current_dir)) return ec;
611
612 // Relative path. Prepend the current directory.
613 if (!rootName && !rootDirectory) {
614 // Append path to the current directory.
Michael J. Spencer936671b2010-12-07 03:57:37 +0000615 path::append(current_dir, p);
Michael J. Spenceree271d82010-12-07 03:57:17 +0000616 // Set path to the result.
617 path.swap(current_dir);
618 return success;
619 }
620
621 if (!rootName && rootDirectory) {
622 StringRef cdrn;
Michael J. Spencer936671b2010-12-07 03:57:37 +0000623 path::root_name(current_dir, cdrn);
Michael J. Spenceree271d82010-12-07 03:57:17 +0000624 SmallString<128> curDirRootName(cdrn.begin(), cdrn.end());
Michael J. Spencer936671b2010-12-07 03:57:37 +0000625 path::append(curDirRootName, p);
Michael J. Spenceree271d82010-12-07 03:57:17 +0000626 // Set path to the result.
627 path.swap(curDirRootName);
628 return success;
629 }
630
631 if (rootName && !rootDirectory) {
632 StringRef pRootName;
633 StringRef bRootDirectory;
634 StringRef bRelativePath;
635 StringRef pRelativePath;
Michael J. Spencer936671b2010-12-07 03:57:37 +0000636 path::root_name(p, pRootName);
637 path::root_directory(current_dir, bRootDirectory);
638 path::relative_path(current_dir, bRelativePath);
639 path::relative_path(p, pRelativePath);
Michael J. Spenceree271d82010-12-07 03:57:17 +0000640
641 SmallString<128> res;
Michael J. Spencer936671b2010-12-07 03:57:37 +0000642 path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath);
Michael J. Spenceree271d82010-12-07 03:57:17 +0000643 path.swap(res);
644 return success;
645 }
646
647 llvm_unreachable("All rootName and rootDirectory combinations should have "
648 "occurred above!");
649}
650
Michael J. Spencerb83769f2010-12-03 05:42:11 +0000651error_code create_directories(const Twine &path, bool &existed) {
652 SmallString<128> path_storage;
653 StringRef p = path.toStringRef(path_storage);
654
655 StringRef parent;
656 bool parent_exists;
Michael J. Spencer936671b2010-12-07 03:57:37 +0000657 path::parent_path(p, parent);
Michael J. Spencerb83769f2010-12-03 05:42:11 +0000658 if (error_code ec = fs::exists(parent, parent_exists)) return ec;
659
660 if (!parent_exists)
661 return create_directories(parent, existed);
662
663 return create_directory(p, existed);
664}
665
Michael J. Spencer753cbbb2010-12-06 04:28:42 +0000666void directory_entry::replace_filename(const Twine &filename, file_status st,
667 file_status symlink_st) {
668 SmallString<128> path(Path.begin(), Path.end());
669 path::remove_filename(path);
670 path::append(path, filename);
671 Path = path.str();
672 Status = st;
673 SymlinkStatus = symlink_st;
674}
675
Michael J. Spencerbee0c382010-12-01 19:32:01 +0000676} // end namespace fs
677} // end namespace sys
678} // end namespace llvm
Michael J. Spencerdffde992010-11-29 22:28:51 +0000679
680// Include the truly platform-specific parts.
681#if defined(LLVM_ON_UNIX)
682#include "Unix/PathV2.inc"
683#endif
684#if defined(LLVM_ON_WIN32)
685#include "Windows/PathV2.inc"
686#endif