path.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*
  2. * Copyright (c) 2012-2014 Daniele Bartolini and individual contributors.
  3. * License: https://github.com/taylor001/crown/blob/master/LICENSE
  4. */
  5. #include "path.h"
  6. #include <ctype.h> // isalpha
  7. namespace crown
  8. {
  9. namespace path
  10. {
  11. bool is_valid_segment(const char* segment)
  12. {
  13. CE_ASSERT(segment != NULL, "Segment must be != NULL");
  14. size_t segment_len = strlen(segment);
  15. // Empty segment is not valid
  16. if (segment_len == 0)
  17. {
  18. return false;
  19. }
  20. // Segments containing only '.' are non valid
  21. if (segment_len == 1 && segment[0] == '.')
  22. {
  23. return false;
  24. }
  25. // Segments containing only ".." are not valid
  26. if (segment_len == 2 && segment[0] == '.' && segment[1] == '.')
  27. {
  28. return false;
  29. }
  30. // The segment does not have to contain any forward slashes ('/')
  31. // nor back slashes ('\'), nor colon signs (':')
  32. for (size_t i = 0; i < segment_len; i++)
  33. {
  34. if (segment[i] == '/' ||
  35. segment[i] == '\\' ||
  36. segment[i] == ':')
  37. {
  38. return false;
  39. }
  40. }
  41. return true;
  42. }
  43. /// Returns whether the path is valid.
  44. /// @note
  45. /// The rules for valid paths are as follows:
  46. /// a) The empty string is not valid.
  47. /// b) If the path is absolute, it mustn't contain any leading character.
  48. bool is_valid_path(const char* path)
  49. {
  50. (void)path;
  51. // size_t path_len = strlen(path);
  52. // if (pathLen == 0)
  53. // {
  54. // return false;
  55. // }
  56. // if (is_root_path(path))
  57. // {
  58. // return true;
  59. // }
  60. // Array<Str> segmentList;
  61. // if (!get_segments(Str(path), segmentList))
  62. // {
  63. // return false;
  64. // }
  65. // size_t i = 0;
  66. // if (IsAbsolutePath(path) && path[0] != '/')
  67. // {
  68. // i = 1;
  69. // }
  70. // for (; i < segmentList.GetSize(); i++)
  71. // {
  72. // if (!IsValidSegment(segmentList[i].c_str()))
  73. // {
  74. // return false;
  75. // }
  76. // }
  77. return true;
  78. }
  79. bool is_absolute_path(const char* path)
  80. {
  81. CE_ASSERT(path != NULL, "Path must be != NULL");
  82. #if CROWN_PLATFORM_POSIX
  83. return strlen(path) > 0 && path[0] == '/';
  84. #elif CROWN_PLATFORM_WINDOWS
  85. return strlen(path) > 2 && isalpha(path[0]) && path[1] == ':' && path[2] == '\\';
  86. #endif
  87. }
  88. bool is_root_path(const char* path)
  89. {
  90. CE_ASSERT(path != NULL, "Path must be != NULL");
  91. #if CROWN_PLATFORM_POSIX
  92. return is_absolute_path(path) && strlen(path) == 1;
  93. #elif CROWN_PLATFORM_WINDOWS
  94. return is_absolute_path(path) && strlen(path) == 3;
  95. #endif
  96. }
  97. /// Returns the pathname of the path.
  98. /// @note
  99. /// e.g. "/home/project/texture.tga" -> "/home/project"
  100. /// e.g. "/home/project" -> "/home"
  101. /// e.g. "/home" -> "/"
  102. /// e.g. "home" -> ""
  103. ///
  104. /// The @a path must be valid.
  105. void pathname(const char* path, char* str, size_t len)
  106. {
  107. CE_ASSERT(path != NULL, "Path must be != NULL");
  108. CE_ASSERT(str != NULL, "Str must be != NULL");
  109. const char* last_separator = find_last(path, '/');
  110. if (last_separator == end(path))
  111. {
  112. strncpy(str, "", len);
  113. }
  114. else
  115. {
  116. substring(begin(path), last_separator, str, len);
  117. }
  118. }
  119. /// Returns the filename of the path.
  120. /// @note
  121. /// e.g. "/home/project/texture.tga" -> "texture.tga"
  122. /// e.g. "/home/project/texture" -> "texture"
  123. /// e.g. "/home -> "home"
  124. /// e.g. "/" -> ""
  125. ///
  126. /// The @a path must be valid.
  127. void filename(const char* path, char* str, size_t len)
  128. {
  129. CE_ASSERT(path != NULL, "Path must be != NULL");
  130. CE_ASSERT(str != NULL, "Str must be != NULL");
  131. const char* last_separator = find_last(path, '/');
  132. if (last_separator == end(path))
  133. {
  134. strncpy(str, "", len);
  135. }
  136. else
  137. {
  138. substring(last_separator + 1, end(path), str, len);
  139. }
  140. }
  141. /// Returns the basename of the path.
  142. /// @note
  143. /// e.g. "/home/project/texture.tga" -> "texture"
  144. /// e.g. "/home/project" -> "project"
  145. /// e.g. "/" -> ""
  146. ///
  147. /// The @a path must be valid.
  148. void basename(const char* path, char* str, size_t len)
  149. {
  150. CE_ASSERT(path != NULL, "Path must be != NULL");
  151. CE_ASSERT(str != NULL, "Str must be != NULL");
  152. const char* last_separator = find_last(path, '/');
  153. const char* last_dot = find_last(path, '.');
  154. if (last_separator == end(path) && last_dot != end(path))
  155. {
  156. substring(begin(path), last_dot, str, len);
  157. }
  158. else if (last_separator != end(path) && last_dot == end(path))
  159. {
  160. substring(last_separator + 1, end(path), str, len);
  161. }
  162. else if (last_separator == end(path) && last_dot == end(path))
  163. {
  164. strncpy(str, path, len);
  165. }
  166. else
  167. {
  168. substring(last_separator + 1, last_dot, str, len);
  169. }
  170. }
  171. /// Returns the extension of the path.
  172. /// @note
  173. /// e.g. "/home/project/texture.tga" -> "tga"
  174. /// e.g. "/home/project.x/texture" -> ""
  175. ///
  176. /// The @a path must be valid.
  177. void extension(const char* path, char* str, size_t len)
  178. {
  179. CE_ASSERT(path != NULL, "Path must be != NULL");
  180. CE_ASSERT(str != NULL, "Str must be != NULL");
  181. const char* last_dot = find_last(path, '.');
  182. if (last_dot == end(path))
  183. {
  184. strncpy(str, "", len);
  185. }
  186. else
  187. {
  188. substring(last_dot + 1, end(path), str, len);
  189. }
  190. }
  191. /// Returns the filename without the extension.
  192. /// @note
  193. /// e.g. "/home/project/texture.tga" -> "/home/project/texture"
  194. /// e.g. "/home/project/texture" -> "/home/project/texture"
  195. ///
  196. /// The @a path must be valid.
  197. void filename_without_extension(const char* path, char* str, size_t len)
  198. {
  199. CE_ASSERT(path != NULL, "Path must be != NULL");
  200. CE_ASSERT(str != NULL, "Str must be != NULL");
  201. const char* last_dot = find_last(path, '.');
  202. substring(begin(path), last_dot, str, len);
  203. }
  204. /// Returns the segments contained in path.
  205. //bool segments(const char* path, Array<Str>& ret)
  206. //{
  207. // path.Split(os::PATH_SEPARATOR, ret);
  208. // if (ret.GetSize() > 0)
  209. // {
  210. // return true;
  211. // }
  212. // return false;
  213. //}
  214. /// Fills 'ret' with the same path but without the trailing directory separator.
  215. /// @note
  216. /// e.g. "/home/project/texture.tga/" -> "/home/project/texture.tga"
  217. /// e.g. "/home/project/texture.tga" -> "/home/project/texture.tga"
  218. ///
  219. /// The @a path must be valid.
  220. void strip_trailing_separator(const char* path, char* str, size_t len)
  221. {
  222. CE_ASSERT(path != NULL, "Path must be != NULL");
  223. CE_ASSERT(str != NULL, "Str must be != NULL");
  224. size_t path_len = strlen(path);
  225. if (path[path_len - 1] == '/')
  226. {
  227. substring(begin(path), end(path) - 2, str, len);
  228. }
  229. else
  230. {
  231. substring(begin(path), end(path), str, len);
  232. }
  233. }
  234. } // namespace path
  235. } // namespace crown