diff options
author | 3gg <3gg@shellblade.net> | 2023-07-11 18:37:45 -0700 |
---|---|---|
committer | 3gg <3gg@shellblade.net> | 2023-07-11 18:38:04 -0700 |
commit | fc5886c75ab2626acbc0d7b3db475d17d2cbe01f (patch) | |
tree | 1f84aabf268a40ddc6b4f5deef2450fca2171f6e | |
parent | 2a016de1c2eb45fc5f9c8cebf6b3c726b01ec340 (diff) |
Add filesystem library.
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | filesystem/CMakeLists.txt | 11 | ||||
-rw-r--r-- | filesystem/include/filesystem.h | 19 | ||||
-rw-r--r-- | filesystem/src/filesystem.c | 92 |
4 files changed, 125 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 4695e06..498b771 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
@@ -3,9 +3,12 @@ cmake_minimum_required(VERSION 3.0) | |||
3 | project(clib) | 3 | project(clib) |
4 | 4 | ||
5 | add_subdirectory(cstring) | 5 | add_subdirectory(cstring) |
6 | add_subdirectory(error) | ||
7 | add_subdirectory(filesystem) | ||
6 | add_subdirectory(list) | 8 | add_subdirectory(list) |
7 | add_subdirectory(listpool) | 9 | add_subdirectory(listpool) |
8 | add_subdirectory(log) | 10 | add_subdirectory(log) |
9 | add_subdirectory(mempool) | 11 | add_subdirectory(mempool) |
12 | add_subdirectory(plugin) | ||
10 | add_subdirectory(random) | 13 | add_subdirectory(random) |
11 | add_subdirectory(timer) | 14 | add_subdirectory(timer) |
diff --git a/filesystem/CMakeLists.txt b/filesystem/CMakeLists.txt new file mode 100644 index 0000000..55430e6 --- /dev/null +++ b/filesystem/CMakeLists.txt | |||
@@ -0,0 +1,11 @@ | |||
1 | cmake_minimum_required(VERSION 3.0) | ||
2 | |||
3 | project(filesystem) | ||
4 | |||
5 | add_library(filesystem | ||
6 | src/filesystem.c) | ||
7 | |||
8 | target_include_directories(filesystem PUBLIC | ||
9 | include) | ||
10 | |||
11 | target_compile_options(filesystem PRIVATE -Wall -Wextra) | ||
diff --git a/filesystem/include/filesystem.h b/filesystem/include/filesystem.h new file mode 100644 index 0000000..62bd7f0 --- /dev/null +++ b/filesystem/include/filesystem.h | |||
@@ -0,0 +1,19 @@ | |||
1 | /* | ||
2 | * Various filesystem utilities. | ||
3 | */ | ||
4 | #pragma once | ||
5 | |||
6 | #include <stdbool.h> | ||
7 | #include <stddef.h> | ||
8 | #include <stdio.h> | ||
9 | |||
10 | /// Get the file's size. | ||
11 | size_t get_file_size(FILE* file); | ||
12 | |||
13 | /// Read the entire contents of the file into memory. | ||
14 | void* read_file(const char* filepath); | ||
15 | |||
16 | /// Make a path relative to the parent directory of a file. | ||
17 | bool make_relative_path( | ||
18 | size_t max_path_length, const char* filepath, const char* path, | ||
19 | char* relative); | ||
diff --git a/filesystem/src/filesystem.c b/filesystem/src/filesystem.c new file mode 100644 index 0000000..6c0dcfb --- /dev/null +++ b/filesystem/src/filesystem.c | |||
@@ -0,0 +1,92 @@ | |||
1 | #include <filesystem.h> | ||
2 | |||
3 | #include <assert.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <string.h> | ||
6 | |||
7 | size_t get_file_size(FILE* file) { | ||
8 | assert(file); | ||
9 | const long int starting_pos = ftell(file); | ||
10 | if (starting_pos == -1) { | ||
11 | return (size_t)-1; | ||
12 | } | ||
13 | if (fseek(file, 0, SEEK_END) != 0) { | ||
14 | return (size_t)-1; | ||
15 | } | ||
16 | const size_t file_size = ftell(file); | ||
17 | if (file_size == (size_t)-1) { | ||
18 | return (size_t)-1; | ||
19 | } | ||
20 | if (fseek(file, starting_pos, SEEK_SET) != 0) { | ||
21 | return (size_t)-1; | ||
22 | } | ||
23 | return file_size; | ||
24 | } | ||
25 | |||
26 | void* read_file(const char* filepath) { | ||
27 | assert(filepath); | ||
28 | |||
29 | void* data = 0; | ||
30 | |||
31 | FILE* file = fopen(filepath, "rb"); | ||
32 | if (!file) { | ||
33 | return 0; | ||
34 | } | ||
35 | const size_t file_size = get_file_size(file); | ||
36 | if (file_size == (size_t)-1) { | ||
37 | goto cleanup; | ||
38 | } | ||
39 | |||
40 | data = calloc(1, file_size); | ||
41 | if (!data) { | ||
42 | goto cleanup; | ||
43 | } | ||
44 | if (fread(data, 1, file_size, file) != file_size) { | ||
45 | goto cleanup; | ||
46 | } | ||
47 | |||
48 | return data; | ||
49 | |||
50 | cleanup: | ||
51 | fclose(file); | ||
52 | if (data) { | ||
53 | free(data); | ||
54 | } | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | bool make_relative_path( | ||
59 | size_t max_path_length, const char* filepath, const char* path, | ||
60 | char* relative) { | ||
61 | assert(filepath); | ||
62 | assert(path); | ||
63 | assert(relative); | ||
64 | |||
65 | // Handle empty filepath. | ||
66 | const size_t filepath_len = strlen(filepath); | ||
67 | if (filepath_len == 0) { | ||
68 | memcpy(relative, path, max_path_length); | ||
69 | return true; | ||
70 | } | ||
71 | |||
72 | memcpy(relative, filepath, max_path_length); | ||
73 | // Search for the last / in the tile map file path to get its parent | ||
74 | // directory. | ||
75 | assert(filepath_len > 0); | ||
76 | size_t tm_dir_len = 0; | ||
77 | for (tm_dir_len = strlen(filepath) - 1; tm_dir_len > 0; --tm_dir_len) { | ||
78 | if (filepath[tm_dir_len] == '/') { | ||
79 | break; | ||
80 | } | ||
81 | } | ||
82 | tm_dir_len++; // Preserve the backslash. | ||
83 | |||
84 | // Copy the tile set file path where the parent dir ends. | ||
85 | // Make sure there is enough space in the output. | ||
86 | const size_t path_len = strlen(path); | ||
87 | if ((tm_dir_len + path_len + 1) >= max_path_length) { | ||
88 | return false; | ||
89 | } | ||
90 | memcpy(&relative[tm_dir_len], path, path_len); | ||
91 | return true; | ||
92 | } | ||