You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

306 lines
9.7 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: unixstl/filesystem/path_functions.hpp
  3. *
  4. * Purpose: Helper functions for file handling
  5. *
  6. * Created: 13th June 2006
  7. * Updated: 2nd April 2010
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 2006-2010, Matthew Wilson and Synesis Software
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions are met:
  16. *
  17. * - Redistributions of source code must retain the above copyright notice, this
  18. * list of conditions and the following disclaimer.
  19. * - Redistributions in binary form must reproduce the above copyright notice,
  20. * this list of conditions and the following disclaimer in the documentation
  21. * and/or other materials provided with the distribution.
  22. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  23. * any contributors may be used to endorse or promote products derived from
  24. * this software without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. * ////////////////////////////////////////////////////////////////////// */
  39. /** \file unixstl/filesystem/path_functions.hpp
  40. *
  41. * \brief [C++ only] Helper functions for (text) file handling
  42. * (\ref group__library__filesystem "File System" Library).
  43. */
  44. #ifndef UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_PATH_FUNCTIONS
  45. #define UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_PATH_FUNCTIONS
  46. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  47. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_PATH_FUNCTIONS_MAJOR 1
  48. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_PATH_FUNCTIONS_MINOR 1
  49. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_PATH_FUNCTIONS_REVISION 5
  50. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_PATH_FUNCTIONS_EDIT 12
  51. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  52. /* /////////////////////////////////////////////////////////////////////////
  53. * Includes
  54. */
  55. #ifndef UNIXSTL_INCL_UNIXSTL_H_UNIXSTL
  56. # include <unixstl/unixstl.h>
  57. #endif /* !UNIXSTL_INCL_UNIXSTL_H_UNIXSTL */
  58. #ifndef UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS
  59. # include <unixstl/filesystem/filesystem_traits.hpp>
  60. #endif /* !UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS */
  61. #ifndef UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_PATH
  62. # include <unixstl/filesystem/path.hpp>
  63. #endif /* !UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_PATH */
  64. #ifndef STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING
  65. # include <stlsoft/shims/access/string.hpp>
  66. #endif /* !STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING */
  67. #if defined(_WIN32) || \
  68. defined(_WIN64)
  69. # include <ctype.h>
  70. #endif /* Windows */
  71. #ifdef STLSOFT_UNITTEST
  72. #endif // STLSOFT_UNITTEST
  73. /* /////////////////////////////////////////////////////////////////////////
  74. * Namespace
  75. */
  76. #ifndef _UNIXSTL_NO_NAMESPACE
  77. # if defined(_STLSOFT_NO_NAMESPACE) || \
  78. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  79. /* There is no stlsoft namespace, so must define ::unixstl */
  80. namespace unixstl
  81. {
  82. # else
  83. /* Define stlsoft::unixstl_project */
  84. namespace stlsoft
  85. {
  86. namespace unixstl_project
  87. {
  88. # endif /* _STLSOFT_NO_NAMESPACE */
  89. #endif /* !_UNIXSTL_NO_NAMESPACE */
  90. /* /////////////////////////////////////////////////////////////////////////
  91. * Functions
  92. */
  93. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  94. template <ss_typename_param_k C>
  95. us_size_t path_squeeze_impl(
  96. C const* path
  97. , us_size_t pathLen
  98. , C* buffer
  99. , us_size_t cchBuffer
  100. )
  101. {
  102. typedef C char_t;
  103. typedef filesystem_traits<C> traits_t;
  104. typedef us_size_t size_t;
  105. if(NULL == buffer)
  106. {
  107. cchBuffer = pathLen + 1u;
  108. }
  109. else if(0 != cchBuffer)
  110. {
  111. basic_path<char_t> p(path, pathLen);
  112. char_t const* file_ptr = p.get_file();
  113. char_t const* path_ptr = p.c_str();
  114. const size_t fileLen = p.size() - (file_ptr - path_ptr);
  115. if(cchBuffer > pathLen)
  116. {
  117. // Room for all
  118. traits_t::char_copy(buffer, path_ptr, pathLen);
  119. buffer[pathLen] = '\0';
  120. cchBuffer = pathLen + 1u;
  121. }
  122. else
  123. {
  124. size_t rootLen;
  125. // Need to handle:
  126. //
  127. // 1. UNC
  128. // 2. drive
  129. // 3. rooted - begins with \ or /
  130. // 4. non-rooted
  131. if(p.is_rooted())
  132. {
  133. if(p.is_absolute())
  134. {
  135. if(traits_t::is_path_UNC(path_ptr))
  136. {
  137. // 1. UNC
  138. char_t const* p1 = traits_t::str_chr(path_ptr + 2, '\\');
  139. rootLen = 1 + static_cast<size_t>(p1 - path_ptr);
  140. }
  141. #if defined(_WIN32) || \
  142. defined(_WIN64)
  143. else if(isalpha(path_ptr[0]) &&
  144. ':' == path_ptr[1])
  145. {
  146. // 2. drive
  147. rootLen = 3;
  148. }
  149. #endif /* Windows */
  150. else
  151. {
  152. // 3. rooted - begins with \ or /
  153. rootLen = 1;
  154. }
  155. }
  156. else
  157. {
  158. // 3. rooted - begins with \ or /
  159. rootLen = 1;
  160. }
  161. }
  162. else
  163. {
  164. // 4. non-rooted
  165. rootLen = 0;
  166. }
  167. if(cchBuffer < 5 + 1)
  168. {
  169. traits_t::char_copy(buffer, file_ptr, cchBuffer - 1);
  170. buffer[cchBuffer - 1] = '\0';
  171. if(cchBuffer > fileLen)
  172. {
  173. cchBuffer = fileLen + 1;
  174. }
  175. }
  176. else if(cchBuffer < fileLen + 1)
  177. {
  178. // Squeezing just file+ext
  179. size_t leftLen = (cchBuffer - 3 - 1) / 2;
  180. size_t rightLen = (cchBuffer - 3 - 1) - leftLen;
  181. traits_t::char_copy(buffer, file_ptr, leftLen);
  182. buffer[leftLen + 0] = '.';
  183. buffer[leftLen + 1] = '.';
  184. buffer[leftLen + 2] = '.';
  185. traits_t::char_copy(buffer + leftLen + 3, file_ptr + (fileLen - rightLen), rightLen);
  186. buffer[leftLen + 3 + rightLen] = '\0';
  187. }
  188. else if(cchBuffer < rootLen + 3 + 1 + fileLen + 1)
  189. {
  190. // File (name + ext) only
  191. traits_t::char_copy(buffer, file_ptr, fileLen);
  192. buffer[fileLen] = '\0';
  193. if(cchBuffer > fileLen)
  194. {
  195. cchBuffer = fileLen + 1;
  196. }
  197. }
  198. else
  199. {
  200. UNIXSTL_ASSERT(cchBuffer < pathLen + 1);
  201. // Squeezing
  202. size_t rightLen = 1 + fileLen;
  203. size_t leftLen = (cchBuffer - 3 - 1) - rightLen;
  204. traits_t::char_copy(buffer, path_ptr, leftLen);
  205. buffer[leftLen + 0] = '.';
  206. buffer[leftLen + 1] = '.';
  207. buffer[leftLen + 2] = '.';
  208. traits_t::char_copy(buffer + leftLen + 3, file_ptr - 1, rightLen);
  209. buffer[leftLen + 3 + rightLen] = '\0';
  210. }
  211. }
  212. }
  213. return cchBuffer;
  214. }
  215. template<ss_typename_param_k S>
  216. us_size_t path_squeeze_impl2(S const& path, us_char_a_t* buffer, us_size_t cchBuffer)
  217. {
  218. return path_squeeze_impl(stlsoft_ns_qual(c_str_ptr_a)(path), stlsoft_ns_qual(c_str_len)(path), buffer, cchBuffer);
  219. }
  220. template<ss_typename_param_k S>
  221. us_size_t path_squeeze_impl2(S const& path, us_char_w_t* buffer, us_size_t cchBuffer)
  222. {
  223. return path_squeeze_impl(stlsoft_ns_qual(c_str_ptr_w)(path), stlsoft_ns_qual(c_str_len)(path), buffer, cchBuffer);
  224. }
  225. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  226. #if 0
  227. template <ss_typename_param_k C>
  228. us_size_t path_squeeze(C const* path, C* buffer, us_size_t cchBuffer)
  229. {
  230. typedef filesystem_traits<C> traits_t;
  231. return path_squeeze_impl(path, traits_t::str_len(path), buffer, cchBuffer);
  232. }
  233. #endif /* 0 */
  234. template< ss_typename_param_k S
  235. , ss_typename_param_k C
  236. >
  237. us_size_t path_squeeze(S const& path, C* buffer, us_size_t cchBuffer)
  238. {
  239. return path_squeeze_impl2(path, buffer, cchBuffer);
  240. }
  241. /* /////////////////////////////////////////////////////////////////////////
  242. * Unit-testing
  243. */
  244. #ifdef STLSOFT_UNITTEST
  245. # include "./unittest/path_functions_unittest_.h"
  246. #endif /* STLSOFT_UNITTEST */
  247. /* ////////////////////////////////////////////////////////////////////// */
  248. #ifndef _UNIXSTL_NO_NAMESPACE
  249. # if defined(_STLSOFT_NO_NAMESPACE) || \
  250. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  251. } // namespace unixstl
  252. # else
  253. } // namespace unixstl_project
  254. } // namespace stlsoft
  255. # endif /* _STLSOFT_NO_NAMESPACE */
  256. #endif /* !_UNIXSTL_NO_NAMESPACE */
  257. /* ////////////////////////////////////////////////////////////////////// */
  258. #endif /* !UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_PATH_FUNCTIONS */
  259. /* ///////////////////////////// end of file //////////////////////////// */