From b978fb2288f7c649cde53e4194135cba5cd65528 Mon Sep 17 00:00:00 2001 From: jacekpoz Date: Fri, 26 Apr 2024 19:05:35 +0200 Subject: [PATCH] fix pretty much everything, read description this is a big (or dare I say, huge) commit that pretty much fixes every problem I've had so far with the basic parsing I still need to do a custom operator>> for some types but at this point the parser goes through the entire file and prints out everything which is a large milestone I'd say changes in this commit: - add SECTION_LIST for a section containing a single list of values examples: TimingPoints, HitObjects - improve operator>> for enums making it accept int values and fail properly when the value is incorrect (there's a warning I need to get rid of but it's ok for now) - skip over blank lines: adding this single line (src/osuparser.cpp:52) made the parser go from shitting itself to actually going through the whole file and printing everything (with some errors but still) - new string util: isBlank() used for the above - new __VA_ARGS__ util: ARG_COUNT() and rename foreach.hpp to va_args_util.hpp as that name no longer fits --- include/config.hpp | 33 ++++++++++++++++++----- include/config_def.hpp | 15 +++++------ include/string_util.hpp | 4 +++ include/{foreach.hpp => va_args_util.hpp} | 19 +++++++++++-- src/osuparser.cpp | 17 ++++++++++++ 5 files changed, 71 insertions(+), 17 deletions(-) rename include/{foreach.hpp => va_args_util.hpp} (80%) diff --git a/include/config.hpp b/include/config.hpp index 3df4c8c..488877f 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -10,7 +10,7 @@ #include #include -#include +#include #define CONFIG(name, ...) \ struct name {\ @@ -22,6 +22,8 @@ __VA_ARGS__\ } name; +#define SECTION_LIST(name, type) std::vector name; + #define VAR_UINT(section, name) uint name; #define VAR_UINT_P(section, name, prefix) VAR_UINT(section, name) #define VAR_UINT_D(section, name, default) uint name = default; @@ -62,7 +64,7 @@ #define VAR_ENUM_D(section, name, enum_type, default) enum_type name = enum_type::default; #define ENUM_TO_STRING_CASE(name, e) case name::e: os << #e; break; -#define ENUM_FROM_STRING(name, e) if (input == #e) en = name::e; +#define ENUM_FROM_STRING(name, e) if (input == #e) { en = name::e; hasBeenSet = true; } #define ENUM_STREAM_OPS(name, ...) \ inline std::ostream &operator<<(std::ostream &os, const name &en) {\ @@ -76,11 +78,29 @@ std::string input;\ is >> input;\ if (isInt(input)) {\ - en = static_cast(std::stoul(input));\ - return is;\ + try {\ + int inputNum = std::stoul(input);\ + if (inputNum >= ARG_COUNT(__VA_ARGS__)) {\ + /* TODO this and the comment below give me -Wmaybe-uninitialized + * which I would say is the expected outcome in this case + * but what do I know; find a way to silence the warning + * while still retaining this behaviour */\ + is.setstate(std::ios_base::failbit);\ + } else {\ + en = static_cast(inputNum);\ + }\ + } catch (std::invalid_argument const&) {\ + /* the comment below */\ + is.setstate(std::ios_base::failbit);\ + }\ + } else {\ + toUpper(input);\ + bool hasBeenSet = false;\ + FOR_EACH(ENUM_FROM_STRING, name, __VA_ARGS__)\ + if (!hasBeenSet) {\ + is.setstate(std::ios_base::failbit);\ + }\ }\ - toUpper(input);\ - FOR_EACH(ENUM_FROM_STRING, name, __VA_ARGS__)\ return is;\ } @@ -123,6 +143,7 @@ #undef CONFIG #undef SECTION +#undef SECTION_LIST #undef VAR_UINT #undef VAR_UINT_P diff --git a/include/config_def.hpp b/include/config_def.hpp index 9ac79c6..9677fb6 100644 --- a/include/config_def.hpp +++ b/include/config_def.hpp @@ -3,6 +3,7 @@ #define CONFIG(name, ...) #define SECTION(name, ...) +#define SECTION_LIST(name, type) #define VAR_UINT(section, name) #define VAR_UINT_P(section, name, prefix) @@ -162,18 +163,13 @@ CONFIG(Difficulty, VAR_FLOAT(.difficulty, sliderMultiplier) VAR_FLOAT(.difficulty, sliderTickRate) ) - SECTION(timingPoints, - VAR_LIST(.timingPoints, timingPoints, TimingPoint) - ) + SECTION_LIST(timingPoints, TimingPoint) SECTION(colours, VAR_LIST_NUMBERED(.colours, combo, sf::Color) VAR_COLOUR(.colours, sliderTrackOverride) VAR_COLOUR(.colours, sliderBorder) ) - - SECTION(hitObjects, - VAR_LIST(.hitObjects, hitObjects, HitObject) - ) + SECTION_LIST(hitObjects, HitObject) ) STRUCT_OUTPUT_STREAM_OP(Difficulty, formatVersion, @@ -214,16 +210,17 @@ STRUCT_OUTPUT_STREAM_OP(Difficulty, difficulty.approachRate, difficulty.sliderMultiplier, difficulty.sliderTickRate, - timingPoints.timingPoints, + timingPoints, colours.combo, colours.sliderTrackOverride, colours.sliderBorder, - hitObjects.hitObjects + hitObjects ) #ifdef CONFIG_DEFINED #undef CONFIG #undef SECTION +#undef SECTION_LIST #undef VAR_UINT #undef VAR_UINT_P diff --git a/include/string_util.hpp b/include/string_util.hpp index 7280251..39f7588 100644 --- a/include/string_util.hpp +++ b/include/string_util.hpp @@ -18,3 +18,7 @@ inline void toUpper(std::string &str) { inline bool isInt(const std::string &str) { return str.find_first_not_of("1234567890") == std::string::npos; } + +inline bool isBlank(const std::string &str) { + return str.find_first_not_of(" \n\t\v\r\f") == std::string::npos; +} diff --git a/include/foreach.hpp b/include/va_args_util.hpp similarity index 80% rename from include/foreach.hpp rename to include/va_args_util.hpp index c854ff1..27b766a 100644 --- a/include/foreach.hpp +++ b/include/va_args_util.hpp @@ -53,5 +53,20 @@ #define FE_49(WHAT, extra_arg, X, ...) WHAT(extra_arg, X)FE_48(WHAT, extra_arg, __VA_ARGS__) #define FE_50(WHAT, extra_arg, X, ...) WHAT(extra_arg, X)FE_49(WHAT, extra_arg, __VA_ARGS__) -#define GET_MACRO(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,NAME,...) NAME -#define FOR_EACH(action,extra_arg,...) GET_MACRO(_0,__VA_ARGS__,FE_50,FE_49,FE_48,FE_47,FE_46,FE_45,FE_44,FE_43,FE_42,FE_41,FE_40,FE_39,FE_38,FE_37,FE_36,FE_35,FE_34,FE_33,FE_32,FE_31,FE_30,FE_29,FE_28,FE_27,FE_26,FE_25,FE_24,FE_23,FE_22,FE_21,FE_20,FE_19,FE_18,FE_17,FE_16,FE_15,FE_14,FE_13,FE_12,FE_11,FE_10,FE_9,FE_8,FE_7,FE_6,FE_5,FE_4,FE_3,FE_2,FE_1,FE_0)(action,extra_arg,__VA_ARGS__) +#define NTH_ARG(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,NAME,...) NAME +#define FOR_EACH(action,extra_arg,...) NTH_ARG(_0,__VA_ARGS__,FE_50,FE_49,FE_48,FE_47,FE_46,FE_45,FE_44,FE_43,FE_42,FE_41,FE_40,FE_39,FE_38,FE_37,FE_36,FE_35,FE_34,FE_33,FE_32,FE_31,FE_30,FE_29,FE_28,FE_27,FE_26,FE_25,FE_24,FE_23,FE_22,FE_21,FE_20,FE_19,FE_18,FE_17,FE_16,FE_15,FE_14,FE_13,FE_12,FE_11,FE_10,FE_9,FE_8,FE_7,FE_6,FE_5,FE_4,FE_3,FE_2,FE_1,FE_0)(action,extra_arg,__VA_ARGS__) + +// https://stackoverflow.com/a/2124385 +#define ARG_COUNT(...) \ + ARG_COUNT_(__VA_ARGS__,FILLER()) +#define ARG_COUNT_(...) \ + NTH_ARG(__VA_ARGS__) +// one more than in NTH_ARG to get the count +// instead of the index of the last element +#define FILLER() \ + 51,50, \ + 49,48,47,46,45,44,43,42,41,40, \ + 39,38,37,36,35,34,33,32,31,30, \ + 29,28,27,26,25,24,23,22,21,20, \ + 19,18,17,16,15,14,13,12,11,10, \ + 9,8,7,6,5,4,3,2,1,0 diff --git a/src/osuparser.cpp b/src/osuparser.cpp index 29a94fc..5decc9a 100644 --- a/src/osuparser.cpp +++ b/src/osuparser.cpp @@ -49,6 +49,7 @@ inline std::string checkAndRemove(const std::string &str, const std::string &pre std::string _prefix;\ \ while (std::getline(configFile, line)) {\ + if (isBlank(line)) continue;\ /* remove \n*/\ line.pop_back();\ \ @@ -69,6 +70,22 @@ inline std::string checkAndRemove(const std::string &str, const std::string &pre __VA_ARGS__\ } +#define SECTION_LIST(name, type) \ + if (currentSection == #name) {\ + std::vector value;\ + std::stringstream ss(line);\ + ssize_t line_len = line.size();\ + type val;\ + while (ss >> val) {\ + std::getline(configFile, line);\ + ss = std::stringstream(line);\ + line_len = line.size();\ + value.push_back(val);\ + }\ + configFile.seekg(configFile.tellg() - line_len);\ + ret.name = value;\ + } + #define CHECK_VAR(section, name, ...) \ if (line.starts_with(_prefix)) {\ __VA_ARGS__\