From 5a161d92d771db5afa89543b757e76bbeb8e615a Mon Sep 17 00:00:00 2001 From: Vincent-FK Date: Mon, 12 Apr 2021 18:32:08 +0200 Subject: [PATCH] config file now with extension .fkcfg --- Makefile | 2 +- platform/common/configfile.c | 4 +- platform/common/configfile_fk.c | 272 ++++++++++++++++++ .../common/{configfile.h => configfile_fk.h} | 0 platform/common/main.c | 4 +- platform/common/menu_pico.c | 2 +- platform/common/plat_sdl.c | 2 +- 7 files changed, 279 insertions(+), 7 deletions(-) create mode 100644 platform/common/configfile_fk.c rename platform/common/{configfile.h => configfile_fk.h} (100%) diff --git a/Makefile b/Makefile index 5e1c726e..93e4e8de 100644 --- a/Makefile +++ b/Makefile @@ -210,7 +210,7 @@ endif ifeq "$(USE_FRONTEND)" "1" # common -OBJS += platform/common/main.o platform/common/configfile.o platform/common/emu.o \ +OBJS += platform/common/main.o platform/common/configfile_fk.o platform/common/emu.o \ platform/common/menu_pico.o platform/common/config_file.o # libpicofe diff --git a/platform/common/configfile.c b/platform/common/configfile.c index 70b8d53b..e663efe3 100644 --- a/platform/common/configfile.c +++ b/platform/common/configfile.c @@ -1,4 +1,4 @@ -// configfile.c - handles loading and saving the configuration options +// configfile_fk.c - handles loading and saving the configuration options #include #include #include @@ -6,7 +6,7 @@ #include #include -#include "configfile.h" +#include "configfile_fk.h" #define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0])) diff --git a/platform/common/configfile_fk.c b/platform/common/configfile_fk.c new file mode 100644 index 00000000..70b8d53b --- /dev/null +++ b/platform/common/configfile_fk.c @@ -0,0 +1,272 @@ +// configfile.c - handles loading and saving the configuration options +#include +#include +#include +#include +#include +#include + +#include "configfile.h" + +#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0])) + +enum ConfigOptionType { + CONFIG_TYPE_BOOL, + CONFIG_TYPE_UINT, + CONFIG_TYPE_FLOAT, + CONFIG_TYPE_ASPECT_RATIO, +}; + +struct ConfigOption { + const char *name; + enum ConfigOptionType type; + union { + bool *boolValue; + unsigned int *uintValue; + float *floatValue; + }; +}; + +#undef X +#define X(a, b) b, +const char *aspect_ratio_name[] = {ASPECT_RATIOS}; +unsigned int aspect_ratio_factor_step = 10; + +/* + *Config options and default values + */ +unsigned int aspect_ratio = ASPECT_RATIOS_TYPE_STRETCHED; +unsigned int aspect_ratio_factor_percent = 50; + +static const struct ConfigOption options[] = { + {.name = "aspect_ratio", .type = CONFIG_TYPE_ASPECT_RATIO, .uintValue = &aspect_ratio}, + {.name = "aspect_ratio_factor_percent", .type = CONFIG_TYPE_UINT, .uintValue = &aspect_ratio_factor_percent}, +}; + +// Reads an entire line from a file (excluding the newline character) and returns an allocated string +// Returns NULL if no lines could be read from the file +static char *read_file_line(FILE *file) { + char *buffer; + size_t bufferSize = 64; + size_t offset = 0; // offset in buffer to write + + buffer = (char*)malloc(bufferSize); + while (1) { + // Read a line from the file + if (fgets(buffer + offset, bufferSize - offset, file) == NULL) { + free(buffer); + return NULL; // Nothing could be read. + } + offset = strlen(buffer); + assert(offset > 0); + + if (feof(file)) // EOF was reached + break; + + // If a newline was found, remove the trailing newline and exit + if (buffer[offset - 1] == '\n') { + buffer[offset - 1] = '\0'; + break; + } + + // If no newline or EOF was reached, then the whole line wasn't read. + bufferSize *= 2; // Increase buffer size + buffer = (char*)realloc(buffer, bufferSize); + assert(buffer != NULL); + } + + return buffer; +} + +// Returns the position of the first non-whitespace character +static char *skip_whitespace(char *str) { + while (isspace(*str)) + str++; + return str; +} + +// Returns the position of the first non-whitespace or '=' character +static char *skip_whitespace_or_equal(char *str) { + while (isspace(*str) || *str=='=') + str++; + return str; +} + +// NULL-terminates the current whitespace-delimited word, and returns a pointer to the next word +static char *word_split(char *str) { + // Precondition: str must not point to whitespace + assert(!isspace(*str)); + + // Find either the next whitespace, '=' or end of string + while (!isspace(*str) && *str != '\0' && *str != '=') + str++; + if (*str == '\0') // End of string + return str; + + // Terminate current word + *(str++) = '\0'; + + // Skip whitespace to next word + return skip_whitespace_or_equal(str); +} + +// Splits a string into words, and stores the words into the 'tokens' array +// 'maxTokens' is the length of the 'tokens' array +// Returns the number of tokens parsed +static unsigned int tokenize_string(char *str, int maxTokens, char **tokens) { + int count = 0; + + str = skip_whitespace(str); + while (str[0] != '\0' && count < maxTokens) { + tokens[count] = str; + str = word_split(str); + count++; + } + return count; +} + +// Loads the config file specified by 'filepath' +void configfile_load(const char *filepath) { + FILE *file; + char *line; + unsigned int cur_line = 0; + char *current_section = NULL; + + printf("Loading configuration from '%s'\n", filepath); + + // Open file or create it if it does not exist + file = fopen(filepath, "r"); + if (file == NULL) { + // Create a new config file and save defaults + printf("Config file '%s' not found. Creating it.\n", filepath); + configfile_save(filepath); + return; + } + + // Go through each line in the file + while ((line = read_file_line(file)) != NULL) { + char *p = line; + char *tokens[2]; + int numTokens; + cur_line++; + + // Get tokens + while (isspace(*p)) p++; + numTokens = tokenize_string(p, 2, tokens); + + // Get content + if (numTokens != 0) { + + // Pass comments + if(tokens[0][0]=='#') continue; + + // Check sections - useless for now + if(tokens[0][0]=='['){ + p=tokens[0]; + while(*p != '\0' && *p!=']') p++; + if(*p == '\0') continue; + *p=0; + if(current_section) free(current_section); + current_section = (char*)malloc(strlen(tokens[0])); //strlen(tokens[0])-1+1 + strcpy(current_section, &tokens[0][1]); + printf("New Section: %s\n", current_section); + continue; + } + + if (numTokens == 2) { + const struct ConfigOption *option = NULL; + + for (unsigned int i = 0; i < ARRAY_LEN(options); i++) { + if (strcmp(tokens[0], options[i].name) == 0) { + option = &options[i]; + break; + } + } + if (option == NULL){ + printf("Unknown option '%s'\n", tokens[0]); + } + else { + printf("Reading option: '%s', value: '%s'\n", tokens[0], tokens[1]); + switch (option->type) { + case CONFIG_TYPE_BOOL: + if (strcmp(tokens[1], "true") == 0) + *option->boolValue = true; + else if (strcmp(tokens[1], "false") == 0) + *option->boolValue = false; + else{ + printf("Unknown CONFIG_TYPE_BOOL value: '%s', using default: %s\n", + tokens[1], (*option->boolValue)?"true":"false"); + } + break; + case CONFIG_TYPE_UINT: + sscanf(tokens[1], "%u", option->uintValue); + break; + case CONFIG_TYPE_FLOAT: + sscanf(tokens[1], "%f", option->floatValue); + break; + case CONFIG_TYPE_ASPECT_RATIO: + ;unsigned int cur_ar; + for(cur_ar=0; cur_aruintValue = cur_ar; + break; + } + } + if(cur_ar >= NB_ASPECT_RATIOS_TYPES){ + printf("Unknown CONFIG_TYPE_ASPECT_RATIO value: '%s', using default value: %s\n", + tokens[1], aspect_ratio_name[*option->uintValue]); + } + break; + default: + printf("Unknown option type '%d'\n", option->type); + break; + } + } + } + else{ + fprintf(stderr, "Error in line %d: wrong format\n", cur_line); + } + } + free(line); + } + + fclose(file); +} + +// Writes the config file to 'filepath' +void configfile_save(const char *filepath) { + FILE *file; + + printf("Saving configuration to '%s'\n", filepath); + + file = fopen(filepath, "w"); + if (file == NULL) { + // error + printf("Could not save\n"); + return; + } + printf("Saved !\n"); + + for (unsigned int i = 0; i < ARRAY_LEN(options); i++) { + const struct ConfigOption *option = &options[i]; + + switch (option->type) { + case CONFIG_TYPE_BOOL: + fprintf(file, "%s = %s\n", option->name, *option->boolValue ? "true" : "false"); + break; + case CONFIG_TYPE_UINT: + fprintf(file, "%s = %u\n", option->name, *option->uintValue); + break; + case CONFIG_TYPE_FLOAT: + fprintf(file, "%s = %f\n", option->name, *option->floatValue); + break; + case CONFIG_TYPE_ASPECT_RATIO: + fprintf(file, "%s = %s\n", option->name, aspect_ratio_name[*option->uintValue]); + break; + default: + assert(0); // unknown type + } + } + + fclose(file); +} diff --git a/platform/common/configfile.h b/platform/common/configfile_fk.h similarity index 100% rename from platform/common/configfile.h rename to platform/common/configfile_fk.h diff --git a/platform/common/main.c b/platform/common/main.c index c6304bf9..9b3852d4 100644 --- a/platform/common/main.c +++ b/platform/common/main.c @@ -20,7 +20,7 @@ #include "../libpicofe/plat.h" #include "menu_pico.h" #include "emu.h" -#include "configfile.h" +#include "configfile_fk.h" #include "version.h" #include @@ -39,7 +39,7 @@ char *quick_save_file = NULL; char *cfg_file_default = NULL; char *cfg_file_rom = NULL; static char *cfg_file_default_name = "default_config"; -static char *cfg_file_extension = "cfg"; +static char *cfg_file_extension = "fkcfg"; int mQuickSaveAndPoweroff=0; diff --git a/platform/common/menu_pico.c b/platform/common/menu_pico.c index 0f8f0db1..e1111e56 100644 --- a/platform/common/menu_pico.c +++ b/platform/common/menu_pico.c @@ -14,7 +14,7 @@ #include #include "emu.h" -#include "configfile.h" +#include "configfile_fk.h" #include "menu_pico.h" #include "input_pico.h" #include "../libpicofe/input.h" diff --git a/platform/common/plat_sdl.c b/platform/common/plat_sdl.c index e771301d..55d0d33b 100644 --- a/platform/common/plat_sdl.c +++ b/platform/common/plat_sdl.c @@ -16,7 +16,7 @@ #include "../libpicofe/in_sdl.h" #include "../libpicofe/gl.h" #include "emu.h" -#include "configfile.h" +#include "configfile_fk.h" #include "menu_pico.h" #include "input_pico.h" #include "plat_sdl.h"