aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2023-07-11 18:37:45 -0700
committer3gg <3gg@shellblade.net>2023-07-11 18:38:04 -0700
commitfc5886c75ab2626acbc0d7b3db475d17d2cbe01f (patch)
tree1f84aabf268a40ddc6b4f5deef2450fca2171f6e
parent2a016de1c2eb45fc5f9c8cebf6b3c726b01ec340 (diff)
Add filesystem library.
-rw-r--r--CMakeLists.txt3
-rw-r--r--filesystem/CMakeLists.txt11
-rw-r--r--filesystem/include/filesystem.h19
-rw-r--r--filesystem/src/filesystem.c92
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)
3project(clib) 3project(clib)
4 4
5add_subdirectory(cstring) 5add_subdirectory(cstring)
6add_subdirectory(error)
7add_subdirectory(filesystem)
6add_subdirectory(list) 8add_subdirectory(list)
7add_subdirectory(listpool) 9add_subdirectory(listpool)
8add_subdirectory(log) 10add_subdirectory(log)
9add_subdirectory(mempool) 11add_subdirectory(mempool)
12add_subdirectory(plugin)
10add_subdirectory(random) 13add_subdirectory(random)
11add_subdirectory(timer) 14add_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 @@
1cmake_minimum_required(VERSION 3.0)
2
3project(filesystem)
4
5add_library(filesystem
6 src/filesystem.c)
7
8target_include_directories(filesystem PUBLIC
9 include)
10
11target_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.
11size_t get_file_size(FILE* file);
12
13/// Read the entire contents of the file into memory.
14void* read_file(const char* filepath);
15
16/// Make a path relative to the parent directory of a file.
17bool 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
7size_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
26void* 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
50cleanup:
51 fclose(file);
52 if (data) {
53 free(data);
54 }
55 return 0;
56}
57
58bool 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}