From: Trent Huber Date: Fri, 11 Oct 2024 01:14:20 +0000 (-0400) Subject: Split code into multiple files X-Git-Url: https://trenthuber.com/code?a=commitdiff_plain;h=dd8a7a9568c090ae14ea146c1f6139e9c8ef8a09;p=xpmview.git Split code into multiple files --- diff --git a/cbs.c b/cbs.c index 5d775ef..423187b 100644 --- a/cbs.c +++ b/cbs.c @@ -3,6 +3,17 @@ #include CBS_LIBRARY_PATH #define CC "cc" +#define CFLAGS "-Wall", "-Wextra", "-Wpedantic" +#ifdef __MACH__ +#define LDFLAGS "-L./external/raylib/lib", "-lraylib", \ + "-framework", "CoreVideo", \ + "-framework", "IOKit", \ + "-framework", "Cocoa", \ + "-framework", "GLUT", \ + "-framework", "OpenGL" +#else +#define LDFLAGS "-L./external/raylib/lib", "-lraylib" +#endif // __MACH__ int main(int argc, char **argv) { cbs_rebuild_self(argv); @@ -12,20 +23,25 @@ int main(int argc, char **argv) { cbs_subbuild("./external"); cbs_run("mkdir", "-p", "./bin"); -#ifdef __MACH__ - cbs_run(CC, "-Wall", "-Wextra", "-Wpedantic", - "-I./external/raylib/src", - "-o", "./bin/simplexpm", - "./src/simplexpm.c", - "-L./external/raylib/lib", - "-lraylib", - "-framework", "CoreVideo", - "-framework", "IOKit", - "-framework", "Cocoa", - "-framework", "GLUT", - "-framework", "OpenGL"); -#endif // __MACH__ - cbs_run("./bin/simplexpm"); + Cbs_File_Paths src_files = {0}; + cbs_file_paths_build_file_ext(&src_files, "./src", ".c"); + cbs_file_paths_for_each (src_file, src_files) { + const char *obj_file = cbs_string_build(cbs_strip_file_ext(src_file), ".o"); + if (cbs_needs_rebuild(obj_file, src_file)) + cbs_run(CC, CFLAGS, "-c", "-I./include", "-I./external/raylib/src", + "-I./external/stb", "-o", obj_file, src_file); + } + + Cbs_File_Paths obj_files = {0}; + cbs_file_paths_build_file_ext(&obj_files, "./src", ".o"); + const char *bin_file = "./bin/simplexpm"; + Cbs_Cmd cmd = {0}; + cbs_cmd_build(&cmd, CC, "-o", bin_file); + cbs_cmd_build_file_paths(&cmd, obj_files); + cbs_cmd_build(&cmd, LDFLAGS); + cbs_cmd_run(&cmd); + + cbs_run(bin_file); return 0; } diff --git a/include/parser.h b/include/parser.h new file mode 100644 index 0000000..ddcca8b --- /dev/null +++ b/include/parser.h @@ -0,0 +1,17 @@ +#ifndef _PARSER_H_ +#define _PARSER_H_ + +#include +#include + +#include "raylib.h" + +extern FILE *file; +extern char *line_buffer; +extern char *keys; +extern unsigned int *color_table; +extern unsigned int *pixels; + +bool parse_xpm_file(Image *image, const char *file_path); + +#endif // _PARSER_H_ diff --git a/include/tokenizer.h b/include/tokenizer.h new file mode 100644 index 0000000..5e0893a --- /dev/null +++ b/include/tokenizer.h @@ -0,0 +1,13 @@ +#ifndef _TOKENIZER_H_ +#define _TOKENIZER_H_ + +#include +#include + +int get_next_line(char **buffer, FILE *file); +void check_next_token(char **string, char *token); +char *get_next_token(char **string); +bool get_terminal_token(char **string, char **token); +size_t convert_token_to_num(char *token, int base); + +#endif // _TOKENIZER_H_ diff --git a/include/utils.h b/include/utils.h new file mode 100644 index 0000000..ce0a356 --- /dev/null +++ b/include/utils.h @@ -0,0 +1,43 @@ +#ifndef _UTILS_H_ +#define _UTILS_H_ + +#include +#include +#include + +#include "parser.h" + +#define SIMPLE_XPM_MALLOC(p, size) \ + do { \ + p = malloc(size); \ + if (p == NULL) { \ + fprintf(stderr, "simplexpm: OUT OF MEMORY (buy more RAM?)"); \ + exit(EXIT_FAILURE); \ + } \ + memset(p, 0, size); \ + } while (0) + +#define SIMPLE_XPM_FREE(p) \ + do { \ + if (p) free(p); \ + p = NULL; \ + } while (0) + +#define ERROR_MESSAGE_CAP 2048 +extern char error_message[ERROR_MESSAGE_CAP]; +extern jmp_buf env; + +#define SIMPLE_XPM_ERROR(...) \ + do { \ + if (file) fclose(file); \ + SIMPLE_XPM_FREE(line_buffer); \ + SIMPLE_XPM_FREE(keys); \ + SIMPLE_XPM_FREE(color_table); \ + SIMPLE_XPM_FREE(pixels); \ + snprintf(error_message, ERROR_MESSAGE_CAP, __VA_ARGS__); \ + siglongjmp(env, 1); \ + } while (0) + +char *strstrip(char **string); + +#endif // _UTILS_H_ diff --git a/include/xpm_mode.h b/include/xpm_mode.h new file mode 100644 index 0000000..3dc0e98 --- /dev/null +++ b/include/xpm_mode.h @@ -0,0 +1,15 @@ +#ifndef _XPM_MODE_H_ +#define _XPM_MODE_H_ + +typedef enum { + XPM_MODE_MONO = 0, + XPM_MODE_SYMBOLIC, + XPM_MODE_GRAYSCALE_4, + XPM_MODE_GRAYSCALE, + XPM_MODE_COLOR, + NUM_XPM_MODES, +} Xpm_Mode; + +Xpm_Mode convert_token_to_mode(char *token); + +#endif // _XPM_MODE_H_ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..90195e5 --- /dev/null +++ b/src/main.c @@ -0,0 +1,63 @@ +#include +#include +#include + +#include "parser.h" +#include "raylib.h" +#include "stb_c_lexer.h" +#include "utils.h" + +#define FILE_PATH_CAP 2048 + +int main(int argc, char **argv) { + char file_path[FILE_PATH_CAP] = {0}; + Texture2D texture = {0}; + bool have_texture = false; + + // Check if a file was given on the command line + if (argc >= 2) { + strncpy(file_path, argv[2], FILE_PATH_CAP); + Image image = {0}; + if (!parse_xpm_file(&image, file_path)) + have_texture = false; + else { + UnloadTexture(texture); + texture = LoadTextureFromImage(image); + have_texture = true; + } + } + + int screenWidth = 800; + int screenHeight = 600; + SetTraceLogLevel(LOG_WARNING); + InitWindow(screenWidth, screenHeight, "simplexpm"); + + while (!WindowShouldClose()) { + if (IsFileDropped()) { + FilePathList file_paths = LoadDroppedFiles(); + strncpy(file_path, file_paths.paths[0], FILE_PATH_CAP); + UnloadDroppedFiles(file_paths); + Image image = {0}; + if (!parse_xpm_file(&image, file_path)) + have_texture = false; + else { + UnloadTexture(texture); + texture = LoadTextureFromImage(image); + have_texture = true; + } + } + + BeginDrawing(); + ClearBackground(RAYWHITE); + if (have_texture) + DrawTexture(texture, screenWidth / 2 - texture.width / 2, screenHeight / 2 - texture.height / 2, WHITE); + else + DrawText(error_message, GetScreenWidth() / 2, GetScreenHeight() / 2, 24, RED); + EndDrawing(); + } + + UnloadTexture(texture); + CloseWindow(); + + return 0; +} diff --git a/src/main.o b/src/main.o new file mode 100644 index 0000000..ddc851e Binary files /dev/null and b/src/main.o differ diff --git a/src/simplexpm.c b/src/parser.c similarity index 57% rename from src/simplexpm.c rename to src/parser.c index 85babb1..ecabf1e 100644 --- a/src/simplexpm.c +++ b/src/parser.c @@ -1,17 +1,13 @@ #include -#include #include #include #include -#include #include -#include #include "raylib.h" - -#include "../external/stb/stb_c_lexer.h" - -#define FILE_PATH_CAP 2048 +#include "tokenizer.h" +#include "utils.h" +#include "xpm_mode.h" FILE *file; char *line_buffer; @@ -19,136 +15,6 @@ char *keys; unsigned int *color_table; unsigned int *pixels; -#define SIMPLE_XPM_MALLOC(p, size) \ - do { \ - p = malloc(size); \ - if (p == NULL) { \ - fprintf(stderr, "simplexpm: OUT OF MEMORY (buy more RAM?)"); \ - exit(EXIT_FAILURE); \ - } \ - memset(p, 0, size); \ - } while (0) - -#define SIMPLE_XPM_FREE(p) \ - do { \ - if (p) free(p); \ - p = NULL; \ - } while (0) - -#define ERROR_MESSAGE_CAP 2048 -char error_message[ERROR_MESSAGE_CAP] = "Drag and drop .xpm files here"; -jmp_buf env; - -#define SIMPLE_XPM_ERROR(...) \ - do { \ - if (file) fclose(file); \ - SIMPLE_XPM_FREE(line_buffer); \ - SIMPLE_XPM_FREE(keys); \ - SIMPLE_XPM_FREE(color_table); \ - SIMPLE_XPM_FREE(pixels); \ - snprintf(error_message, ERROR_MESSAGE_CAP, __VA_ARGS__); \ - siglongjmp(env, 1); \ - } while(0) - -typedef enum { - XPM_MODE_MONO = 0, - XPM_MODE_SYMBOLIC, - XPM_MODE_GRAYSCALE_4, - XPM_MODE_GRAYSCALE, - XPM_MODE_COLOR, - NUM_XPM_MODES, -} Xpm_Mode; - -Xpm_Mode convert_token_to_mode(char *token) { - if (strcmp(token, "m") == 0) return XPM_MODE_MONO; - if (strcmp(token, "s") == 0) return XPM_MODE_SYMBOLIC; - if (strcmp(token, "g4") == 0) return XPM_MODE_GRAYSCALE_4; - if (strcmp(token, "g") == 0) return XPM_MODE_GRAYSCALE; - if (strcmp(token, "c") == 0) return XPM_MODE_COLOR; - SIMPLE_XPM_ERROR("\"%s\" is not a valid color mode", token); -} - -char *strstrip(char **string) { - for (; isspace(**string) && **string != '\0'; ++*string); - if (**string == '\0') return *string; - char *end; - for (end = *string + strlen(*string); isspace(*(end - 1)); --end); - *end = '\0'; - return *string; -} - -// TODO: Ignore comments -int get_next_line(char **buffer, FILE *file) { - static size_t line_cap = 0; - errno = 0; - if (getline(buffer, &line_cap, file) == -1) { - if (errno != 0) - SIMPLE_XPM_ERROR("Unable to parse provided file: expected a new line"); - return 0; - } - return 1; -} - -void check_next_token(char **string, char *token) { - size_t token_len = strlen(token); - if (strncmp(strstrip(string), token, token_len) != 0) - SIMPLE_XPM_ERROR("Unable to parse provided file: expected token \"%s\"", token); - *string += token_len; -} - -char *get_next_token(char **string) { - char *result; - do { - if ((result = strsep(string, "\t ")) == NULL) - SIMPLE_XPM_ERROR("Couldn't parse expected next token"); - } while (*result == '\0'); - if (*string == NULL) - SIMPLE_XPM_ERROR("Did not expect next token to be a terminal token"); - if (strlen(result) != strlen(strstrip(&result))) - SIMPLE_XPM_ERROR("Weird whitespace characters between array tokens"); - return result; -} - -bool get_terminal_token(char **string, char **token) { - bool result = true; - while (**string == '\t' || **string == ' ') ++*string; - *token = *string; - while (**string != '\t' && **string != ' ') { - if (**string == '"') { - *(*string)++ = '\0'; - goto check_comma; - } - ++*string; - } - *(*string)++ = '\0'; - if (*token == *string) - SIMPLE_XPM_ERROR("Couldn't parse potential last token"); - while (**string == '\t' || **string == ' ') ++*string; - if (**string != '"') { - result = false; - goto defer; - } - -check_comma: - check_next_token(string, ","); - -defer: - if (strlen(*token) != strlen(strstrip(token))) - SIMPLE_XPM_ERROR("Weird whitespace characters between array tokens"); - return result; -} - -size_t convert_token_to_num(char *token, int base) { - if (token == NULL) - SIMPLE_XPM_ERROR("Expected non-null token to parse"); - errno = 0; - char *end_p; - long result = strtol(token, &end_p, base); - if (*end_p != '\0' || errno == ERANGE || result < 0) - SIMPLE_XPM_ERROR("\"%s\" is not a valid number", token); - return (size_t)result; -} - bool parse_xpm_file(Image *image, const char *file_path) { switch (sigsetjmp(env, 0)) { case 1: @@ -329,57 +195,3 @@ bool parse_xpm_file(Image *image, const char *file_path) { }; return true; } - -int main(int argc, char **argv) { - char file_path[FILE_PATH_CAP] = {0}; - Texture2D texture = {0}; - bool have_texture = false; - - // Check if a file was given on the command line - if (argc >= 2) { - strncpy(file_path, argv[2], FILE_PATH_CAP); - Image image = {0}; - if (!parse_xpm_file(&image, file_path)) - have_texture = false; - else { - UnloadTexture(texture); - texture = LoadTextureFromImage(image); - have_texture = true; - } - } - - int screenWidth = 800; - int screenHeight = 600; - SetTraceLogLevel(LOG_WARNING); - InitWindow(screenWidth, screenHeight, "simplexpm"); - - while (!WindowShouldClose()) { - if (IsFileDropped()) { - FilePathList file_paths = LoadDroppedFiles(); - strncpy(file_path, file_paths.paths[0], FILE_PATH_CAP); - UnloadDroppedFiles(file_paths); - Image image = {0}; - if (!parse_xpm_file(&image, file_path)) - have_texture = false; - else { - UnloadTexture(texture); - texture = LoadTextureFromImage(image); - have_texture = true; - } - } - - BeginDrawing(); - ClearBackground(RAYWHITE); - if (have_texture) { - DrawTexture(texture, screenWidth / 2 - texture.width / 2, screenHeight / 2 - texture.height / 2, WHITE); - } else { - DrawText(error_message, GetScreenWidth() / 2, GetScreenHeight() / 2, 24, RED); - } - EndDrawing(); - } - - UnloadTexture(texture); - CloseWindow(); - - return 0; -} diff --git a/src/parser.o b/src/parser.o new file mode 100644 index 0000000..283a23b Binary files /dev/null and b/src/parser.o differ diff --git a/src/tokenizer.c b/src/tokenizer.c new file mode 100644 index 0000000..c9528f7 --- /dev/null +++ b/src/tokenizer.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include + +#include "raylib.h" +#include "utils.h" + +// TODO: Ignore comments +int get_next_line(char **buffer, FILE *file) { + static size_t line_cap = 0; + errno = 0; + if (getline(buffer, &line_cap, file) == -1) { + if (errno != 0) + SIMPLE_XPM_ERROR("Unable to parse provided file: expected a new line"); + return 0; + } + return 1; +} + +void check_next_token(char **string, char *token) { + size_t token_len = strlen(token); + if (strncmp(strstrip(string), token, token_len) != 0) + SIMPLE_XPM_ERROR("Unable to parse provided file: expected token \"%s\"", token); + *string += token_len; +} + +char *get_next_token(char **string) { + char *result; + do { + if ((result = strsep(string, "\t ")) == NULL) + SIMPLE_XPM_ERROR("Couldn't parse expected next token"); + } while (*result == '\0'); + if (*string == NULL) + SIMPLE_XPM_ERROR("Did not expect next token to be a terminal token"); + if (strlen(result) != strlen(strstrip(&result))) + SIMPLE_XPM_ERROR("Weird whitespace characters between array tokens"); + return result; +} + +bool get_terminal_token(char **string, char **token) { + bool result = true; + while (**string == '\t' || **string == ' ') ++*string; + *token = *string; + while (**string != '\t' && **string != ' ') { + if (**string == '"') { + *(*string)++ = '\0'; + goto check_comma; + } + ++*string; + } + *(*string)++ = '\0'; + if (*token == *string) + SIMPLE_XPM_ERROR("Couldn't parse potential last token"); + while (**string == '\t' || **string == ' ') ++*string; + if (**string != '"') { + result = false; + goto defer; + } + +check_comma: + check_next_token(string, ","); + +defer: + if (strlen(*token) != strlen(strstrip(token))) + SIMPLE_XPM_ERROR("Weird whitespace characters between array tokens"); + return result; +} + +size_t convert_token_to_num(char *token, int base) { + if (token == NULL) + SIMPLE_XPM_ERROR("Expected non-null token to parse"); + errno = 0; + char *end_p; + long result = strtol(token, &end_p, base); + if (*end_p != '\0' || errno == ERANGE || result < 0) + SIMPLE_XPM_ERROR("\"%s\" is not a valid number", token); + return (size_t)result; +} diff --git a/src/tokenizer.o b/src/tokenizer.o new file mode 100644 index 0000000..4526e74 Binary files /dev/null and b/src/tokenizer.o differ diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..9588307 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +#include "utils.h" + +char error_message[ERROR_MESSAGE_CAP] = "Drag and drop .xpm files here"; +jmp_buf env; + +char *strstrip(char **string) { + for (; isspace(**string) && **string != '\0'; ++*string); + if (**string == '\0') return *string; + char *end; + for (end = *string + strlen(*string); isspace(*(end - 1)); --end); + *end = '\0'; + return *string; +} diff --git a/src/utils.o b/src/utils.o new file mode 100644 index 0000000..c6608d2 Binary files /dev/null and b/src/utils.o differ diff --git a/src/xpm_mode.c b/src/xpm_mode.c new file mode 100644 index 0000000..812be3b --- /dev/null +++ b/src/xpm_mode.c @@ -0,0 +1,13 @@ +#include + +#include "xpm_mode.h" +#include "utils.h" + +Xpm_Mode convert_token_to_mode(char *token) { + if (strcmp(token, "m") == 0) return XPM_MODE_MONO; + if (strcmp(token, "s") == 0) return XPM_MODE_SYMBOLIC; + if (strcmp(token, "g4") == 0) return XPM_MODE_GRAYSCALE_4; + if (strcmp(token, "g") == 0) return XPM_MODE_GRAYSCALE; + if (strcmp(token, "c") == 0) return XPM_MODE_COLOR; + SIMPLE_XPM_ERROR("\"%s\" is not a valid color mode", token); +} diff --git a/src/xpm_mode.o b/src/xpm_mode.o new file mode 100644 index 0000000..33dd389 Binary files /dev/null and b/src/xpm_mode.o differ