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 /filesystem | |
| parent | 2a016de1c2eb45fc5f9c8cebf6b3c726b01ec340 (diff) | |
Add filesystem library.
Diffstat (limited to 'filesystem')
| -rw-r--r-- | filesystem/CMakeLists.txt | 11 | ||||
| -rw-r--r-- | filesystem/include/filesystem.h | 19 | ||||
| -rw-r--r-- | filesystem/src/filesystem.c | 92 |
3 files changed, 122 insertions, 0 deletions
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 | } | ||
