#define _DEFAULT_SOURCE #include #include #include #include #include #include "app.h" // // PlatformAPI Implementation. // size_t platform_read_file(const char *path, char *memory) { size_t file_size = 0; FILE *fp = fopen(path, "rb"); if (!fp) { return 0; } fseek(fp, 0, SEEK_END); file_size = ftell(fp); rewind(fp); fread(memory, 1, file_size, fp); fclose(fp); memory[file_size] = '\0'; return file_size; } void platform_log(const char *format, ...) { // Print date. time_t raw_time = time(NULL); struct tm *tm = localtime(&raw_time); char date[64]; strftime(date, sizeof(date), "%Y-%M-%d | %H:%M:%S", tm); printf("%s | ", date); // Print message. va_list args; va_start(args, format); vprintf(format, args); printf("\n"); va_end(args); } void platform_sleep(size_t microseconds) { usleep(microseconds); } #if defined(LIB_NAME) && defined(LIB_DIR) // // Dynamic linking with hot code reload. // #include #include #include static ino_t lib_id; static void * lib_handle; static const char *lib_path = LIB_DIR "/" LIB_NAME; static bool load_lib(AppAPI *api) { struct stat st; if (stat(lib_path, &st) != 0) { return false; } if (lib_id != st.st_ino) { void *handle = dlopen(lib_path, RTLD_NOW); if (!handle) { lib_handle = NULL; lib_id = 0; return false; } lib_handle = handle; lib_id = st.st_ino; const AppAPI *app_api = dlsym(lib_handle, "APP_API"); if (app_api == NULL) { dlclose(lib_handle); lib_handle = NULL; lib_id = 0; return false; } *api = *app_api; } return true; } static bool _app_reload(AppAPI *api, AppState *state, PlatformAPI platform) { struct stat st; if (stat(lib_path, &st) == 0 && lib_id != st.st_ino) { if (lib_handle) { api->unload(state, platform); dlclose(lib_handle); } if (!load_lib(api)) { return false; } api->reload(state, platform); } return true; } static bool _app_init(AppAPI *api, AppState *state, PlatformAPI platform) { if (!load_lib(api)) { fprintf(stderr, "error: can't open app library file: %s\n", lib_path); return false; } api->init(state, platform); return true; } static void _app_destroy(AppAPI *api, AppState *state, PlatformAPI platform) { api->destroy(state, platform); if (lib_handle) { dlclose(lib_handle); lib_handle = NULL; lib_id = 0; } } #else // // Static linking of app code. // extern const AppAPI APP_API; static bool _app_reload() { return true; } static bool _app_init(AppAPI *api, AppState *state, PlatformAPI platform) { *api = APP_API; api->init(state, platform); return true; } static void _app_destroy(AppAPI *api, AppState *state, PlatformAPI platform) { api->destroy(state, platform); } #endif const PlatformAPI PLATFORM_API = { .read_file = platform_read_file, .malloc = malloc, .free = free, .calloc = calloc, .realloc = realloc, .log = platform_log, .sleep = platform_sleep, };