1 /* ///////////////////////////////////////////////////////////////////////
10 * Copyright (c) 2008-2020, Waruqi All rights reserved.
11 * //////////////////////////////////////////////////////////////////// */
13 #ifndef EXTL_PLATFORM_WIN_PATH_H
14 #define EXTL_PLATFORM_WIN_PATH_H
21 # error path.h need be supported by c++.
24 /* ///////////////////////////////////////////////////////////////////////
27 #include "filesystem_traits.h"
28 #include "path_entry_iterator.h"
29 #include "../../memory/allocator_selector.h"
30 #include "../../string/string.h"
31 #include "../../utility/operators.h"
32 /* ///////////////////////////////////////////////////////////////////////
33 * ::extl::platform::win namespace
35 EXTL_WIN_BEGIN_WHOLE_NAMESPACE
37 /*!\brief basic_path class
39 * \param C The character type
40 * \param S The string type
41 * \param T The filesystem_traits
43 * \ingroup extl_group_filesystem
45 template< typename_param_k C
46 #ifdef EXTL_TEMPLATE_CLASS_DEFAULT_ARGUMENT_SUPPORT
47 , typename_param_k S
= typename_type_def_k filesystem_traits
<C
>::stack_path_string_type
48 , typename_param_k T
= filesystem_traits
<C
>
56 #ifndef EXTL_COMPILER_IS_DMC
58 : private operators_equal_1_2_
<basic_path
<C
, S
, T
>, typename_type_k
S::const_pointer
59 , operators_div_1_2_
<basic_path
<C
, S
, T
>, typename_type_k
S::const_pointer
60 #ifndef EXTL_TEMPLATE_CLASS_DEFAULT_ARGUMENT_SUPPORT
61 , operators_base_
< basic_path
<C
, S
, T
> >
70 typedef S string_type
;
71 typedef T filesystem_traits_type
;
72 typedef basic_path
<C
, S
, T
> class_type
;
73 typedef char_type value_type
;
74 typedef value_type
* pointer
;
75 typedef value_type
const* const_pointer
;
76 typedef value_type
& reference
;
77 typedef value_type
const& const_reference
;
78 typedef typename_type_k
string_type::string_traits_type string_traits_type
;
79 typedef typename_type_k
filesystem_traits_type::path_traits_type path_traits_type
;
80 typedef typename_type_k
filesystem_traits_type::system_traits_type system_traits_type
;
81 typedef typename_type_k
filesystem_traits_type::size_type size_type
;
82 typedef typename_type_k
filesystem_traits_type::bool_type bool_type
;
83 typedef const_path_entry_iterator
<char_type
, path_traits
<char_type
> > const_entry_iterator
;
84 typedef const_reverse_path_entry_iterator
<char_type
, path_traits
<char_type
> > const_reverse_entry_iterator
;
85 typedef typename_type_k
const_entry_iterator::path_entry_type path_entry_type
;
86 typedef typename_type_k
const_entry_iterator::enum_flag_type enum_flag_type
;
90 #if defined(EXTL_COMPILER_IS_DMC)
91 EXTL_OPERATORS_EQUAL_1_2_(class_type
const&, const_pointer
)
92 // EXTL_OPERATORS_DIV_1_2_(class_type const&, const_pointer)
94 friend class_type
operator/(class_type
const& lhs
, class_type
const& rhs
)
95 { basic_path
<C
, S
, T
> ret(lhs
); ret
/= rhs
; return ret
; }
96 friend class_type
operator/(class_type
const& lhs
, const_pointer rhs
)
97 { basic_path
<C
, S
, T
> ret(lhs
); ret
/= rhs
; return ret
; }
98 friend class_type
operator/(const_pointer lhs
, class_type
const& rhs
)
99 { basic_path
<C
, S
, T
> ret(lhs
); ret
/= rhs
; return ret
; } // _left_2
102 /// \name Constructors
109 explicit_k
basic_path(const_pointer path
)
113 basic_path(const_pointer path
, size_type size
)
117 basic_path(class_type
const& path
)
118 : m_path(path
.m_path
)
122 #ifdef EXTL_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED_SUPPORT
123 template< typename_param_k S1
>
124 explicit_k
basic_path(S1
const& s
)
125 : m_path(c_strptr(s
), c_strlen(s
))
134 class_type
& operator =(const_pointer rhs
) { m_path
.assign(rhs
); return *this; }
135 class_type
& operator =(class_type
const& rhs
) { m_path
.assign(rhs
.m_path
); return *this; }
136 #ifdef EXTL_MEMBER_TEMPLATE_FUNC_OVERLOAD_DISCRIMINATED_SUPPORT
137 template< typename_param_k S1
>
138 class_type
& operator =(S1
const& rhs
) { return operator =(c_strptr(rhs
)); }
141 /// Equivalent to push()
142 class_type
& operator /=(const_pointer rhs
) { return push(rhs
); }
143 /// Equivalent to push()
144 class_type
& operator /=(class_type rhs
) { return push(rhs
); }
145 /// Equivalent to push()
146 #ifdef EXTL_MEMBER_TEMPLATE_FUNC_OVERLOAD_DISCRIMINATED_SUPPORT
147 template< typename_param_k S1
>
148 class_type
& operator /=(S1
const& rhs
) { return push(c_strptr(rhs
)); }
151 bool_type
operator ==(const_pointer rhs
) const { return equal(rhs
); }
152 bool_type
operator ==(class_type
const& rhs
) const { return equal(rhs
); }
153 #ifdef EXTL_MEMBER_TEMPLATE_FUNC_OVERLOAD_DISCRIMINATED_SUPPORT
154 template< typename_param_k S1
>
155 bool_type
operator ==(S1
const& rhs
) { return equal(c_strptr(rhs
)); }
162 /// Returns the the pointer the storage of the path
163 pointer
data() { return m_path
.data(); }
164 /// Returns the the pointer the storage of the path
165 const_pointer
data() const { return m_path
.data(); }
166 /// Returns the c-style string type of the path
167 const_pointer
c_str() const { return m_path
.c_str(); }
168 /// Returns the length of the path
169 size_type
length() const { return m_path
.length(); }
170 /// Returns the length of the path
171 size_type
size() const { return length(); }
172 /// Returns \c true if the path is empty
173 bool_type
is_empty() const { return m_path
.is_empty(); }
174 /// Returns \c true if the path is empty
175 bool_type
empty() const { return is_empty(); }
177 /// The maximum length of path
178 static size_type
max_length() { return path_traits_type::max_length(); }
179 /// The maximum length of path
180 static size_type
max_size() { return max_length(); }
181 /// Returns a path separator
182 static char_type
path_sep() { return path_traits_type::path_sep(); }
183 /// Returns a path name separator
184 static char_type
path_name_sep() { return path_traits_type::path_name_sep(); }
185 /// Returns the wildcard pattern that represents all possible matches
186 static const_pointer
pattern_all() { return path_traits_type::pattern_all(); }
188 /// Returns \c true if the path represents an existing file system entry
189 bool_type
exists() const { return filesystem_traits_type::file_exists(c_str()); }
190 /// Returns \c true if the path is \c "." or \c ".."
191 bool_type
is_dots() const { return path_traits_type::is_dots(c_str()); }
192 /// Returns \c true if the path is is \c "\\\\..."
193 bool_type
is_unc_path() const { return path_traits_type::is_unc_path(c_str()); }
194 /// Returns \c true if the path is is \c "\\\\" + '\\0'
195 bool_type
is_unc_root() const { return path_traits_type::is_unc_root(c_str()); }
196 /// Returns \c true if the path is rooted
197 bool_type
is_rooted_drive() const { return path_traits_type::is_rooted_drive(c_str()); }
198 /// Returns \c true if the path is absolute
199 bool_type
is_absolute_path() const { return path_traits_type::is_absolute_path(c_str()); }
201 /// Returns \c true if the path has trailing path name separator
202 bool_type
has_sep_end() const { return path_traits_type::has_sep_end(c_str()); }
203 /// Returns \c true if the path has rooted drive
204 bool_type
has_rooted_drive() const { return path_traits_type::has_rooted_drive(c_str()); }
206 /*!\brief Returns the file name of the path
208 * e.g. "C:\\dir\\file.txt" return "file.txt"
209 * e.g. "C:\\dir" return "dir"
210 * e.g. "C:\\dir\\" return ""
212 const_pointer
get_file_name() const;
214 /// Returns the extensible name of the path
215 const_pointer
get_ext_name() const;
217 /// Returns the title name of the path
218 const_pointer
get_title_name() const;
224 /// Appends a path name separator if one does not exist
225 class_type
& push_sep();
226 /// \brief Removes the path name separator from the end of the path, if it has it
227 /// \note Does not trim the separator character from the root designator
228 class_type
& pop_sep();
231 /// Removes the last path element from the path
232 class_type
& pop(bool_type is_pop_sep
= e_true_v
);
233 /// Appends the contents of \c rhs to the path
234 class_type
& push(const_pointer rhs
, bool_type is_push_sep
= e_false_v
);
235 /// Appends the contents of \c rhs to the path
236 class_type
& push(class_type
const& rhs
, bool_type is_push_sep
= e_false_v
);
237 #ifdef EXTL_MEMBER_TEMPLATE_FUNC_OVERLOAD_DISCRIMINATED_SUPPORT
238 /// Appends the contents of \c rhs to the path
239 template< typename_param_k S1
>
240 class_type
& push(S1
const& rhs
, bool_type is_push_sep
= e_false_v
) { push(c_strptr(rhs
), is_push_sep
); }
244 /// Removes the extensible name from the path
245 class_type
& pop_ext_name(bool_type is_pop_dot
= e_true_v
);
246 /// Appends an extensible name
247 class_type
& push_ext_name(const_pointer rhs
);
248 /// Appends an extensible name
249 class_type
& push_ext_name(class_type
const& rhs
);
250 #ifdef EXTL_MEMBER_TEMPLATE_FUNC_OVERLOAD_DISCRIMINATED_SUPPORT
251 /// Appends an extensible name
252 template< typename_param_k S1
>
253 class_type
& push_ext_name(S
const& rhs
) { push_ext_name(c_strptr(rhs
)); }
256 /// Makes a relative path
257 class_type
& make_relative_path();
258 /// Makes a absolute path
259 class_type
& make_absolute_path();
260 /// Makes a current directory
261 class_type
& make_current_directory();
264 /// Clears all contents
265 void clear() { m_path
.clear(); }
266 /// Swaps the contents
267 class_type
& swap(class_type
& other
) { m_path
.swap(other
.m_path
); return *this; }
273 /// Return \c true if this->c_str() == rhs (case-insensitive)
274 bool_type
equal(const_pointer rhs
) const { return 0 == m_path
.compare_nocase(rhs
); }
275 /// Return \c true if this->c_str() == rhs (case-insensitive)
276 bool_type
equal(string_type
const& rhs
) const { return 0 == m_path
.compare_nocase(rhs
); }
277 /// Return \c true if this->c_str() == rhs (case-insensitive)
278 bool_type
equal(class_type
const& rhs
) const { return equal(rhs
.m_path
); }
279 #ifdef EXTL_MEMBER_TEMPLATE_FUNC_OVERLOAD_DISCRIMINATED_SUPPORT
280 /// Return \c true if this->c_str() == rhs (case-insensitive)
281 template< typename_param_k S1
>
282 bool_type
equal(S1
const& rhs
) const { return equal(c_strptr(rhs
)); }
290 static class_type
make_path(const_pointer path
) { return class_type(path
); }
291 #ifdef EXTL_MEMBER_TEMPLATE_FUNC_OVERLOAD_DISCRIMINATED_SUPPORT
293 template< typename_param_k S1
>
294 static class_type
make_path(S1
const& path
) { return class_type(c_strptr(path
)); }
301 /// Returns reference at the given index
302 reference
operator[](size_type index
)
304 return const_cast<reference
>(static_cast<class_type
const&>(*this).operator[](index
));
306 /// Returns const reference at the given index
307 const_reference
operator[](size_type index
) const
309 EXTL_ASSERT(index
< length());
310 return m_path
[index
];
312 /// Returns reference at the given index and throws index_error() if index >= length()
313 reference
at(size_type index
)
315 return const_cast<reference
>(static_cast<class_type
const&>(*this).at(index
));
317 /// Returns const reference at the given index and throws index_error() if index >= length()
318 const_reference
at(size_type index
) const
320 EXTL_ASSERT(index
< length());
321 EXTL_ASSERT_THROW(index
< length(), index_error("out of range"));
322 return m_path
[index
];
326 /// \name Path entry iterator
329 const_entry_iterator
entry_begin(enum_flag_type flag
= path_entry_type::en_enum_all
) const
331 return const_entry_iterator(c_str(), flag
);
333 const_entry_iterator
entry_end() const
335 return const_entry_iterator();
337 const_reverse_entry_iterator
entry_rbegin(enum_flag_type flag
= path_entry_type::en_enum_all_rev
) const
339 return const_reverse_entry_iterator(c_str(), flag
);
341 const_reverse_entry_iterator
entry_rend() const
343 return const_reverse_entry_iterator();
353 /* ///////////////////////////////////////////////////////////////////////
357 /* Template declaration */
358 #ifdef EXTL_BASIC_PATH_TEMPLATE_DECL
359 # undef EXTL_BASIC_PATH_TEMPLATE_DECL
362 #define EXTL_BASIC_PATH_TEMPLATE_DECL template< typename_param_k C \
363 , typename_param_k S \
364 , typename_param_k T \
367 /* Class qualification */
368 #ifdef EXTL_BASIC_PATH_QUAL
369 # undef EXTL_BASIC_PATH_QUAL
372 #define EXTL_BASIC_PATH_QUAL basic_path<C, S, T>
374 /* Class qualification */
375 #ifdef EXTL_BASIC_PATH_RET_QUAL
376 # undef EXTL_BASIC_PATH_RET_QUAL
379 #define EXTL_BASIC_PATH_RET_QUAL(ret_type) \
380 typename_type_ret_k EXTL_BASIC_PATH_QUAL::ret_type \
383 /* ///////////////////////////////////////////////////////////////////////
386 EXTL_BASIC_PATH_TEMPLATE_DECL
387 inline EXTL_BASIC_PATH_RET_QUAL(class_type
&)::push_sep()
389 EXTL_ASSERT(NULL
!= data());
391 /* Maybe path_name_sep() is '\\' or '/',
392 * so ensure_push_back(path_name_sep()) isn't used.
394 if(!path_traits_type::is_path_name_sep(*--m_path
.end()))
395 m_path
.push_back(path_traits_type::path_name_sep());
399 EXTL_BASIC_PATH_TEMPLATE_DECL
400 inline EXTL_BASIC_PATH_RET_QUAL(class_type
&)::pop_sep()
402 EXTL_ASSERT(NULL
!= data());
404 if(is_rooted_drive()) return *this;
405 if(is_unc_root()) return *this;
407 /* Maybe path_name_sep() is '\\' or '/',
408 * so ensure_pop_back(path_name_sep()) isn't used.
410 if(path_traits_type::is_path_name_sep(*--m_path
.end()))
416 EXTL_BASIC_PATH_TEMPLATE_DECL
417 inline EXTL_BASIC_PATH_RET_QUAL(const_pointer
)::get_file_name() const
419 size_type pos
= path_traits_type::rfind_sep(m_path
.c_str(), m_path
.size());
421 if(string_type::fof() != pos
)
423 EXTL_ASSERT(pos
<= length());
424 return m_path
.c_str() + pos
+ 1;
426 else return string_traits_type::empty();
428 EXTL_BASIC_PATH_TEMPLATE_DECL
429 inline EXTL_BASIC_PATH_RET_QUAL(const_pointer
)::get_ext_name() const
431 size_type pos
= m_path
.rfind(char_type('.'));
432 if(string_type::fof() != pos
)
434 EXTL_ASSERT(pos
<= length());
435 return m_path
.c_str() + pos
+ 1;
437 else return string_traits_type::empty();
440 EXTL_BASIC_PATH_TEMPLATE_DECL
441 inline EXTL_BASIC_PATH_RET_QUAL(const_pointer
)::get_title_name() const
443 string_type
s(get_file_name());
444 if(s
.is_empty()) return string_traits_type::empty();
446 size_type pos
= s
.rfind(char_type('.'));
447 if(string_type::fof() != pos
) s
.resize(pos
);
451 EXTL_BASIC_PATH_TEMPLATE_DECL
452 inline EXTL_BASIC_PATH_RET_QUAL(class_type
&)::push(const_pointer rhs
, bool_type is_push_sep
)
454 EXTL_ASSERT(NULL
!= rhs
);
455 if (NULL
== rhs
) return *this;
456 if (string_traits_type::is_empty(rhs
)) return *this;
457 if (path_traits_type::has_rooted_drive(rhs
)) m_path
.assign(rhs
);
460 if (!is_empty()) push_sep();
463 if (is_push_sep
) push_sep();
466 // The function isn't forwarded to push(const_pointer, bool_type) for the efficiency of string operation
467 EXTL_BASIC_PATH_TEMPLATE_DECL
468 inline EXTL_BASIC_PATH_RET_QUAL(class_type
&)::push(class_type
const& rhs
, bool_type is_push_sep
)
470 EXTL_ASSERT(!rhs
.is_empty());
471 if (rhs
.is_empty()) return *this;
472 if (rhs
.has_rooted_drive()) m_path
.assign(rhs
.m_path
);
475 if (!is_empty()) push_sep();
476 m_path
.append(rhs
.m_path
);
478 if (is_push_sep
) push_sep();
482 EXTL_BASIC_PATH_TEMPLATE_DECL
483 inline EXTL_BASIC_PATH_RET_QUAL(class_type
&)::pop(bool_type is_pop_sep
)
485 if (is_rooted_drive()) return *this;
486 if (is_unc_root()) return *this;
488 size_type pos
= path_traits_type::rfind_sep(m_path
.c_str(), m_path
.size());
489 if (string_type::fof() != pos
)
491 EXTL_ASSERT(pos
<= length());
493 if (!is_pop_sep
) m_path
.resize(pos
+ 1);
494 else if (has_rooted_drive() && pos
< 3) // Cannot remove '\\' for "C:\\dir"
495 m_path
.resize(pos
+ 1);
496 else m_path
.resize(pos
);
501 EXTL_BASIC_PATH_TEMPLATE_DECL
502 inline EXTL_BASIC_PATH_RET_QUAL(class_type
&)::push_ext_name(const_pointer rhs
)
504 EXTL_ASSERT(NULL
!= rhs
);
505 if (NULL
== rhs
) return *this;
506 if (string_traits_type::is_empty(rhs
)) return *this;
507 if (path_traits_type::is_path_name_sep(*--m_path
.end())) return *this; // for "C:dir\\"
508 EXTL_ASSERT(!path_traits_type::has_rooted_drive(rhs
));
510 m_path
.ensure_push_back(char_type('.'));
515 // The function isn't forwarded to push_ext_name(const_pointer) for the efficiency of string operation
516 EXTL_BASIC_PATH_TEMPLATE_DECL
517 inline EXTL_BASIC_PATH_RET_QUAL(class_type
&)::push_ext_name(class_type
const& rhs
)
519 EXTL_ASSERT(!rhs
.is_empty());
520 if (rhs
.is_empty()) return *this;
521 if (path_traits_type::is_path_name_sep(*--m_path
.end())) return *this; // for "C:dir\\"
522 EXTL_ASSERT(!rhs
.has_rooted_drive());
524 m_path
.ensure_push_back(char_type('.'));
525 m_path
.append(rhs
.m_path
);
530 EXTL_BASIC_PATH_TEMPLATE_DECL
531 inline EXTL_BASIC_PATH_RET_QUAL(class_type
&)::pop_ext_name(bool_type is_pop_dot
)
533 if (is_rooted_drive()) return *this;
534 if (is_unc_root()) return *this;
536 size_type pos
= m_path
.rfind(char_type('.'));
537 if (string_type::fof() != pos
)
539 EXTL_ASSERT(pos
<= length());
541 if (!is_pop_dot
) m_path
.resize(pos
+ 1);
542 else m_path
.resize(pos
);
548 EXTL_BASIC_PATH_TEMPLATE_DECL
549 inline EXTL_BASIC_PATH_RET_QUAL(class_type
&)::make_relative_path()
551 char_type buffer
[path_traits_type::en_max_size
];
552 size_type n
= filesystem_traits_type::get_relative_path(c_str(), size(), buffer
, path_traits_type::en_max_size
);
553 m_path
.assign(buffer
, n
);
556 EXTL_BASIC_PATH_TEMPLATE_DECL
557 inline EXTL_BASIC_PATH_RET_QUAL(class_type
&)::make_absolute_path()
559 char_type buffer
[path_traits_type::en_max_size
];
560 size_type n
= filesystem_traits_type::get_absolute_path(c_str(), size(), buffer
, path_traits_type::en_max_size
);
561 m_path
.assign(buffer
, n
);
564 EXTL_BASIC_PATH_TEMPLATE_DECL
565 inline EXTL_BASIC_PATH_RET_QUAL(class_type
&)::make_current_directory()
567 char_type buffer
[path_traits_type::en_max_size
];
568 size_type n
= filesystem_traits_type::get_current_directory(buffer
, path_traits_type::en_max_size
);
569 m_path
.assign(buffer
, n
);
573 /* /////////////////////////////////////////////////////////////////////////
576 EXTL_BASIC_PATH_TEMPLATE_DECL
577 EXTL_INLINE
void swap(EXTL_BASIC_PATH_QUAL
&lhs
, EXTL_BASIC_PATH_QUAL
&rhs
)
581 /* /////////////////////////////////////////////////////////////////////////
584 EXTL_BASIC_PATH_TEMPLATE_DECL
585 EXTL_INLINE typename_type_ret_k
EXTL_BASIC_PATH_QUAL::
586 size_type
c_strlen(EXTL_BASIC_PATH_QUAL
const& p
)
588 return EXTL_NS(c_strlen
)(p
.c_str());
591 EXTL_BASIC_PATH_TEMPLATE_DECL
592 EXTL_INLINE typename_type_ret_k
EXTL_BASIC_PATH_QUAL::
593 const_pointer
c_strptr(EXTL_BASIC_PATH_QUAL
const& p
)
598 EXTL_BASIC_PATH_TEMPLATE_DECL
599 EXTL_INLINE typename_type_ret_k
EXTL_BASIC_PATH_QUAL::
600 const_pointer
get_ptr(EXTL_BASIC_PATH_QUAL
const& p
)
605 template< typename_param_k St
610 EXTL_INLINE St
& operator<<(St
& s
, EXTL_BASIC_PATH_QUAL
const& p
)
612 return s
<< p
.c_str();
614 /* /////////////////////////////////////////////////////////////////////////
618 typedef basic_path
< e_char_t
619 , filesystem_traits
<e_char_t
>::stack_path_string_type
620 , filesystem_traits
<e_char_t
>
623 typedef basic_path
< e_wchar_t
624 , filesystem_traits
<e_wchar_t
>::stack_path_string_type
625 , filesystem_traits
<e_wchar_t
>
628 typedef basic_path
< e_tchar_t
629 , filesystem_traits
<e_tchar_t
>::stack_path_string_type
630 , filesystem_traits
<e_tchar_t
>
632 /* //////////////////////////////////////////////////////////////////// */
633 #undef EXTL_BASIC_PATH_TEMPLATE_DECL
634 #undef EXTL_BASIC_PATH_QUAL
635 #undef EXTL_BASIC_PATH_RET_QUAL
637 /* ///////////////////////////////////////////////////////////////////////
640 #ifdef EXTL_PATH_TEST_ENABLE
641 # include "unit_test/path_test.h"
644 /* ///////////////////////////////////////////////////////////////////////
645 * ::extl::platform::win namespace
647 EXTL_WIN_END_WHOLE_NAMESPACE
649 /* ///////////////////////////////////////////////////////////////////////
652 #if !defined(EXTL_NO_STL) && \
653 !defined(EXTL_NO_NAMESPACE)
654 /* ::std namespace */
655 EXTL_STD_BEGIN_NAMESPACE
657 template< typename_param_k C
661 EXTL_INLINE
void swap(EXTL_NS(EXTL_NS_PLATFORM(EXTL_NS_WIN(basic_path
)))<C
, S
, T
> const& lhs
,
662 EXTL_NS(EXTL_NS_PLATFORM(EXTL_NS_WIN(basic_path
)))<C
, S
, T
> const& rhs
)
666 /* ::std namespace */
667 EXTL_STD_END_NAMESPACE
670 /* //////////////////////////////////////////////////////////////////// */
671 #endif /* EXTL_PLATFORM_WIN_PATH_H */
672 /* //////////////////////////////////////////////////////////////////// */