os_path.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. #include "os_path.h"
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #ifdef _WIN32
  5. #include <windows.h>
  6. #endif
  7. #ifdef __linux
  8. #include <sys/stat.h>
  9. #include <unistd.h>
  10. #endif
  11. #include "PikaStdData_List.h"
  12. #include "PikaStdData_Tuple.h"
  13. #ifdef _WIN32
  14. #define PATH_SEPARATOR '\\'
  15. #define PATH_SEPARATOR_STRING "\\"
  16. #else
  17. #define PATH_SEPARATOR '/'
  18. #define PATH_SEPARATOR_STRING "/"
  19. #endif
  20. #define IS_PATH_SEP(ch) ((ch) == '/' || (ch) == '\\')
  21. char* os_path_abspath(PikaObj* self, char* path) {
  22. char* abs_path = NULL;
  23. #ifdef _WIN32
  24. DWORD size = GetFullPathNameA(path, 0, NULL, NULL);
  25. if (size == 0) {
  26. return NULL;
  27. }
  28. abs_path = (char*)malloc(size * sizeof(char));
  29. if (abs_path == NULL) {
  30. return NULL;
  31. }
  32. DWORD ret_size = GetFullPathNameA(path, size, abs_path, NULL);
  33. if (ret_size == 0 || ret_size > size) {
  34. free(abs_path);
  35. return NULL;
  36. }
  37. #else
  38. char* cwd = pika_platform_getcwd(NULL, 0);
  39. if (cwd == NULL) {
  40. return NULL;
  41. }
  42. abs_path = pika_platform_realpath(path, NULL);
  43. if (abs_path == NULL) {
  44. free(cwd);
  45. return NULL;
  46. }
  47. if (abs_path[0] != '/') {
  48. char* temp_path =
  49. (char*)malloc((strlen(cwd) + strlen(abs_path) + 2) * sizeof(char));
  50. if (temp_path == NULL) {
  51. free(cwd);
  52. free(abs_path);
  53. return NULL;
  54. }
  55. strcpy(temp_path, cwd);
  56. strcat(temp_path, "/");
  57. strcat(temp_path, abs_path);
  58. free(abs_path);
  59. abs_path = temp_path;
  60. }
  61. free(cwd);
  62. #endif
  63. char* res = obj_cacheStr(self, abs_path);
  64. free(abs_path);
  65. return res;
  66. }
  67. PIKA_BOOL os_path_exists(PikaObj* self, char* path) {
  68. #ifdef _WIN32
  69. DWORD attr = GetFileAttributesA((LPCWSTR)path);
  70. if (attr == INVALID_FILE_ATTRIBUTES) {
  71. return PIKA_FALSE;
  72. }
  73. return PIKA_TRUE;
  74. #elif defined(__linux)
  75. struct stat statbuf;
  76. if (stat(path, &statbuf) == -1) {
  77. return PIKA_FALSE;
  78. }
  79. return PIKA_TRUE;
  80. #else
  81. return pika_platform_path_exists(path);
  82. #endif
  83. }
  84. PIKA_BOOL os_path_isabs(PikaObj* self, char* path) {
  85. #ifdef _WIN32
  86. if (path[0] == '\\' || path[0] == '/') {
  87. return PIKA_TRUE;
  88. }
  89. if (strlen(path) > 1 && path[1] == ':') {
  90. return PIKA_TRUE;
  91. }
  92. return PIKA_FALSE;
  93. #else
  94. if (path[0] == '/') {
  95. return PIKA_TRUE;
  96. }
  97. return PIKA_FALSE;
  98. #endif
  99. }
  100. // Returns true if the given path is a directory, false otherwise.
  101. PIKA_BOOL os_path_isdir(PikaObj* self, char* path) {
  102. return pika_platform_path_isdir(path);
  103. }
  104. // Returns true if the given path is a regular file, false otherwise.
  105. PIKA_BOOL os_path_isfile(PikaObj* self, char* path) {
  106. return pika_platform_path_isfile(path);
  107. }
  108. char* os_path_join(PikaObj* self, PikaTuple* paths) {
  109. size_t total_len = 1; // Start with a single null terminator
  110. int num_paths = pikaTuple_getSize(paths);
  111. for (int i = 0; i < num_paths; i++) {
  112. const char* path = pikaTuple_getStr(paths, i);
  113. total_len += strlen(path);
  114. if (i < num_paths - 1) {
  115. if (!IS_PATH_SEP(path[strlen(path) - 1])) {
  116. total_len++;
  117. }
  118. }
  119. }
  120. char* result = (char*)malloc(total_len);
  121. if (!result) {
  122. return NULL;
  123. }
  124. result[0] = '\0';
  125. for (int i = 0; i < num_paths; i++) {
  126. const char* path = pikaTuple_getStr(paths, i);
  127. if (!path || !path[0]) {
  128. continue;
  129. }
  130. if (i == 0) {
  131. // First component
  132. strncat(result, path, total_len);
  133. } else {
  134. // Subsequent components
  135. if (!IS_PATH_SEP(result[strlen(result) - 1])) {
  136. strncat(result, PATH_SEPARATOR_STRING, total_len);
  137. }
  138. strncat(result, path, total_len);
  139. }
  140. }
  141. char* res = obj_cacheStr(self, result);
  142. free(result);
  143. return res;
  144. }
  145. char* os_path_basename(PikaObj* self, char* path) {
  146. char* sep_pos = strrchr(path, PATH_SEPARATOR);
  147. if (sep_pos == NULL) {
  148. return obj_cacheStr(self, path);
  149. } else {
  150. return obj_cacheStr(self, sep_pos + 1);
  151. }
  152. }
  153. char* os_path_dirname(PikaObj* self, char* path) {
  154. char* sep_pos = strrchr(path, PATH_SEPARATOR);
  155. if (sep_pos == NULL) {
  156. return obj_cacheStr(self, ".");
  157. } else if (sep_pos == path) {
  158. return obj_cacheStr(self, PATH_SEPARATOR_STRING);
  159. } else {
  160. int dirname_len = sep_pos - path;
  161. char* dirname = malloc(dirname_len + 1);
  162. memcpy(dirname, path, dirname_len);
  163. dirname[dirname_len] = '\0';
  164. char* res = obj_cacheStr(self, dirname);
  165. free(dirname);
  166. return res;
  167. }
  168. }
  169. int _os_path_split(char* path, char** folder, char** file) {
  170. if (path == NULL || folder == NULL || file == NULL) {
  171. return -1;
  172. }
  173. char* p = strrchr(path, PATH_SEPARATOR);
  174. if (p) {
  175. size_t idx = p - path;
  176. *folder = pika_platform_malloc(idx + 2);
  177. if (*folder == NULL) {
  178. return -1;
  179. }
  180. strncpy(*folder, path, idx + 1);
  181. (*folder)[idx] = '\0';
  182. *file = pika_platform_strdup(p + 1);
  183. if (*file == NULL) {
  184. pika_platform_free(*folder);
  185. *folder = NULL;
  186. return -1;
  187. }
  188. return 0;
  189. } else {
  190. *folder = pika_platform_strdup(path);
  191. if (*folder == NULL) {
  192. return -1;
  193. }
  194. *file = pika_platform_strdup("");
  195. if (*file == NULL) {
  196. pika_platform_free(*folder);
  197. *folder = NULL;
  198. return -1;
  199. }
  200. return 0;
  201. }
  202. }
  203. int _os_path_splitext(char* path, char** file, char** ext) {
  204. char* p = strrchr(path, '.');
  205. if (p) {
  206. size_t idx = p - path;
  207. *file = malloc(idx + 1);
  208. if (!(*file)) {
  209. return -1;
  210. }
  211. strncpy(*file, path, idx);
  212. (*file)[idx] = '\0';
  213. *ext = pika_platform_strdup(p);
  214. if (!(*ext)) {
  215. pika_platform_free(*file);
  216. *file = NULL;
  217. return -1;
  218. }
  219. return 0;
  220. } else {
  221. *file = pika_platform_strdup(path);
  222. if (!(*file)) {
  223. return -1;
  224. }
  225. *ext = pika_platform_strdup("");
  226. if (!(*ext)) {
  227. free(*file);
  228. *file = NULL;
  229. return -1;
  230. }
  231. return 0;
  232. }
  233. }
  234. PikaObj* os_path_split(PikaObj* self, char* path) {
  235. char* folder = NULL;
  236. char* file = NULL;
  237. PikaObj* tuple = NULL;
  238. if (0 != _os_path_split(path, &folder, &file)) {
  239. goto __exit;
  240. }
  241. tuple = New_pikaTupleFromVarArgs(arg_newStr(folder), arg_newStr(file));
  242. pika_platform_free(folder);
  243. pika_platform_free(file);
  244. return tuple;
  245. __exit:
  246. if (tuple) {
  247. obj_deinit(tuple);
  248. }
  249. if (folder) {
  250. pika_platform_free(folder);
  251. }
  252. if (file) {
  253. pika_platform_free(file);
  254. }
  255. return NULL;
  256. }
  257. PikaObj* os_path_splitext(PikaObj* self, char* path) {
  258. char* file = NULL;
  259. char* ext = NULL;
  260. PikaObj* tuple = NULL;
  261. Arg* aFile = NULL;
  262. Arg* aExt = NULL;
  263. if (0 != _os_path_splitext(path, &file, &ext)) {
  264. goto __exit;
  265. }
  266. tuple = newNormalObj(New_PikaStdData_Tuple);
  267. PikaStdData_Tuple___init__(tuple);
  268. aFile = arg_newStr(file);
  269. aExt = arg_newStr(ext);
  270. PikaStdData_List_append(tuple, aFile);
  271. PikaStdData_List_append(tuple, aExt);
  272. arg_deinit(aFile);
  273. arg_deinit(aExt);
  274. free(file);
  275. free(ext);
  276. return tuple;
  277. __exit:
  278. if (aFile) {
  279. arg_deinit(aFile);
  280. }
  281. if (aExt) {
  282. arg_deinit(aExt);
  283. }
  284. if (tuple) {
  285. obj_deinit(tuple);
  286. }
  287. if (file) {
  288. pika_platform_free(file);
  289. }
  290. if (ext) {
  291. pika_platform_free(ext);
  292. }
  293. return NULL;
  294. }