diff --git a/Makefile.common b/Makefile.common index 44d05c3be6..e52f65f28f 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1475,6 +1475,7 @@ ifeq ($(HAVE_NETWORKING), 1) DEFINES += -DHAVE_CHEEVOS OBJ += cheevos/cheevos.o \ cheevos/var.o \ + cheevos/cond.o \ $(LIBRETRO_COMM_DIR)/utils/md5.o endif diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index 231385665a..8fe4ddd6a7 100644 --- a/cheevos/cheevos.c +++ b/cheevos/cheevos.c @@ -37,6 +37,7 @@ #include "cheevos.h" #include "var.h" +#include "cond.h" #include "../command.h" #include "../dynamic.h" @@ -98,30 +99,6 @@ #define CHEEVOS_EIGHT_MB ( 8 * 1024 * 1024) #define CHEEVOS_SIZE_LIMIT (64 * 1024 * 1024) -enum -{ - CHEEVOS_COND_OP_EQUALS = 0, - CHEEVOS_COND_OP_LESS_THAN, - CHEEVOS_COND_OP_LESS_THAN_OR_EQUAL, - CHEEVOS_COND_OP_GREATER_THAN, - CHEEVOS_COND_OP_GREATER_THAN_OR_EQUAL, - CHEEVOS_COND_OP_NOT_EQUAL_TO, - - CHEEVOS_COND_OP_LAST -}; /* cheevos_cond_t.op */ - -enum -{ - CHEEVOS_COND_TYPE_STANDARD = 0, - CHEEVOS_COND_TYPE_PAUSE_IF, - CHEEVOS_COND_TYPE_RESET_IF, - CHEEVOS_COND_TYPE_ADD_SOURCE, - CHEEVOS_COND_TYPE_SUB_SOURCE, - CHEEVOS_COND_TYPE_ADD_HITS, - - CHEEVOS_COND_TYPE_LAST -}; /* cheevos_cond_t.type */ - enum { CHEEVOS_DIRTY_TITLE = 1 << 0, @@ -143,17 +120,6 @@ enum CHEEVOS_ACTIVE_HARDCORE = 1 << 1 }; -typedef struct -{ - unsigned type; - unsigned req_hits; - unsigned curr_hits; - - cheevos_var_t source; - unsigned op; - cheevos_var_t target; -} cheevos_cond_t; - typedef struct { cheevos_cond_t *conds; @@ -862,115 +828,6 @@ static int cheevos_count_cheevos(const char *json, Parse the MemAddr field. *****************************************************************************/ -static unsigned cheevos_read_hits(const char **memaddr) -{ - char *end = NULL; - const char *str = *memaddr; - unsigned num_hits = 0; - - if (*str == '(' || *str == '.') - { - num_hits = (unsigned)strtol(str + 1, &end, 10); - str = end + 1; - } - - *memaddr = str; - return num_hits; -} - -static unsigned cheevos_parse_operator(const char **memaddr) -{ - unsigned char op; - const char *str = *memaddr; - - if (*str == '=' && str[1] == '=') - { - op = CHEEVOS_COND_OP_EQUALS; - str += 2; - } - else if (*str == '=') - { - op = CHEEVOS_COND_OP_EQUALS; - str++; - } - else if (*str == '!' && str[1] == '=') - { - op = CHEEVOS_COND_OP_NOT_EQUAL_TO; - str += 2; - } - else if (*str == '<' && str[1] == '=') - { - op = CHEEVOS_COND_OP_LESS_THAN_OR_EQUAL; - str += 2; - } - else if (*str == '<') - { - op = CHEEVOS_COND_OP_LESS_THAN; - str++; - } - else if (*str == '>' && str[1] == '=') - { - op = CHEEVOS_COND_OP_GREATER_THAN_OR_EQUAL; - str += 2; - } - else if (*str == '>') - { - op = CHEEVOS_COND_OP_GREATER_THAN; - str++; - } - else - { - RARCH_ERR("[CHEEVOS]: Unknown operator %c\n.", *str); - op = CHEEVOS_COND_OP_EQUALS; - } - - *memaddr = str; - return op; -} - -static void cheevos_parse_cond(cheevos_cond_t *cond, const char **memaddr) -{ - const char* str = *memaddr; - cond->type = CHEEVOS_COND_TYPE_STANDARD; - - if (str[1] == ':') - { - int skip = 2; - - switch (*str) - { - case 'R': - cond->type = CHEEVOS_COND_TYPE_RESET_IF; - break; - case 'P': - cond->type = CHEEVOS_COND_TYPE_PAUSE_IF; - break; - case 'A': - cond->type = CHEEVOS_COND_TYPE_ADD_SOURCE; - break; - case 'B': - cond->type = CHEEVOS_COND_TYPE_SUB_SOURCE; - break; - case 'C': - cond->type = CHEEVOS_COND_TYPE_ADD_HITS; - break; - default: - skip = 0; - break; - } - - str += skip; - } - - cheevos_var_parse(&cond->source, &str); - cond->op = cheevos_parse_operator(&str); - cheevos_var_parse(&cond->target, &str); - cond->curr_hits = 0; - cond->req_hits = cheevos_read_hits(&str); - - *memaddr = str; -} - static unsigned cheevos_count_cond_sets(const char *memaddr) { cheevos_cond_t cond; @@ -982,7 +839,7 @@ static unsigned cheevos_count_cond_sets(const char *memaddr) for (;;) { - cheevos_parse_cond(&cond, &memaddr); + cheevos_cond_parse(&cond, &memaddr); if (*memaddr != '_') break; @@ -999,73 +856,6 @@ static unsigned cheevos_count_cond_sets(const char *memaddr) return count; } -static unsigned cheevos_count_conds_in_set(const char *memaddr, unsigned set) -{ - cheevos_cond_t cond; - unsigned index = 0; - unsigned count = 0; - - for (;;) - { - for (;;) - { - cheevos_parse_cond(&cond, &memaddr); - - if (index == set) - count++; - - if (*memaddr != '_') - break; - - memaddr++; - } - - index++; - - if (*memaddr != 'S') - break; - - memaddr++; - } - - return count; -} - -static void cheevos_parse_memaddr(cheevos_cond_t *cond, const char *memaddr, unsigned set) -{ - cheevos_cond_t dummy; - unsigned index = 0; - - for (;;) - { - for (;;) - { - if (index == set) - { - cheevos_parse_cond(cond, &memaddr); -#ifdef CHEEVOS_VERBOSE - cheevos_log_cond(cond); -#endif - cond++; - } - else - cheevos_parse_cond(&dummy, &memaddr); - - if (*memaddr != '_') - break; - - memaddr++; - } - - index++; - - if (*memaddr != 'S') - break; - - memaddr++; - } -} - static int cheevos_parse_condition(cheevos_condition_t *condition, const char* memaddr) { condition->count = cheevos_count_cond_sets(memaddr); @@ -1088,7 +878,7 @@ static int cheevos_parse_condition(cheevos_condition_t *condition, const char* m for (condset = condition->condsets; condset < end; condset++, set++) { condset->count = - cheevos_count_conds_in_set(memaddr, set); + cheevos_cond_count_in_set(memaddr, set); condset->conds = NULL; #ifdef CHEEVOS_VERBOSE @@ -1112,7 +902,7 @@ static int cheevos_parse_condition(cheevos_condition_t *condition, const char* m } condset->conds = conds; - cheevos_parse_memaddr(condset->conds, memaddr, set); + cheevos_cond_parse_in_set(condset->conds, memaddr, set); } } } diff --git a/cheevos/cheevos.h b/cheevos/cheevos.h index 5b14489cca..359d8a541b 100644 --- a/cheevos/cheevos.h +++ b/cheevos/cheevos.h @@ -19,6 +19,8 @@ #include #include +#include + #include RETRO_BEGIN_DECLS diff --git a/cheevos/cond.c b/cheevos/cond.c new file mode 100644 index 0000000000..3566f8e6bf --- /dev/null +++ b/cheevos/cond.c @@ -0,0 +1,192 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2015-2017 - Andre Leiradella + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include "cond.h" +#include "var.h" + +#include "../retroarch.h" +#include "../verbosity.h" + +/***************************************************************************** +Parsing +*****************************************************************************/ + +static cheevos_cond_op_t cheevos_cond_parse_operator(const char** memaddr) +{ + const char *str = *memaddr; + cheevos_cond_op_t op; + + if (*str == '=' && str[1] == '=') + { + op = CHEEVOS_COND_OP_EQUALS; + str += 2; + } + else if (*str == '=') + { + op = CHEEVOS_COND_OP_EQUALS; + str++; + } + else if (*str == '!' && str[1] == '=') + { + op = CHEEVOS_COND_OP_NOT_EQUAL_TO; + str += 2; + } + else if (*str == '<' && str[1] == '=') + { + op = CHEEVOS_COND_OP_LESS_THAN_OR_EQUAL; + str += 2; + } + else if (*str == '<') + { + op = CHEEVOS_COND_OP_LESS_THAN; + str++; + } + else if (*str == '>' && str[1] == '=') + { + op = CHEEVOS_COND_OP_GREATER_THAN_OR_EQUAL; + str += 2; + } + else if (*str == '>') + { + op = CHEEVOS_COND_OP_GREATER_THAN; + str++; + } + else + { + RARCH_ERR(CHEEVOS_TAG "unknown operator %c\n.", *str); + op = CHEEVOS_COND_OP_EQUALS; + } + + *memaddr = str; + return op; +} + +void cheevos_cond_parse(cheevos_cond_t* cond, const char** memaddr) +{ + const char* str = *memaddr; + cond->type = CHEEVOS_COND_TYPE_STANDARD; + + if (*str != 0 && str[1] == ':') + { + int skip = 2; + + switch (*str) + { + case 'R': + cond->type = CHEEVOS_COND_TYPE_RESET_IF; + break; + case 'P': + cond->type = CHEEVOS_COND_TYPE_PAUSE_IF; + break; + case 'A': + cond->type = CHEEVOS_COND_TYPE_ADD_SOURCE; + break; + case 'B': + cond->type = CHEEVOS_COND_TYPE_SUB_SOURCE; + break; + case 'C': + cond->type = CHEEVOS_COND_TYPE_ADD_HITS; + break; + default: + skip = 0; + break; + } + + str += skip; + } + + cheevos_var_parse(&cond->source, &str); + cond->op = cheevos_cond_parse_operator(&str); + cheevos_var_parse(&cond->target, &str); + cond->curr_hits = 0; + + if (*str == '(' || *str == '.') + { + char* end; + cond->req_hits = (unsigned)strtol(str + 1, &end, 10); + str = end + (*end == ')' || *end == '.'); + } + else + cond->req_hits = 0; + + *memaddr = str; +} + +unsigned cheevos_cond_count_in_set(const char* memaddr, unsigned which) +{ + cheevos_cond_t dummy; + unsigned index = 0; + unsigned count = 0; + + for (;;) + { + for (;;) + { + cheevos_cond_parse(&dummy, &memaddr); + + if (index == which) + count++; + + if (*memaddr != '_') + break; + + memaddr++; + } + + index++; + + if (*memaddr != 'S') + break; + + memaddr++; + } + + return count; +} + +void cheevos_cond_parse_in_set(cheevos_cond_t* cond, const char* memaddr, unsigned which) +{ + cheevos_cond_t dummy; + unsigned index = 0; + + for (;;) + { + for (;;) + { + if (index == which) + { + cheevos_cond_parse(cond, &memaddr); +#ifdef CHEEVOS_VERBOSE + /*cheevos_log_cond(cond);*/ +#endif + cond++; + } + else + cheevos_cond_parse(&dummy, &memaddr); + + if (*memaddr != '_') + break; + + memaddr++; + } + + index++; + + if (*memaddr != 'S') + break; + + memaddr++; + } +} diff --git a/cheevos/cond.h b/cheevos/cond.h new file mode 100644 index 0000000000..5fc0e532b6 --- /dev/null +++ b/cheevos/cond.h @@ -0,0 +1,62 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2015-2017 - Andre Leiradella + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __RARCH_CHEEVOS_COND_H +#define __RARCH_CHEEVOS_COND_H + +#include "var.h" + +#include + +RETRO_BEGIN_DECLS + +typedef enum +{ + CHEEVOS_COND_TYPE_STANDARD, + CHEEVOS_COND_TYPE_PAUSE_IF, + CHEEVOS_COND_TYPE_RESET_IF, + CHEEVOS_COND_TYPE_ADD_SOURCE, + CHEEVOS_COND_TYPE_SUB_SOURCE, + CHEEVOS_COND_TYPE_ADD_HITS +} cheevos_cond_type_t; + +typedef enum +{ + CHEEVOS_COND_OP_EQUALS, + CHEEVOS_COND_OP_LESS_THAN, + CHEEVOS_COND_OP_LESS_THAN_OR_EQUAL, + CHEEVOS_COND_OP_GREATER_THAN, + CHEEVOS_COND_OP_GREATER_THAN_OR_EQUAL, + CHEEVOS_COND_OP_NOT_EQUAL_TO +} cheevos_cond_op_t; + +typedef struct +{ + cheevos_cond_type_t type; + unsigned req_hits; + unsigned curr_hits; + + cheevos_var_t source; + cheevos_cond_op_t op; + cheevos_var_t target; +} cheevos_cond_t; + +void cheevos_cond_parse(cheevos_cond_t* cond, const char** memaddr); +unsigned cheevos_cond_count_in_set(const char* memaddr, unsigned which); +void cheevos_cond_parse_in_set(cheevos_cond_t* cond, const char* memaddr, unsigned which); + +RETRO_END_DECLS + +#endif /* __RARCH_CHEEVOS_COND_H */ diff --git a/cheevos/var.c b/cheevos/var.c index 1f11707354..282a4d8dc6 100644 --- a/cheevos/var.c +++ b/cheevos/var.c @@ -296,7 +296,7 @@ uint8_t* cheevos_var_get_memory(const cheevos_var_t* var) memory = (uint8_t*)system->mmaps.descriptors[var->bank_id].core.ptr; else { - retro_ctx_memory_info_t meminfo; + retro_ctx_memory_info_t meminfo = {NULL, 0, 0}; switch (var->bank_id) { diff --git a/griffin/griffin.c b/griffin/griffin.c index f316fc7a07..1a64bde2f4 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -152,6 +152,7 @@ ACHIEVEMENTS #include "../network/net_http_special.c" #include "../cheevos/cheevos.c" #include "../cheevos/var.c" +#include "../cheevos/cond.c" #endif /*============================================================