1 //===-- PathV2.cpp - Implement OS Path Concept ------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements the operating system PathV2 API.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/Support/PathV2.h"
15 #include "llvm/Support/FileSystem.h"
16 #include "llvm/Support/ErrorHandling.h"
22 using llvm::StringRef
;
23 using llvm::sys::path::is_separator
;
26 const StringRef separators
= "\\/";
27 const char prefered_separator
= '\\';
29 const StringRef separators
= "/";
30 const char prefered_separator
= '/';
33 const llvm::error_code success
;
35 StringRef
find_first_component(StringRef path
) {
36 // Look for this first component in the following order.
37 // * empty (in this case we return an empty string)
38 // * either C: or {//,\\}net.
41 // * {file,directory}name
48 if (path
.size() >= 2 && std::isalpha(path
[0]) && path
[1] == ':')
49 return path
.substr(0, 2);
53 if ((path
.size() > 2) &&
54 is_separator(path
[0]) &&
56 !is_separator(path
[2])) {
57 // Find the next directory separator.
58 size_t end
= path
.find_first_of(separators
, 2);
59 return path
.substr(0, end
);
63 if (is_separator(path
[0]))
64 return path
.substr(0, 1);
66 if (path
.startswith(".."))
67 return path
.substr(0, 2);
70 return path
.substr(0, 1);
72 // * {file,directory}name
73 size_t end
= path
.find_first_of(separators
, 2);
74 return path
.substr(0, end
);
77 size_t filename_pos(StringRef str
) {
78 if (str
.size() == 2 &&
79 is_separator(str
[0]) &&
83 if (str
.size() > 0 && is_separator(str
[str
.size() - 1]))
84 return str
.size() - 1;
86 size_t pos
= str
.find_last_of(separators
, str
.size() - 1);
89 if (pos
== StringRef::npos
)
90 pos
= str
.find_last_of(':', str
.size() - 2);
93 if (pos
== StringRef::npos
||
94 (pos
== 1 && is_separator(str
[0])))
100 size_t root_dir_start(StringRef str
) {
103 if (str
.size() > 2 &&
105 is_separator(str
[2]))
110 if (str
.size() == 2 &&
111 is_separator(str
[0]) &&
113 return StringRef::npos
;
116 if (str
.size() > 3 &&
117 is_separator(str
[0]) &&
119 !is_separator(str
[2])) {
120 return str
.find_first_of(separators
, 2);
124 if (str
.size() > 0 && is_separator(str
[0]))
127 return StringRef::npos
;
130 size_t parent_path_end(StringRef path
) {
131 size_t end_pos
= filename_pos(path
);
133 bool filename_was_sep
= path
.size() > 0 && is_separator(path
[end_pos
]);
135 // Skip separators except for root dir.
136 size_t root_dir_pos
= root_dir_start(path
.substr(0, end_pos
));
139 (end_pos
- 1) != root_dir_pos
&&
140 is_separator(path
[end_pos
- 1]))
143 if (end_pos
== 1 && root_dir_pos
== 0 && filename_was_sep
)
144 return StringRef::npos
;
148 } // end unnamed namespace
154 const_iterator
begin(StringRef path
) {
157 i
.Component
= find_first_component(path
);
162 const_iterator
end(StringRef path
) {
165 i
.Position
= path
.size();
169 const_iterator
&const_iterator::operator++() {
170 assert(Position
< Path
.size() && "Tried to increment past end!");
172 // Increment Position to past the current component
173 Position
+= Component
.size();
176 if (Position
== Path
.size()) {
177 Component
= StringRef();
181 // Both POSIX and Windows treat paths that begin with exactly two separators
183 bool was_net
= Component
.size() > 2 &&
184 is_separator(Component
[0]) &&
185 Component
[1] == Component
[0] &&
186 !is_separator(Component
[2]);
188 // Handle separators.
189 if (is_separator(Path
[Position
])) {
194 || Component
.endswith(":")
197 Component
= Path
.substr(Position
, 1);
201 // Skip extra separators.
202 while (Position
!= Path
.size() &&
203 is_separator(Path
[Position
])) {
207 // Treat trailing '/' as a '.'.
208 if (Position
== Path
.size()) {
215 // Find next component.
216 size_t end_pos
= Path
.find_first_of(separators
, Position
);
217 Component
= Path
.slice(Position
, end_pos
);
222 const_iterator
&const_iterator::operator--() {
223 // If we're at the end and the previous char was a '/', return '.'.
224 if (Position
== Path
.size() &&
226 is_separator(Path
[Position
- 1])
228 && Path
[Position
- 2] != ':'
236 // Skip separators unless it's the root directory.
237 size_t root_dir_pos
= root_dir_start(Path
);
238 size_t end_pos
= Position
;
241 (end_pos
- 1) != root_dir_pos
&&
242 is_separator(Path
[end_pos
- 1]))
245 // Find next separator.
246 size_t start_pos
= filename_pos(Path
.substr(0, end_pos
));
247 Component
= Path
.slice(start_pos
, end_pos
);
248 Position
= start_pos
;
252 bool const_iterator::operator==(const const_iterator
&RHS
) const {
253 return Path
.begin() == RHS
.Path
.begin() &&
254 Position
== RHS
.Position
;
257 bool const_iterator::operator!=(const const_iterator
&RHS
) const {
258 return !(*this == RHS
);
261 ptrdiff_t const_iterator::operator-(const const_iterator
&RHS
) const {
262 return Position
- RHS
.Position
;
265 const StringRef
root_path(StringRef path
) {
266 const_iterator b
= begin(path
),
270 bool has_net
= b
->size() > 2 && is_separator((*b
)[0]) && (*b
)[1] == (*b
)[0];
278 if (has_net
|| has_drive
) {
279 if ((++pos
!= e
) && is_separator((*pos
)[0])) {
280 // {C:/,//net/}, so get the first two components.
281 return path
.substr(0, b
->size() + pos
->size());
283 // just {C:,//net}, return the first component.
288 // POSIX style root directory.
289 if (is_separator((*b
)[0])) {
297 const StringRef
root_name(StringRef path
) {
298 const_iterator b
= begin(path
),
301 bool has_net
= b
->size() > 2 && is_separator((*b
)[0]) && (*b
)[1] == (*b
)[0];
309 if (has_net
|| has_drive
) {
310 // just {C:,//net}, return the first component.
315 // No path or no name.
319 const StringRef
root_directory(StringRef path
) {
320 const_iterator b
= begin(path
),
324 bool has_net
= b
->size() > 2 && is_separator((*b
)[0]) && (*b
)[1] == (*b
)[0];
332 if ((has_net
|| has_drive
) &&
333 // {C:,//net}, skip to the next component.
334 (++pos
!= e
) && is_separator((*pos
)[0])) {
338 // POSIX style root directory.
339 if (!has_net
&& is_separator((*b
)[0])) {
344 // No path or no root.
348 const StringRef
relative_path(StringRef path
) {
349 StringRef root
= root_path(path
);
350 return root
.substr(root
.size());
353 void append(SmallVectorImpl
<char> &path
, const Twine
&a
,
357 SmallString
<32> a_storage
;
358 SmallString
<32> b_storage
;
359 SmallString
<32> c_storage
;
360 SmallString
<32> d_storage
;
362 SmallVector
<StringRef
, 4> components
;
363 if (!a
.isTriviallyEmpty()) components
.push_back(a
.toStringRef(a_storage
));
364 if (!b
.isTriviallyEmpty()) components
.push_back(b
.toStringRef(b_storage
));
365 if (!c
.isTriviallyEmpty()) components
.push_back(c
.toStringRef(c_storage
));
366 if (!d
.isTriviallyEmpty()) components
.push_back(d
.toStringRef(d_storage
));
368 for (SmallVectorImpl
<StringRef
>::const_iterator i
= components
.begin(),
369 e
= components
.end();
371 bool path_has_sep
= !path
.empty() && is_separator(path
[path
.size() - 1]);
372 bool component_has_sep
= !i
->empty() && is_separator((*i
)[0]);
373 bool is_root_name
= has_root_name(*i
);
376 // Strip separators from beginning of component.
377 size_t loc
= i
->find_first_not_of(separators
);
378 StringRef c
= i
->substr(loc
);
381 path
.append(c
.begin(), c
.end());
385 if (!component_has_sep
&& !(path
.empty() || is_root_name
)) {
387 path
.push_back(prefered_separator
);
390 path
.append(i
->begin(), i
->end());
394 void append(SmallVectorImpl
<char> &path
,
395 const_iterator begin
, const_iterator end
) {
396 for (; begin
!= end
; ++begin
)
397 path::append(path
, *begin
);
400 const StringRef
parent_path(StringRef path
) {
401 size_t end_pos
= parent_path_end(path
);
402 if (end_pos
== StringRef::npos
)
405 return path
.substr(0, end_pos
);
408 void remove_filename(SmallVectorImpl
<char> &path
) {
409 size_t end_pos
= parent_path_end(StringRef(path
.begin(), path
.size()));
410 if (end_pos
!= StringRef::npos
)
411 path
.set_size(end_pos
);
414 void replace_extension(SmallVectorImpl
<char> &path
, const Twine
&extension
) {
415 StringRef
p(path
.begin(), path
.size());
416 SmallString
<32> ext_storage
;
417 StringRef ext
= extension
.toStringRef(ext_storage
);
419 // Erase existing extension.
420 size_t pos
= p
.find_last_of('.');
421 if (pos
!= StringRef::npos
&& pos
>= filename_pos(p
))
424 // Append '.' if needed.
425 if (ext
.size() > 0 && ext
[0] != '.')
429 path
.append(ext
.begin(), ext
.end());
432 void native(const Twine
&path
, SmallVectorImpl
<char> &result
) {
436 SmallString
<128> path_storage
;
437 StringRef p
= path
.toStringRef(path_storage
);
438 result
.reserve(p
.size());
439 for (StringRef::const_iterator i
= p
.begin(),
444 result
.push_back('\\');
446 result
.push_back(*i
);
449 path
.toVector(result
);
453 const StringRef
filename(StringRef path
) {
454 return *(--end(path
));
457 const StringRef
stem(StringRef path
) {
458 StringRef fname
= filename(path
);
459 size_t pos
= fname
.find_last_of('.');
460 if (pos
== StringRef::npos
)
463 if ((fname
.size() == 1 && fname
== ".") ||
464 (fname
.size() == 2 && fname
== ".."))
467 return fname
.substr(0, pos
);
470 const StringRef
extension(StringRef path
) {
471 StringRef fname
= filename(path
);
472 size_t pos
= fname
.find_last_of('.');
473 if (pos
== StringRef::npos
)
476 if ((fname
.size() == 1 && fname
== ".") ||
477 (fname
.size() == 2 && fname
== ".."))
480 return fname
.substr(pos
);
483 bool is_separator(char value
) {
486 case '\\': // fall through
488 case '/': return true;
489 default: return false;
493 bool has_root_name(const Twine
&path
) {
494 SmallString
<128> path_storage
;
495 StringRef p
= path
.toStringRef(path_storage
);
497 return !root_name(p
).empty();
500 bool has_root_directory(const Twine
&path
) {
501 SmallString
<128> path_storage
;
502 StringRef p
= path
.toStringRef(path_storage
);
504 return !root_directory(p
).empty();
507 bool has_root_path(const Twine
&path
) {
508 SmallString
<128> path_storage
;
509 StringRef p
= path
.toStringRef(path_storage
);
511 return !root_path(p
).empty();
514 bool has_relative_path(const Twine
&path
) {
515 SmallString
<128> path_storage
;
516 StringRef p
= path
.toStringRef(path_storage
);
518 return !relative_path(p
).empty();
521 bool has_filename(const Twine
&path
) {
522 SmallString
<128> path_storage
;
523 StringRef p
= path
.toStringRef(path_storage
);
525 return !filename(p
).empty();
528 bool has_parent_path(const Twine
&path
) {
529 SmallString
<128> path_storage
;
530 StringRef p
= path
.toStringRef(path_storage
);
532 return !parent_path(p
).empty();
535 bool has_stem(const Twine
&path
) {
536 SmallString
<128> path_storage
;
537 StringRef p
= path
.toStringRef(path_storage
);
539 return !stem(p
).empty();
542 bool has_extension(const Twine
&path
) {
543 SmallString
<128> path_storage
;
544 StringRef p
= path
.toStringRef(path_storage
);
546 return !extension(p
).empty();
549 bool is_absolute(const Twine
&path
) {
550 SmallString
<128> path_storage
;
551 StringRef p
= path
.toStringRef(path_storage
);
553 bool rootDir
= has_root_directory(p
),
555 rootName
= has_root_name(p
);
560 return rootDir
&& rootName
;
563 bool is_relative(const Twine
&path
) {
564 return !is_absolute(path
);
567 } // end namespace path
571 error_code
make_absolute(SmallVectorImpl
<char> &path
) {
572 StringRef
p(path
.data(), path
.size());
574 bool rootName
= path::has_root_name(p
),
575 rootDirectory
= path::has_root_directory(p
);
578 if (rootName
&& rootDirectory
)
581 // All of the following conditions will need the current directory.
582 SmallString
<128> current_dir
;
583 if (error_code ec
= current_path(current_dir
)) return ec
;
585 // Relative path. Prepend the current directory.
586 if (!rootName
&& !rootDirectory
) {
587 // Append path to the current directory.
588 path::append(current_dir
, p
);
589 // Set path to the result.
590 path
.swap(current_dir
);
594 if (!rootName
&& rootDirectory
) {
595 StringRef cdrn
= path::root_name(current_dir
);
596 SmallString
<128> curDirRootName(cdrn
.begin(), cdrn
.end());
597 path::append(curDirRootName
, p
);
598 // Set path to the result.
599 path
.swap(curDirRootName
);
603 if (rootName
&& !rootDirectory
) {
604 StringRef pRootName
= path::root_name(p
);
605 StringRef bRootDirectory
= path::root_directory(current_dir
);
606 StringRef bRelativePath
= path::relative_path(current_dir
);
607 StringRef pRelativePath
= path::relative_path(p
);
609 SmallString
<128> res
;
610 path::append(res
, pRootName
, bRootDirectory
, bRelativePath
, pRelativePath
);
615 llvm_unreachable("All rootName and rootDirectory combinations should have "
619 error_code
create_directories(const Twine
&path
, bool &existed
) {
620 SmallString
<128> path_storage
;
621 StringRef p
= path
.toStringRef(path_storage
);
623 StringRef parent
= path::parent_path(p
);
626 if (error_code ec
= fs::exists(parent
, parent_exists
)) return ec
;
629 return create_directories(parent
, existed
);
631 return create_directory(p
, existed
);
634 bool exists(file_status status
) {
635 return status_known(status
) && status
.type() != file_type::file_not_found
;
638 bool status_known(file_status s
) {
639 return s
.type() != file_type::status_error
;
642 bool is_directory(file_status status
) {
643 return status
.type() == file_type::directory_file
;
646 error_code
is_directory(const Twine
&path
, bool &result
) {
648 if (error_code ec
= status(path
, st
))
650 result
= is_directory(st
);
654 bool is_regular_file(file_status status
) {
655 return status
.type() == file_type::regular_file
;
658 error_code
is_regular_file(const Twine
&path
, bool &result
) {
660 if (error_code ec
= status(path
, st
))
662 result
= is_regular_file(st
);
666 bool is_symlink(file_status status
) {
667 return status
.type() == file_type::symlink_file
;
670 error_code
is_symlink(const Twine
&path
, bool &result
) {
672 if (error_code ec
= status(path
, st
))
674 result
= is_symlink(st
);
678 bool is_other(file_status status
) {
679 return exists(status
) &&
680 !is_regular_file(status
) &&
681 !is_directory(status
) &&
685 void directory_entry::replace_filename(const Twine
&filename
, file_status st
,
686 file_status symlink_st
) {
687 SmallString
<128> path(Path
.begin(), Path
.end());
688 path::remove_filename(path
);
689 path::append(path
, filename
);
692 SymlinkStatus
= symlink_st
;
695 error_code
has_magic(const Twine
&path
, const Twine
&magic
, bool &result
) {
696 SmallString
<32> MagicStorage
;
697 StringRef Magic
= magic
.toStringRef(MagicStorage
);
698 SmallString
<32> Buffer
;
700 if (error_code ec
= get_magic(path
, Magic
.size(), Buffer
)) {
701 if (ec
== errc::value_too_large
) {
702 // Magic.size() > file_size(Path).
709 result
= Magic
== Buffer
;
713 error_code
identify_magic(const Twine
&path
, LLVMFileType
&result
) {
714 SmallString
<32> Magic
;
715 error_code ec
= get_magic(path
, Magic
.capacity(), Magic
);
716 if (ec
&& ec
!= errc::value_too_large
)
719 result
= IdentifyFileType(Magic
.data(), Magic
.size());
724 error_code
remove_all_r(StringRef path
, file_type ft
, uint32_t &count
) {
725 if (ft
== file_type::directory_file
) {
726 // This code would be a lot better with exceptions ;/.
728 for (directory_iterator
i(path
, ec
), e
; i
!= e
; i
.increment(ec
)) {
731 if (error_code ec
= i
->status(st
)) return ec
;
732 if (error_code ec
= remove_all_r(i
->path(), st
.type(), count
)) return ec
;
734 bool obviously_this_exists
;
735 if (error_code ec
= remove(path
, obviously_this_exists
)) return ec
;
736 assert(obviously_this_exists
);
737 ++count
; // Include the directory itself in the items removed.
739 bool obviously_this_exists
;
740 if (error_code ec
= remove(path
, obviously_this_exists
)) return ec
;
741 assert(obviously_this_exists
);
747 } // end unnamed namespace
749 error_code
remove_all(const Twine
&path
, uint32_t &num_removed
) {
750 SmallString
<128> path_storage
;
751 StringRef p
= path
.toStringRef(path_storage
);
754 if (error_code ec
= status(path
, fs
))
757 return remove_all_r(p
, fs
.type(), num_removed
);
760 error_code
directory_entry::status(file_status
&result
) const {
761 return fs::status(Path
, result
);
764 } // end namespace fs
765 } // end namespace sys
766 } // end namespace llvm
768 // Include the truly platform-specific parts.
769 #if defined(LLVM_ON_UNIX)
770 #include "Unix/PathV2.inc"
772 #if defined(LLVM_ON_WIN32)
773 #include "Windows/PathV2.inc"