aboutsummaryrefslogtreecommitdiffstats
path: root/src/platform_posix.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform_posix.c')
-rw-r--r--src/platform_posix.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/platform_posix.c b/src/platform_posix.c
new file mode 100644
index 0000000..7c2fb6c
--- /dev/null
+++ b/src/platform_posix.c
@@ -0,0 +1,171 @@
1#define _DEFAULT_SOURCE
2#include <stdarg.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <time.h>
6#include <unistd.h>
7
8#include "app.h"
9
10//
11// PlatformAPI Implementation.
12//
13
14size_t
15platform_read_file(const char *path, char *memory) {
16 size_t file_size = 0;
17 FILE *fp = fopen(path, "rb");
18 if (!fp) {
19 return 0;
20 }
21 fseek(fp, 0, SEEK_END);
22 file_size = ftell(fp);
23 rewind(fp);
24 fread(memory, 1, file_size, fp);
25 fclose(fp);
26 memory[file_size] = '\0';
27 return file_size;
28}
29
30void
31platform_log(const char *format, ...) {
32 // Print date.
33 time_t raw_time = time(NULL);
34 struct tm *tm = localtime(&raw_time);
35 char date[64];
36 strftime(date, sizeof(date), "%Y-%M-%d | %H:%M:%S", tm);
37 printf("%s | ", date);
38
39 // Print message.
40 va_list args;
41 va_start(args, format);
42 vprintf(format, args);
43
44 printf("\n");
45 va_end(args);
46}
47
48void
49platform_sleep(size_t microseconds) {
50 usleep(microseconds);
51}
52
53#if defined(LIB_NAME) && defined(LIB_DIR)
54
55//
56// Dynamic linking with hot code reload.
57//
58
59#include <dlfcn.h>
60#include <sys/stat.h>
61#include <sys/types.h>
62
63static ino_t lib_id;
64static void * lib_handle;
65
66static const char *lib_path = LIB_DIR "/" LIB_NAME;
67
68static bool
69load_lib(AppAPI *api) {
70 struct stat st;
71 if (stat(lib_path, &st) != 0) {
72 return false;
73 }
74
75 if (lib_id != st.st_ino) {
76 void *handle = dlopen(lib_path, RTLD_NOW);
77 if (!handle) {
78 lib_handle = NULL;
79 lib_id = 0;
80 return false;
81 }
82 lib_handle = handle;
83 lib_id = st.st_ino;
84
85 const AppAPI *app_api = dlsym(lib_handle, "APP_API");
86 if (app_api == NULL) {
87 dlclose(lib_handle);
88 lib_handle = NULL;
89 lib_id = 0;
90 return false;
91 }
92 *api = *app_api;
93 }
94
95 return true;
96}
97
98static bool
99_app_reload(AppAPI *api, AppState *state, PlatformAPI platform) {
100 struct stat st;
101 if (stat(lib_path, &st) == 0 && lib_id != st.st_ino) {
102 if (lib_handle) {
103 api->unload(state, platform);
104 dlclose(lib_handle);
105 }
106
107 if (!load_lib(api)) {
108 return false;
109 }
110 api->reload(state, platform);
111 }
112
113 return true;
114}
115
116static bool
117_app_init(AppAPI *api, AppState *state, PlatformAPI platform) {
118 if (!load_lib(api)) {
119 fprintf(stderr, "error: can't open app library file: %s\n", lib_path);
120 return false;
121 }
122 api->init(state, platform);
123 return true;
124}
125
126static void
127_app_destroy(AppAPI *api, AppState *state, PlatformAPI platform) {
128 api->destroy(state, platform);
129 if (lib_handle) {
130 dlclose(lib_handle);
131 lib_handle = NULL;
132 lib_id = 0;
133 }
134}
135
136#else
137
138//
139// Static linking of app code.
140//
141
142extern const AppAPI APP_API;
143
144static bool
145_app_reload() {
146 return true;
147}
148
149static bool
150_app_init(AppAPI *api, AppState *state, PlatformAPI platform) {
151 *api = APP_API;
152 api->init(state, platform);
153 return true;
154}
155
156static void
157_app_destroy(AppAPI *api, AppState *state, PlatformAPI platform) {
158 api->destroy(state, platform);
159}
160
161#endif
162
163const PlatformAPI PLATFORM_API = {
164 .read_file = platform_read_file,
165 .malloc = malloc,
166 .free = free,
167 .calloc = calloc,
168 .realloc = realloc,
169 .log = platform_log,
170 .sleep = platform_sleep,
171};