os_path.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. #include "os_path.h"
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #ifdef _WIN32
  5. #include <windows.h>
  6. #else
  7. #include <sys/stat.h>
  8. #include <unistd.h>
  9. #include "PikaStdData_List.h"
  10. #include "PikaStdData_Tuple.h"
  11. #endif
  12. #ifdef _WIN32
  13. #define PATH_SEPARATOR '\\'
  14. #define PATH_SEPARATOR_STRING "\\"
  15. #else
  16. #define PATH_SEPARATOR '/'
  17. #define PATH_SEPARATOR_STRING "/"
  18. #endif
  19. #define IS_PATH_SEP(ch) ((ch) == '/' || (ch) == '\\')
  20. // 返回指定路径的绝对路径
  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. // 获取绝对路径失败
  27. return NULL;
  28. }
  29. abs_path = (char*)malloc(size * sizeof(char));
  30. if (abs_path == NULL) {
  31. // 内存分配失败
  32. return NULL;
  33. }
  34. DWORD ret_size = GetFullPathNameA(path, size, abs_path, NULL);
  35. if (ret_size == 0 || ret_size > size) {
  36. // 获取绝对路径失败
  37. free(abs_path);
  38. return NULL;
  39. }
  40. #else
  41. char* cwd = getcwd(NULL, 0);
  42. if (cwd == NULL) {
  43. // 获取当前工作目录失败
  44. return NULL;
  45. }
  46. abs_path = realpath(path, NULL);
  47. if (abs_path == NULL) {
  48. // 获取绝对路径失败
  49. free(cwd);
  50. return NULL;
  51. }
  52. // 如果路径不是绝对路径,则将其转换为绝对路径
  53. if (abs_path[0] != '/') {
  54. char* temp_path =
  55. (char*)malloc((strlen(cwd) + strlen(abs_path) + 2) * sizeof(char));
  56. if (temp_path == NULL) {
  57. // 内存分配失败
  58. free(cwd);
  59. free(abs_path);
  60. return NULL;
  61. }
  62. strcpy(temp_path, cwd);
  63. strcat(temp_path, "/");
  64. strcat(temp_path, abs_path);
  65. free(abs_path);
  66. abs_path = temp_path;
  67. }
  68. free(cwd);
  69. #endif
  70. char* res = obj_cacheStr(self, abs_path);
  71. free(abs_path);
  72. return res;
  73. }
  74. // 判断指定路径是否存在
  75. PIKA_BOOL os_path_exists(PikaObj* self, char* path) {
  76. #ifdef _WIN32
  77. DWORD attr = GetFileAttributesA(path);
  78. if (attr == INVALID_FILE_ATTRIBUTES) {
  79. // 获取文件属性失败
  80. return PIKA_FALSE;
  81. }
  82. return PIKA_TRUE;
  83. #else
  84. struct stat statbuf;
  85. if (stat(path, &statbuf) == -1) {
  86. // 获取文件状态失败
  87. return PIKA_FALSE;
  88. }
  89. return PIKA_TRUE;
  90. #endif
  91. }
  92. // 判断指定路径是否为绝对路径
  93. PIKA_BOOL os_path_isabs(PikaObj* self, char* path) {
  94. #ifdef _WIN32
  95. if (path[0] == '\\' || path[0] == '/') {
  96. return PIKA_TRUE;
  97. }
  98. if (strlen(path) > 1 && path[1] == ':') {
  99. return PIKA_TRUE;
  100. }
  101. return PIKA_FALSE;
  102. #else
  103. if (path[0] == '/') {
  104. return PIKA_TRUE;
  105. }
  106. return PIKA_FALSE;
  107. #endif
  108. }
  109. // Returns true if the given path is a directory, false otherwise.
  110. PIKA_BOOL os_path_isdir(PikaObj* self, char* path) {
  111. PIKA_BOOL is_dir = PIKA_FALSE;
  112. #ifdef _WIN32
  113. DWORD attrs = GetFileAttributes(path);
  114. if (attrs != INVALID_FILE_ATTRIBUTES) {
  115. is_dir =
  116. (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0 ? PIKA_TRUE : PIKA_FALSE;
  117. }
  118. #else
  119. struct stat st;
  120. if (stat(path, &st) == 0) {
  121. is_dir = S_ISDIR(st.st_mode) ? PIKA_TRUE : PIKA_FALSE;
  122. }
  123. #endif
  124. return is_dir;
  125. }
  126. // Returns true if the given path is a regular file, false otherwise.
  127. PIKA_BOOL os_path_isfile(PikaObj* self, char* path) {
  128. PIKA_BOOL is_file = PIKA_FALSE;
  129. #ifdef _WIN32
  130. DWORD attrs = GetFileAttributes(path);
  131. if (attrs != INVALID_FILE_ATTRIBUTES) {
  132. is_file =
  133. (attrs & FILE_ATTRIBUTE_DIRECTORY) == 0 ? PIKA_TRUE : PIKA_FALSE;
  134. }
  135. #else
  136. struct stat st;
  137. if (stat(path, &st) == 0) {
  138. is_file = S_ISREG(st.st_mode) ? PIKA_TRUE : PIKA_FALSE;
  139. }
  140. #endif
  141. return is_file;
  142. }
  143. char* os_path_join(PikaObj* self, PikaTuple* paths) {
  144. size_t total_len = 1; // Start with a single null terminator
  145. int num_paths = pikaTuple_getSize(paths);
  146. for (int i = 0; i < num_paths; i++) {
  147. const char* path = pikaTuple_getStr(paths, i);
  148. total_len += strlen(path);
  149. if (i < num_paths - 1) {
  150. if (!IS_PATH_SEP(path[strlen(path) - 1])) {
  151. total_len++;
  152. }
  153. }
  154. }
  155. char* result = (char*)malloc(total_len);
  156. if (!result) {
  157. return NULL;
  158. }
  159. result[0] = '\0';
  160. for (int i = 0; i < num_paths; i++) {
  161. const char* path = pikaTuple_getStr(paths, i);
  162. if (!path || !path[0]) {
  163. continue;
  164. }
  165. if (i == 0) {
  166. // First component
  167. strncat(result, path, total_len);
  168. } else {
  169. // Subsequent components
  170. if (!IS_PATH_SEP(result[strlen(result) - 1])) {
  171. strncat(result, PATH_SEPARATOR_STRING, total_len);
  172. }
  173. strncat(result, path, total_len);
  174. }
  175. }
  176. char* res = obj_cacheStr(self, result);
  177. free(result);
  178. return res;
  179. }
  180. char* os_path_basename(PikaObj* self, char* path) {
  181. char* sep_pos = strrchr(path, PATH_SEPARATOR);
  182. if (sep_pos == NULL) {
  183. return obj_cacheStr(self, path);
  184. } else {
  185. return obj_cacheStr(self, sep_pos + 1);
  186. }
  187. }
  188. char* os_path_dirname(PikaObj* self, char* path) {
  189. char* sep_pos = strrchr(path, PATH_SEPARATOR);
  190. if (sep_pos == NULL) {
  191. return obj_cacheStr(self, ".");
  192. } else if (sep_pos == path) {
  193. return obj_cacheStr(self, PATH_SEPARATOR_STRING);
  194. } else {
  195. int dirname_len = sep_pos - path;
  196. char* dirname = malloc(dirname_len + 1);
  197. memcpy(dirname, path, dirname_len);
  198. dirname[dirname_len] = '\0';
  199. char* res = obj_cacheStr(self, dirname);
  200. free (dirname);
  201. return res;
  202. }
  203. }
  204. int _os_path_split(char* path, char** folder, char** file) {
  205. if (path == NULL || folder == NULL || file == NULL) {
  206. return -1;
  207. }
  208. char* p = strrchr(path, PATH_SEPARATOR);
  209. if (p) {
  210. /* 字符串最后一个路径分隔符的位置 */
  211. size_t idx = p - path;
  212. /* 获取最后一个路径分隔符之前的路径 */
  213. *folder = malloc(idx + 2);
  214. if (*folder == NULL) {
  215. return -1;
  216. }
  217. strncpy(*folder, path, idx + 1);
  218. (*folder)[idx] = '\0';
  219. /* 获取最后一个路径分隔符之后的文件名 */
  220. *file = strdup(p + 1);
  221. if (*file == NULL) {
  222. free(*folder);
  223. return -1;
  224. }
  225. return 0;
  226. } else {
  227. /* 如果路径没有分隔符,则返回路径本身和空字符串 */
  228. *folder = strdup(path);
  229. if (*folder == NULL) {
  230. return -1;
  231. }
  232. *file = strdup("");
  233. if (*file == NULL) {
  234. free(*folder);
  235. return -1;
  236. }
  237. return 0;
  238. }
  239. }
  240. int _os_path_splitext(char* path, char** file, char** ext) {
  241. char* p = strrchr(path, '.');
  242. if (p) {
  243. /* 字符串最后一个点的位置 */
  244. size_t idx = p - path;
  245. /* 获取点之前的路径 */
  246. *file = malloc(idx + 1);
  247. if (!(*file)) {
  248. /* 内存分配失败 */
  249. return -1;
  250. }
  251. strncpy(*file, path, idx);
  252. (*file)[idx] = '\0';
  253. /* 获取点之后的扩展名 */
  254. *ext = strdup(p);
  255. if (!(*ext)) {
  256. /* 内存分配失败 */
  257. free(*file);
  258. return -1;
  259. }
  260. return 0;
  261. } else {
  262. /* 如果没有扩展名,则返回路径本身和空字符串 */
  263. *file = strdup(path);
  264. if (!(*file)) {
  265. /* 内存分配失败 */
  266. return -1;
  267. }
  268. *ext = strdup("");
  269. if (!(*ext)) {
  270. /* 内存分配失败 */
  271. free(*file);
  272. return -1;
  273. }
  274. return 0;
  275. }
  276. }
  277. PikaObj* os_path_split(PikaObj* self, char* path) {
  278. char* folder = NULL;
  279. char* file = NULL;
  280. PikaObj* tuple = NULL;
  281. if (0 != _os_path_split(path, &folder, &file)) {
  282. goto __exit; // 发生错误,跳转到 __exit 处做资源回收
  283. }
  284. tuple = obj_newTuple(arg_newStr(folder), arg_newStr(file));
  285. free(folder);
  286. free(file);
  287. return tuple;
  288. __exit:
  289. if (tuple) {
  290. obj_deinit(tuple);
  291. }
  292. if (folder) {
  293. free(folder);
  294. }
  295. if (file) {
  296. free(file);
  297. }
  298. return NULL;
  299. }
  300. PikaObj* os_path_splitext(PikaObj* self, char* path) {
  301. char* file = NULL;
  302. char* ext = NULL;
  303. PikaObj* tuple = NULL;
  304. Arg* aFile = NULL;
  305. Arg* aExt = NULL;
  306. if (0 != _os_path_splitext(path, &file, &ext)) {
  307. goto __exit; // 发生错误,跳转到 __exit 处做资源回收
  308. }
  309. tuple = newNormalObj(New_PikaStdData_Tuple);
  310. PikaStdData_Tuple___init__(tuple);
  311. aFile = arg_newStr(file);
  312. aExt = arg_newStr(ext);
  313. PikaStdData_List_append(tuple, aFile);
  314. PikaStdData_List_append(tuple, aExt);
  315. arg_deinit(aFile);
  316. arg_deinit(aExt);
  317. free(file);
  318. free(ext);
  319. return tuple;
  320. __exit:
  321. if (aFile) {
  322. arg_deinit(aFile);
  323. }
  324. if (aExt) {
  325. arg_deinit(aExt);
  326. }
  327. if (tuple) {
  328. obj_deinit(tuple);
  329. }
  330. if (file) {
  331. free(file);
  332. }
  333. if (ext) {
  334. free(ext);
  335. }
  336. return NULL;
  337. }