diff --git a/libretro-common/file/config_file.c b/libretro-common/file/config_file.c index 0a63e7781a..7dd671b662 100644 --- a/libretro-common/file/config_file.c +++ b/libretro-common/file/config_file.c @@ -66,7 +66,7 @@ struct config_include_list }; static config_file_t *config_file_new_internal( - const char *path, unsigned depth); + const char *path, unsigned depth, config_file_cb_t *cb); static int config_sort_compare_func(struct config_entry_list *a, struct config_entry_list *b) @@ -267,7 +267,7 @@ static void add_child_list(config_file_t *parent, config_file_t *child) parent->tail = NULL; } -static void add_sub_conf(config_file_t *conf, char *path) +static void add_sub_conf(config_file_t *conf, char *path, config_file_cb_t *cb) { char real_path[PATH_MAX_LENGTH]; config_file_t *sub_conf = NULL; @@ -314,7 +314,7 @@ static void add_sub_conf(config_file_t *conf, char *path) #endif sub_conf = (config_file_t*) - config_file_new_internal(real_path, conf->include_depth + 1); + config_file_new_internal(real_path, conf->include_depth + 1, cb); if (!sub_conf) return; @@ -324,7 +324,7 @@ static void add_sub_conf(config_file_t *conf, char *path) } static bool parse_line(config_file_t *conf, - struct config_entry_list *list, char *line) + struct config_entry_list *list, char *line, config_file_cb_t *cb) { char *comment = NULL; char *key_tmp = NULL; @@ -351,7 +351,7 @@ static bool parse_line(config_file_t *conf, if (conf->include_depth >= MAX_INCLUDE_DEPTH) fprintf(stderr, "!!! #include depth exceeded for config. Might be a cycle.\n"); else - add_sub_conf(conf, path); + add_sub_conf(conf, path, cb); free(path); } goto error; @@ -396,18 +396,19 @@ error: } static config_file_t *config_file_new_internal( - const char *path, unsigned depth) + const char *path, unsigned depth, config_file_cb_t *cb) { RFILE *file = NULL; struct config_file *conf = (struct config_file*)malloc(sizeof(*conf)); if (!conf) return NULL; - conf->path = NULL; - conf->entries = NULL; - conf->tail = NULL; - conf->includes = NULL; - conf->include_depth = 0; + conf->path = NULL; + conf->entries = NULL; + conf->tail = NULL; + conf->includes = NULL; + conf->include_depth = 0; + conf->guaranteed_no_duplicates = false ; if (!path || !*path) return conf; @@ -455,7 +456,7 @@ static config_file_t *config_file_new_internal( continue; } - if (*line && parse_line(conf, list, line)) + if (*line && parse_line(conf, list, line, cb)) { if (conf->entries) conf->tail->next = list; @@ -463,6 +464,9 @@ static config_file_t *config_file_new_internal( conf->entries = list; conf->tail = list; + + if (cb != NULL && list->key != NULL && list->value != NULL) + cb->config_file_new_entry_cb(list->key, list->value) ; } free(line); @@ -551,11 +555,12 @@ config_file_t *config_file_new_from_string(const char *from_string) if (!from_string) return conf; - conf->path = NULL; - conf->entries = NULL; - conf->tail = NULL; - conf->includes = NULL; - conf->include_depth = 0; + conf->path = NULL; + conf->entries = NULL; + conf->tail = NULL; + conf->includes = NULL; + conf->include_depth = 0; + conf->guaranteed_no_duplicates = false ; lines = string_split(from_string, "\n"); if (!lines) @@ -580,7 +585,7 @@ config_file_t *config_file_new_from_string(const char *from_string) if (line && conf) { - if (*line && parse_line(conf, list, line)) + if (*line && parse_line(conf, list, line, NULL)) { if (conf->entries) conf->tail->next = list; @@ -600,9 +605,13 @@ config_file_t *config_file_new_from_string(const char *from_string) return conf; } +config_file_t *config_file_new_with_callback(const char *path, config_file_cb_t *cb) +{ + return config_file_new_internal(path, 0, cb); +} config_file_t *config_file_new(const char *path) { - return config_file_new_internal(path, 0); + return config_file_new_internal(path, 0, NULL); } static struct config_entry_list *config_get_entry(const config_file_t *conf, @@ -834,7 +843,7 @@ bool config_get_bool(config_file_t *conf, const char *key, bool *in) void config_set_string(config_file_t *conf, const char *key, const char *val) { struct config_entry_list *last = conf->entries; - struct config_entry_list *entry = config_get_entry(conf, key, &last); + struct config_entry_list *entry = conf->guaranteed_no_duplicates?NULL:config_get_entry(conf, key, &last); if (entry && !entry->readonly) { diff --git a/libretro-common/include/file/config_file.h b/libretro-common/include/file/config_file.h index 97fca031a3..e55430472d 100644 --- a/libretro-common/include/file/config_file.h +++ b/libretro-common/include/file/config_file.h @@ -58,6 +58,7 @@ struct config_file struct config_entry_list *entries; struct config_entry_list *tail; unsigned include_depth; + bool guaranteed_no_duplicates; struct config_include_list *includes; }; @@ -65,6 +66,13 @@ struct config_file typedef struct config_file config_file_t; +struct config_file_cb +{ + void (*config_file_new_entry_cb)(char*, char*); +}; + +typedef struct config_file_cb config_file_cb_t ; + /* Config file format * - # are treated as comments. Rest of the line is ignored. * - Format is: key = value. There can be as many spaces as you like in-between. @@ -79,6 +87,11 @@ typedef struct config_file config_file_t; * NULL path will create an empty config file. */ config_file_t *config_file_new(const char *path); +/* Loads a config file. Returns NULL if file doesn't exist. + * NULL path will create an empty config file. + * Includes cb callbacks to run custom code during config file processing.*/ +config_file_t *config_file_new_with_callback(const char *path, config_file_cb_t *cb); + /* Load a config file from a string. */ config_file_t *config_file_new_from_string(const char *from_string); diff --git a/managers/cheat_manager.c b/managers/cheat_manager.c index 73971f69d2..d6cc891414 100644 --- a/managers/cheat_manager.c +++ b/managers/cheat_manager.c @@ -17,6 +17,7 @@ #include <stdlib.h> #include <stddef.h> #include <string.h> +#include <errno.h> #include <file/config_file.h> #include <file/file_path.h> @@ -171,6 +172,8 @@ bool cheat_manager_save(const char *path, const char *cheat_database, bool overw if (!conf) return false; + conf->guaranteed_no_duplicates = true ; + config_set_int(conf, "cheats", cheat_manager_state.size); for (i = 0; i < cheat_manager_state.size; i++) @@ -303,39 +306,118 @@ static void cheat_manager_new(unsigned size) return ; } +void cheat_manager_load_cb_first_pass(char *key, char *value) +{ + errno = 0 ; + + if (string_is_equal(key, "cheats")) + { + cheat_manager_state.loading_cheat_size = (unsigned)strtoul(value, NULL, 0); + + if (errno != 0) + cheat_manager_state.loading_cheat_size = 0 ; + } +} + +void cheat_manager_load_cb_second_pass(char *key, char *value) +{ + char cheat_num_str[20] ; + unsigned cheat_num ; + unsigned cheat_idx ; + int idx = 0 ; + int key_length ; + errno = 0 ; + + if (strncmp(key, "cheat", 5) != 0) + return ; + + idx = 5 ; + key_length = strlen(key) ; + + while (idx < key_length && key[idx] >= '0' && key[idx] <= '9' && idx < 24) + { + cheat_num_str[idx-5] = key[idx] ; + idx++ ; + } + + cheat_num_str[idx-5] = '\0' ; + + cheat_num = (unsigned)strtoul(cheat_num_str, NULL, 0); ; + + if (cheat_num+cheat_manager_state.loading_cheat_offset >= cheat_manager_state.size) + return ; + + key = key+idx+1 ; + + cheat_idx = cheat_num+cheat_manager_state.loading_cheat_offset ; + + if (string_is_equal(key, "address")) + cheat_manager_state.cheats[cheat_idx].address = (unsigned)strtoul(value, NULL, 0); + else if (string_is_equal(key, "address_bit_position")) + cheat_manager_state.cheats[cheat_idx].address_mask = (unsigned)strtoul(value, NULL, 0); + else if (string_is_equal(key, "big_endian")) + cheat_manager_state.cheats[cheat_idx].big_endian = (string_is_equal(value,"true") || string_is_equal(value,"1")); + else if (string_is_equal(key, "cheat_type")) + cheat_manager_state.cheats[cheat_idx].cheat_type = (unsigned)strtoul(value, NULL, 0); + else if (string_is_equal(key, "code")) + cheat_manager_state.cheats[cheat_idx].code = strdup(value) ; + else if (string_is_equal(key, "desc")) + cheat_manager_state.cheats[cheat_idx].desc = strdup(value) ; + else if (string_is_equal(key, "enable")) + cheat_manager_state.cheats[cheat_idx].state = (string_is_equal(value,"true") || string_is_equal(value,"1")); + else if (string_is_equal(key, "handler")) + cheat_manager_state.cheats[cheat_idx].handler = (unsigned)strtoul(value, NULL, 0); + else if (string_is_equal(key, "memory_search_size")) + cheat_manager_state.cheats[cheat_idx].memory_search_size = (unsigned)strtoul(value, NULL, 0); + else if (string_is_equal(key, "repeat_add_to_address")) + cheat_manager_state.cheats[cheat_idx].repeat_add_to_address = (unsigned)strtoul(value, NULL, 0); + else if (string_is_equal(key, "repeat_add_to_value")) + cheat_manager_state.cheats[cheat_idx].repeat_add_to_value = (unsigned)strtoul(value, NULL, 0); + else if (string_is_equal(key, "repeat_count")) + cheat_manager_state.cheats[cheat_idx].repeat_count = (unsigned)strtoul(value, NULL, 0); + else if (string_is_equal(key, "rumble_port")) + cheat_manager_state.cheats[cheat_idx].rumble_port = (unsigned)strtoul(value, NULL, 0); + else if (string_is_equal(key, "rumble_primary_duration")) + cheat_manager_state.cheats[cheat_idx].rumble_primary_duration = (unsigned)strtoul(value, NULL, 0); + else if (string_is_equal(key, "rumble_primary_strength")) + cheat_manager_state.cheats[cheat_idx].rumble_primary_strength = (unsigned)strtoul(value, NULL, 0); + else if (string_is_equal(key, "rumble_secondary_duration")) + cheat_manager_state.cheats[cheat_idx].rumble_secondary_duration = (unsigned)strtoul(value, NULL, 0); + else if (string_is_equal(key, "rumble_secondary_strength")) + cheat_manager_state.cheats[cheat_idx].rumble_secondary_strength = (unsigned)strtoul(value, NULL, 0); + else if (string_is_equal(key, "rumble_type")) + cheat_manager_state.cheats[cheat_idx].rumble_type = (unsigned)strtoul(value, NULL, 0); + else if (string_is_equal(key, "rumble_value")) + cheat_manager_state.cheats[cheat_idx].rumble_value = (unsigned)strtoul(value, NULL, 0); + else if (string_is_equal(key, "value")) + cheat_manager_state.cheats[cheat_idx].value = (unsigned)strtoul(value, NULL, 0); + +} + bool cheat_manager_load(const char *path, bool append) { unsigned cheats = 0, i; - config_file_t *conf = config_file_new(path); + config_file_cb_t cb ; + cb.config_file_new_entry_cb = cheat_manager_load_cb_first_pass ; + config_file_t *conf = NULL ; unsigned orig_size ; - unsigned int* data_ptrs[16] = { NULL}; - char* keys[16] = { - "cheat%u_handler", - "cheat%u_memory_search_size", - "cheat%u_cheat_type", - "cheat%u_value", - "cheat%u_address", - "cheat%u_address_bit_position", - "cheat%u_rumble_type", - "cheat%u_rumble_value", - "cheat%u_rumble_port", - "cheat%u_rumble_primary_strength", - "cheat%u_rumble_primary_duration", - "cheat%u_rumble_secondary_strength", - "cheat%u_rumble_secondary_duration", - "cheat%u_repeat_count", - "cheat%u_repeat_add_to_value", - "cheat%u_repeat_add_to_address", - }; + + cheat_manager_state.loading_cheat_size = 0 ; + + conf = config_file_new_with_callback(path, &cb); if (!conf) return false; - config_get_uint(conf, "cheats", &cheats); + cheats = cheat_manager_state.loading_cheat_size ; if (cheats == 0) goto error; + config_file_free(conf) ; + conf = NULL ; + + cheat_manager_alloc_if_empty() ; if ( append ) @@ -359,75 +441,25 @@ bool cheat_manager_load(const char *path, bool append) cheat_manager_new(cheats); } + for (i = orig_size; i < cheats; i++) { - unsigned j; - char desc_key[256]; - char code_key[256]; - char enable_key[256]; - char endian_key[256]; - char *tmp = NULL; - bool tmp_bool = false; - - data_ptrs[0] = &cheat_manager_state.cheats[i].handler; - data_ptrs[1] = &cheat_manager_state.cheats[i].memory_search_size; - data_ptrs[2] = &cheat_manager_state.cheats[i].cheat_type; - data_ptrs[3] = &cheat_manager_state.cheats[i].value; - data_ptrs[4] = &cheat_manager_state.cheats[i].address; - data_ptrs[5] = &cheat_manager_state.cheats[i].address_mask; - data_ptrs[6] = &cheat_manager_state.cheats[i].rumble_type; - data_ptrs[7] = &cheat_manager_state.cheats[i].rumble_value; - data_ptrs[8] = &cheat_manager_state.cheats[i].rumble_port; - data_ptrs[9] = &cheat_manager_state.cheats[i].rumble_primary_strength; - data_ptrs[10] = &cheat_manager_state.cheats[i].rumble_primary_duration; - data_ptrs[11] = &cheat_manager_state.cheats[i].rumble_secondary_strength; - data_ptrs[12] = &cheat_manager_state.cheats[i].rumble_secondary_duration; - data_ptrs[13] = &cheat_manager_state.cheats[i].repeat_count; - data_ptrs[14] = &cheat_manager_state.cheats[i].repeat_add_to_value; - data_ptrs[15] = &cheat_manager_state.cheats[i].repeat_add_to_address; - - endian_key[0] = desc_key[0] = code_key[0] = enable_key[0] = '\0'; - - snprintf(desc_key, sizeof(desc_key), "cheat%u_desc", i-orig_size); - snprintf(code_key, sizeof(code_key), "cheat%u_code", i-orig_size); - snprintf(enable_key, sizeof(enable_key), "cheat%u_enable", i-orig_size); - snprintf(endian_key, sizeof(endian_key), "cheat%u_endian", i-orig_size); - cheat_manager_state.cheats[i].idx = i ; - cheat_manager_state.cheats[i].desc = NULL ; cheat_manager_state.cheats[i].code = NULL ; cheat_manager_state.cheats[i].state = false ; cheat_manager_state.cheats[i].big_endian = false ; - - if (config_get_string(conf, desc_key, &tmp) && !string_is_empty(tmp)) - cheat_manager_state.cheats[i].desc = strdup(tmp) ; - - if (config_get_string(conf, code_key, &tmp) && !string_is_empty(tmp)) - cheat_manager_state.cheats[i].code = strdup(tmp) ; - - if (config_get_bool(conf, enable_key, &tmp_bool)) - cheat_manager_state.cheats[i].state = tmp_bool; - - if (config_get_bool(conf, endian_key, &tmp_bool)) - cheat_manager_state.cheats[i].big_endian = tmp_bool; - - if (tmp) - free(tmp); - cheat_manager_state.cheats[i].cheat_type = CHEAT_TYPE_SET_TO_VALUE ; cheat_manager_state.cheats[i].memory_search_size = 3; - for (j = 0 ; j < 16 ; j++ ) - { - char key[50] ; - unsigned val = 0; - snprintf(key, sizeof(key), keys[j], i-orig_size); - - if ( config_get_uint(conf, key, &val)) - *(data_ptrs[j]) = val ; - } } + cheat_manager_state.loading_cheat_offset = orig_size ; + cb.config_file_new_entry_cb = cheat_manager_load_cb_second_pass ; + conf = config_file_new_with_callback(path, &cb); + + if (!conf) + return false; + config_file_free(conf); return true; diff --git a/managers/cheat_manager.h b/managers/cheat_manager.h index 917ea711b8..1e0737bcbc 100644 --- a/managers/cheat_manager.h +++ b/managers/cheat_manager.h @@ -77,7 +77,8 @@ enum cheat_rumble_type RUMBLE_TYPE_LT_VALUE, RUMBLE_TYPE_GT_VALUE, RUMBLE_TYPE_INCREASE_BY_VALUE, - RUMBLE_TYPE_DECREASE_BY_VALUE + RUMBLE_TYPE_DECREASE_BY_VALUE, + RUMBLE_TYPE_END_LIST }; /* Some codes are ridiculously large - over 10000 bytes */ @@ -178,6 +179,8 @@ struct cheat_manager unsigned browse_address; char working_desc[CHEAT_DESC_SCRATCH_SIZE] ; char working_code[CHEAT_CODE_SCRATCH_SIZE] ; + unsigned int loading_cheat_size; + unsigned int loading_cheat_offset; }; typedef struct cheat_manager cheat_manager_t; diff --git a/menu/menu_driver.h b/menu/menu_driver.h index a48402c62b..d103367302 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -45,7 +45,7 @@ RETRO_BEGIN_DECLS #endif #ifndef MAX_CHEAT_COUNTERS -#define MAX_CHEAT_COUNTERS 100 +#define MAX_CHEAT_COUNTERS 6000 #endif #define MENU_SETTINGS_CORE_INFO_NONE 0xffff diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 1a4d06d20f..7c5dff5bf6 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -4670,7 +4670,7 @@ static bool setting_append_list( config_uint_cbs(cheat_manager_state.working_cheat.rumble_type, CHEAT_RUMBLE_TYPE, setting_uint_action_left_default,setting_uint_action_right_default, MENU_ENUM_LABEL_RUMBLE_TYPE_DISABLED,&setting_get_string_representation_uint_as_enum, - RUMBLE_TYPE_DISABLED,RUMBLE_TYPE_GT_VALUE,1) ; + RUMBLE_TYPE_DISABLED,RUMBLE_TYPE_END_LIST-1,1) ; (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; config_uint_cbs(cheat_manager_state.working_cheat.rumble_value, CHEAT_RUMBLE_VALUE,