ohsp

Prototype for a game with dual thruster controls.
git clone git://git.amin.space/ohsp.git
Log | Files | Refs | LICENSE

commit 3825f6b625b648774f35e39f3612f573ae7d6272
parent 7fd94c8e3a2b002597c4ece1c3a30070c49a529c
Author: amin <dev@aminmesbah.com>
Date:   Mon, 13 Nov 2017 07:44:14 +0000

Move linux-specific platform code to util_linux.h

The plan is to include either util_linux.h or util_windows.h, which each
supply platform-specific functions with the same signatures and names.

FossilOrigin-Name: 1545aa158bcddebac1a53934021ecaa43d5b232ea4fd03ef7af35b56d0bfc29e
Diffstat:
MMakefile | 2+-
Msrc/platform_sdl.c | 86+++++++++----------------------------------------------------------------------
Asrc/util_linux.h | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 88 insertions(+), 78 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,7 +1,7 @@ CC = gcc #TODO: add -Wpedantic back CFLAGS = -std=c99 -Wall -Wextra -Wshadow -Wno-unused-parameter -LDFLAGS = $(SDL_LDFLAGS) -lm +LDFLAGS = $(SDL_LDFLAGS) -ldl -lm SDL_CFLAGS := $(shell sdl2-config --cflags) SDL_LDFLAGS := $(shell sdl2-config --libs) diff --git a/src/platform_sdl.c b/src/platform_sdl.c @@ -1,12 +1,14 @@ #include "platform_sdl.h" +#ifdef __linux__ +#include "util_linux.h" +#elif __WIN32 +#endif + #include <stdbool.h> #include <stdio.h> #include <time.h> -// TODO: move to linux specific code -#include <sys/stat.h> - #ifndef MAP_ANONYMOUS #define MAP_ANONYMOUS MAP_ANON #endif @@ -16,76 +18,6 @@ extern bool PAUSED; static struct SDLOffscreenBuffer global_back_buffer; -time_t linux_file_get_modified_time(char *file_path) -{ - time_t mtime = 0; - struct stat file_status = {0}; - if (stat(file_path, &file_status) == 0) - { - //printf("File: %s last modified: %s\n", file_path, ctime(&file_status.st_mtime)); - mtime = file_status.st_mtime; - } - else - { - fprintf(stderr, "ERROR: Failed to stat file: %s\n", file_path); - } - return mtime; -} - - -void sdl_unload_game_code(struct SDLGameCode *game_code) -{ - if (!game_code) - { - printf("Invalid pointer *game_code\n"); - return; - } - - if (game_code->game_code_library) - { - SDL_UnloadObject(game_code->game_code_library); - game_code->game_code_library = 0; - } - game_code->is_valid = false; - game_code->game_update = 0; - game_code->game_render = 0; -} - - -// TODO: Add backup dll in case loading fails -struct SDLGameCode sdl_load_game_code(char *source_lib_path) -{ - struct SDLGameCode game_code = {0}; - - game_code.last_write_time = linux_file_get_modified_time(source_lib_path); - if (game_code.last_write_time) - { - game_code.game_code_library = SDL_LoadObject(source_lib_path); - if (game_code.game_code_library) - { - // NOTE: The C standard (as of C99) distinguishes function pointers - // from object pointers (`void *` is an object pointer). Technically it - // is undefined behavior to cast between these two pointer types. In - // practice, it works on most modern platforms. - // - // In this case, we are protected by POSIX, which specifies that - // function and data pointers must be the same size. We will only ever - // be using SDL_LoadFunction on POSIX-compliant platforms. - game_code.game_update = (game_update_t *) SDL_LoadFunction(game_code.game_code_library, "game_update"); - game_code.game_render = (game_render_t *) SDL_LoadFunction(game_code.game_code_library, "game_render"); - game_code.is_valid = (game_code.game_update && game_code.game_render); - } - } - - if (!game_code.is_valid) - { - fprintf(stderr, "ERROR: Game code is not valid: %s\n", SDL_GetError()); - } - - return game_code; -} - - struct SDLWindowDimension sdl_get_window_dimension(SDL_Window *window) { struct SDLWindowDimension result; @@ -319,7 +251,7 @@ int main(int argc, char *argv[]) controller_input.right_stick_x = 0; controller_input.right_stick_y = 0; - struct SDLGameCode game_code = sdl_load_game_code(GAME_LIB_PATH); + struct SDLGameCode game_code = load_game_code(GAME_LIB_PATH); while (running) { @@ -329,12 +261,12 @@ int main(int argc, char *argv[]) lag += elapsed_ms; //printf("%" PRIu64 ", %" PRIu64 ", %f\n", elapsed_ms, lag, MS_PER_UPDATE); - time_t last_write_time = linux_file_get_modified_time(GAME_LIB_PATH); + time_t last_write_time = file_get_modified_time(GAME_LIB_PATH); bool game_code_has_changed = last_write_time && (last_write_time != game_code.last_write_time); if (game_code_has_changed) { - sdl_unload_game_code(&game_code); - game_code = sdl_load_game_code(GAME_LIB_PATH); + unload_game_code(&game_code); + game_code = load_game_code(GAME_LIB_PATH); if (!game_code.is_valid) { // TODO: fall back to backup? diff --git a/src/util_linux.h b/src/util_linux.h @@ -0,0 +1,78 @@ +#ifndef UTIL_LINUX_H +#define UTIL_LINUX_H + +#include <dlfcn.h> +#include <sys/stat.h> + + +time_t file_get_modified_time(char *file_path) +{ + time_t mtime = 0; + struct stat file_status = {0}; + if (stat(file_path, &file_status) == 0) + { + //printf("File: %s last modified: %s\n", file_path, ctime(&file_status.st_mtime)); + mtime = file_status.st_mtime; + } + else + { + fprintf(stderr, "ERROR: Failed to stat file: %s\n", file_path); + } + return mtime; +} + + +void unload_game_code(struct SDLGameCode *game_code) +{ + if (!game_code) + { + printf("Invalid pointer *game_code\n"); + return; + } + + if (game_code->game_code_library) + { + dlclose(game_code->game_code_library); + game_code->game_code_library = 0; + } + game_code->is_valid = false; + game_code->game_update = 0; + game_code->game_render = 0; +} + + +// TODO: Add backup dll in case loading fails +struct SDLGameCode load_game_code(char *source_lib_path) +{ + struct SDLGameCode game_code = {0}; + + game_code.last_write_time = file_get_modified_time(source_lib_path); + if (game_code.last_write_time) + { + game_code.game_code_library = dlopen(source_lib_path, RTLD_LAZY); + if (game_code.game_code_library) + { + // NOTE: The C standard (as of C99) distinguishes function pointers + // from object pointers (`void *` is an object pointer). Technically it + // is undefined behavior to cast between these two pointer types. In + // practice, it works on most modern platforms. + // + // In this case, we are protected by POSIX, which specifies that + // function and data pointers must be the same size. We will only ever + // be using dlsym on POSIX-compliant platforms. + game_code.game_update = (game_update_t *) dlsym(game_code.game_code_library, "game_update"); + game_code.game_render = (game_render_t *) dlsym(game_code.game_code_library, "game_render"); + game_code.is_valid = (game_code.game_update && game_code.game_render); + } + } + + if (!game_code.is_valid) + { + fprintf(stderr, "ERROR: Game code is not valid: %s\n", dlerror()); + } + + return game_code; +} + + +#endif