path.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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 "platform.h"
  7. #include "string_utils.h"
  8. #include <ctype.h> // isalpha
  9. namespace crown
  10. {
  11. namespace path
  12. {
  13. #if CROWN_PLATFORM_POSIX
  14. const char SEPARATOR = '/';
  15. #elif CROWN_PLATFORM_WINDOWS
  16. const char SEPARATOR = '\\';
  17. #endif // CROWN_PLATFORM_POSIX
  18. bool is_absolute_path(const char* path)
  19. {
  20. CE_ASSERT(path != NULL, "Path must be != NULL");
  21. #if CROWN_PLATFORM_POSIX
  22. return strlen(path) > 0 && path[0] == SEPARATOR;
  23. #elif CROWN_PLATFORM_WINDOWS
  24. return strlen(path) > 2 && isalpha(path[0]) && path[1] == ':' && path[2] == SEPARATOR;
  25. #endif
  26. }
  27. bool is_root_path(const char* path)
  28. {
  29. CE_ASSERT(path != NULL, "Path must be != NULL");
  30. #if CROWN_PLATFORM_POSIX
  31. return is_absolute_path(path) && strlen(path) == 1;
  32. #elif CROWN_PLATFORM_WINDOWS
  33. return is_absolute_path(path) && strlen(path) == 3;
  34. #endif
  35. }
  36. void join(const char* p1, const char* p2, DynamicString& path)
  37. {
  38. path += p1;
  39. path += SEPARATOR;
  40. path += p2;
  41. }
  42. const char* normalize_path(const char* path)
  43. {
  44. #if CROWN_PLATFORM_POSIX
  45. static char norm[1024];
  46. char* cur = norm;
  47. while ((*path) != '\0')
  48. {
  49. if ((*path) == '\\')
  50. {
  51. (*cur) = SEPARATOR;
  52. }
  53. else
  54. {
  55. (*cur) = (*path);
  56. }
  57. path++;
  58. cur++;
  59. }
  60. return norm;
  61. #elif CROWN_PLATFORM_WINDOWS
  62. static char norm[1024];
  63. for (uint32_t i = 0; i < strlen(path)+1; i++)
  64. {
  65. if (path[i] == '/')
  66. {
  67. norm[i] = SEPARATOR;
  68. }
  69. else
  70. {
  71. norm[i] = path[i];
  72. }
  73. }
  74. return norm;
  75. #endif
  76. }
  77. /// Returns the pathname of the path.
  78. /// @note
  79. /// e.g. "/home/project/texture.tga" -> "/home/project"
  80. /// e.g. "/home/project" -> "/home"
  81. /// e.g. "/home" -> "/"
  82. /// e.g. "home" -> ""
  83. ///
  84. /// The @a path must be valid.
  85. void pathname(const char* path, char* str, size_t len)
  86. {
  87. CE_ASSERT(path != NULL, "Path must be != NULL");
  88. CE_ASSERT(str != NULL, "Str must be != NULL");
  89. const char* last_separator = find_last(path, '/');
  90. if (last_separator == end(path))
  91. {
  92. strncpy(str, "", len);
  93. }
  94. else
  95. {
  96. substring(begin(path), last_separator, str, len);
  97. }
  98. }
  99. /// Returns the filename of the path.
  100. /// @note
  101. /// e.g. "/home/project/texture.tga" -> "texture.tga"
  102. /// e.g. "/home/project/texture" -> "texture"
  103. /// e.g. "/home -> "home"
  104. /// e.g. "/" -> ""
  105. ///
  106. /// The @a path must be valid.
  107. void filename(const char* path, char* str, size_t len)
  108. {
  109. CE_ASSERT(path != NULL, "Path must be != NULL");
  110. CE_ASSERT(str != NULL, "Str must be != NULL");
  111. const char* last_separator = find_last(path, '/');
  112. if (last_separator == end(path))
  113. {
  114. strncpy(str, "", len);
  115. }
  116. else
  117. {
  118. substring(last_separator + 1, end(path), str, len);
  119. }
  120. }
  121. /// Returns the basename of the path.
  122. /// @note
  123. /// e.g. "/home/project/texture.tga" -> "texture"
  124. /// e.g. "/home/project" -> "project"
  125. /// e.g. "/" -> ""
  126. ///
  127. /// The @a path must be valid.
  128. void basename(const char* path, char* str, size_t len)
  129. {
  130. CE_ASSERT(path != NULL, "Path must be != NULL");
  131. CE_ASSERT(str != NULL, "Str must be != NULL");
  132. const char* last_separator = find_last(path, '/');
  133. const char* last_dot = find_last(path, '.');
  134. if (last_separator == end(path) && last_dot != end(path))
  135. {
  136. substring(begin(path), last_dot, str, len);
  137. }
  138. else if (last_separator != end(path) && last_dot == end(path))
  139. {
  140. substring(last_separator + 1, end(path), str, len);
  141. }
  142. else if (last_separator == end(path) && last_dot == end(path))
  143. {
  144. strncpy(str, path, len);
  145. }
  146. else
  147. {
  148. substring(last_separator + 1, last_dot, str, len);
  149. }
  150. }
  151. /// Returns the extension of the path.
  152. /// @note
  153. /// e.g. "/home/project/texture.tga" -> "tga"
  154. /// e.g. "/home/project.x/texture" -> ""
  155. ///
  156. /// The @a path must be valid.
  157. void extension(const char* path, char* str, size_t len)
  158. {
  159. CE_ASSERT(path != NULL, "Path must be != NULL");
  160. CE_ASSERT(str != NULL, "Str must be != NULL");
  161. const char* last_dot = find_last(path, '.');
  162. if (last_dot == end(path))
  163. {
  164. strncpy(str, "", len);
  165. }
  166. else
  167. {
  168. substring(last_dot + 1, end(path), str, len);
  169. }
  170. }
  171. /// Returns the filename without the extension.
  172. /// @note
  173. /// e.g. "/home/project/texture.tga" -> "/home/project/texture"
  174. /// e.g. "/home/project/texture" -> "/home/project/texture"
  175. ///
  176. /// The @a path must be valid.
  177. void filename_without_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. substring(begin(path), last_dot, str, len);
  183. }
  184. /// Fills 'ret' with the same path but without the trailing directory separator.
  185. /// @note
  186. /// e.g. "/home/project/texture.tga/" -> "/home/project/texture.tga"
  187. /// e.g. "/home/project/texture.tga" -> "/home/project/texture.tga"
  188. ///
  189. /// The @a path must be valid.
  190. void strip_trailing_separator(const char* path, char* str, size_t len)
  191. {
  192. CE_ASSERT(path != NULL, "Path must be != NULL");
  193. CE_ASSERT(str != NULL, "Str must be != NULL");
  194. size_t path_len = strlen(path);
  195. if (path[path_len - 1] == '/')
  196. {
  197. substring(begin(path), end(path) - 2, str, len);
  198. }
  199. else
  200. {
  201. substring(begin(path), end(path), str, len);
  202. }
  203. }
  204. } // namespace path
  205. } // namespace crown