From a908f39dde1dc8866bda1a85b8443ae4cdaaa2b4 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 21 Jun 2014 20:33:23 +0100 Subject: Rewrote furnace recipe parser * Fixes #110 --- src/FurnaceRecipe.cpp | 252 +++++++++++++++++++++++++++++++------------------- 1 file changed, 159 insertions(+), 93 deletions(-) (limited to 'src/FurnaceRecipe.cpp') diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp index bd7fd8079..b4b3d34d9 100644 --- a/src/FurnaceRecipe.cpp +++ b/src/FurnaceRecipe.cpp @@ -5,7 +5,8 @@ #include "Item.h" #include -#include + +#define FURNACE_RECIPE_FILE "furnace.txt" @@ -53,128 +54,193 @@ void cFurnaceRecipe::ReloadRecipes(void) ClearRecipes(); LOGD("Loading furnace recipes..."); - std::ifstream f; - char a_File[] = "furnace.txt"; - f.open(a_File, std::ios::in); - - if (!f.good()) + std::ifstream F(FURNACE_RECIPE_FILE, std::ios::in); + if (!F.good()) { - f.close(); - LOG("Could not open the furnace recipes file \"%s\"", a_File); + F.close(); + LOG("Could not open the furnace recipes file \"%s\"", FURNACE_RECIPE_FILE); return; } + + AString SyntaxError; + unsigned int Line = 0; + AString ParsingLine; - // TODO: Replace this messy parse with a high-level-structured one (ReadLine / ProcessLine) - bool bSyntaxError = false; - while (f.good()) - { - char c; + ASSERT(ParsingLine.empty()); - ////////////////////////////////////////////////////////////////////////// - // comments - f >> c; - f.unget(); - if( c == '#' ) + while (std::getline(F, ParsingLine)) + { + Line++; + ParsingLine.erase(std::remove_if(ParsingLine.begin(), ParsingLine.end(), isspace), ParsingLine.end()); // Remove whitespace + if (ParsingLine.empty()) { - while( f.good() && c != '\n' ) - { - f.get( c ); - } continue; } - - ////////////////////////////////////////////////////////////////////////// - // Line breaks - f.get( c ); - while( f.good() && ( c == '\n' || c == '\r' ) ) { f.get( c ); } - if (f.eof()) + // Comments + if (ParsingLine[0] == '#') { - break; + continue; } - f.unget(); - ////////////////////////////////////////////////////////////////////////// - // Check for fuel - f >> c; - if( c == '!' ) // It's fuel :) + if (ParsingLine[0] == '!') // Fuels start with a bang :) { - // Read item - int IItemID = 0, IItemCount = 0, IItemHealth = 0; - f >> IItemID; - f >> c; if( c != ':' ) { bSyntaxError = true; break; } - f >> IItemCount; - - // Optional health - f >> c; - if( c != ':' ) - f.unget(); - else + int IItemID = 0, IItemCount = 0, IItemHealth = 0, IBurnTime = 0; + AString::size_type BeginPos = 1; // Begin at one after exclamation mark (bang) + + if ( + !ReadMandatoryNumber(BeginPos, ":", ParsingLine, SyntaxError, Line, IItemID) || // Read item ID + !ReadOptionalNumbers(BeginPos, ":", "=", ParsingLine, SyntaxError, Line, IItemCount, IItemHealth) || // Read item count (and optionally health) + !ReadMandatoryNumber(BeginPos, "0123456789", ParsingLine, SyntaxError, Line, IBurnTime, true) // Read item burn time - last value + ) { - f >> IItemHealth; + break; } - // Burn time - int BurnTime; - f >> c; if( c != '=' ) { bSyntaxError = true; break; } - f >> BurnTime; - // Add to fuel list Fuel F; - F.In = new cItem( (ENUM_ITEM_ID) IItemID, (char)IItemCount, (short)IItemHealth ); - F.BurnTime = BurnTime; - m_pState->Fuel.push_back( F ); + F.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth); + F.BurnTime = IBurnTime; + m_pState->Fuel.push_back(F); + printf("%i %i %i %i\n", IItemID, IItemCount, IItemHealth, IBurnTime); continue; } - f.unget(); - - ////////////////////////////////////////////////////////////////////////// - // Read items - int IItemID = 0, IItemCount = 0, IItemHealth = 0; - f >> IItemID; - f >> c; if( c != ':' ) { bSyntaxError = true; break; } - f >> IItemCount; - - // Optional health - f >> c; - if( c != ':' ) - f.unget(); - else + else if (isdigit(ParsingLine[0])) // Recipes start with a numeral :) { - f >> IItemHealth; + int IItemID = 0, IItemCount = 0, IItemHealth = 0, IBurnTime = 0; + int OItemID = 0, OItemCount = 0, OItemHealth = 0; + AString::size_type BeginPos = 0; // Begin at start of line + + if ( + !ReadMandatoryNumber(BeginPos, ":", ParsingLine, SyntaxError, Line, IItemID) || // Read item ID + !ReadOptionalNumbers(BeginPos, ":", "@", ParsingLine, SyntaxError, Line, IItemCount, IItemHealth) || // Read item count (and optionally health) + !ReadMandatoryNumber(BeginPos, "=", ParsingLine, SyntaxError, Line, IBurnTime) || // Read item burn time + !ReadMandatoryNumber(BeginPos, ":", ParsingLine, SyntaxError, Line, OItemID) || // Read result ID + !ReadOptionalNumbers(BeginPos, ":", "012456789", ParsingLine, SyntaxError, Line, OItemCount, OItemHealth, true) // Read result count (and optionally health) - last value + ) + { + break; + } + + // Add to recipe list + Recipe R; + R.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth); + R.Out = new cItem((ENUM_ITEM_ID)OItemID, (char)OItemCount, (short)OItemHealth); + R.CookTime = IBurnTime; + m_pState->Recipes.push_back(R); } + } + F.close(); - int CookTime; - f >> c; if( c != '@' ) { bSyntaxError = true; break; } - f >> CookTime; + if (!SyntaxError.empty()) + { + LOGWARN("Error parsing furnace recipes at %s", SyntaxError.c_str()); + } + else + { + LOG("Loaded " SIZE_T_FMT " furnace recipes and " SIZE_T_FMT " fuels", m_pState->Recipes.size(), m_pState->Fuel.size()); + } +} - int OItemID = 0, OItemCount = 0, OItemHealth = 0; - f >> c; if( c != '=' ) { bSyntaxError = true; break; } - f >> OItemID; - f >> c; if( c != ':' ) { bSyntaxError = true; break; } - f >> OItemCount; - // Optional health - f >> c; - if( c != ':' ) - f.unget(); - else + + + +void cFurnaceRecipe::SetParseError(AString & a_ErrorString, unsigned int a_Line, size_t a_Position, const AString & a_CharactersMissing) +{ + Printf(a_ErrorString, "line %i pos %i: missing '%s'", a_Line, a_Position, a_CharactersMissing.c_str()); +} + + + + + +bool cFurnaceRecipe::ReadMandatoryNumber(AString::size_type & a_Begin, const AString & a_Delimiter, const AString & a_Text, AString & a_ErrorString, unsigned int a_Line, int & a_Value, bool a_IsLastValue) +{ + AString::size_type End; + if (a_IsLastValue) + { + End = a_Text.find_first_not_of(a_Delimiter, a_Begin); + } + else + { + End = a_Text.find_first_of(a_Delimiter, a_Begin); + if (End == AString::npos) { - f >> OItemHealth; + SetParseError(a_ErrorString, a_Line, a_Begin, a_Delimiter); + return false; } - - // Add to recipe list - Recipe R; - R.In = new cItem( (ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth ); - R.Out = new cItem( (ENUM_ITEM_ID)OItemID, (char)OItemCount, (short)OItemHealth ); - R.CookTime = CookTime; - m_pState->Recipes.push_back( R ); } - if (bSyntaxError) + + // stoi won't throw an exception if the string is alphanumeric, we should check for this + if (!DoesStringContainOnlyNumbers(a_Text.substr(a_Begin, End - a_Begin))) { - LOGERROR("ERROR: FurnaceRecipe, syntax error" ); + SetParseError(a_ErrorString, a_Line, a_Begin, "number"); + return false; + } + a_Value = std::stoi(a_Text.substr(a_Begin, End - a_Begin)); + + a_Begin = End + 1; // Jump over delimiter + return true; +} + + + + + +bool cFurnaceRecipe::ReadOptionalNumbers(AString::size_type & a_Begin, const AString & a_DelimiterOne, const AString & a_DelimiterTwo, const AString & a_Text, AString & a_ErrorString, unsigned int a_Line, int & a_ValueOne, int & a_ValueTwo, bool a_IsLastValue) +{ + unsigned int End, Begin = a_Begin; + + End = a_Text.find_first_of(a_DelimiterOne, Begin); + if (End != AString::npos) + { + if (DoesStringContainOnlyNumbers(a_Text.substr(Begin, End - Begin))) + { + a_ValueOne = std::stoi(a_Text.substr(Begin, End - Begin)); + Begin = End + 1; + + if (a_IsLastValue) + { + End = a_Text.find_first_not_of(a_DelimiterTwo, Begin); + } + else + { + End = a_Text.find_first_of(a_DelimiterTwo, Begin); + if (End == AString::npos) + { + SetParseError(a_ErrorString, a_Line, Begin, a_DelimiterTwo); + return false; + } + } + + // stoi won't throw an exception if the string is alphanumeric, we should check for this + if (!DoesStringContainOnlyNumbers(a_Text.substr(Begin, End - Begin))) + { + SetParseError(a_ErrorString, a_Line, Begin, "number"); + return false; + } + a_ValueTwo = std::stoi(a_Text.substr(Begin, End - Begin)); + + a_Begin = End + 1; // Jump over delimiter + return true; + } + else + { + return ReadMandatoryNumber(a_Begin, a_DelimiterTwo, a_Text, a_ErrorString, a_Line, a_ValueOne, a_IsLastValue); + } } - LOG("Loaded " SIZE_T_FMT " furnace recipes and " SIZE_T_FMT " fuels", m_pState->Recipes.size(), m_pState->Fuel.size()); + + return ReadMandatoryNumber(a_Begin, a_DelimiterTwo, a_Text, a_ErrorString, a_Line, a_ValueOne, a_IsLastValue); +} + + + + + +bool cFurnaceRecipe::DoesStringContainOnlyNumbers(const AString & a_String) +{ + return std::all_of(a_String.begin(), a_String.end(), isdigit); } -- cgit v1.2.3 From 537467fe25386a67ef5cb9a33b9806ac2db0c894 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 21 Jun 2014 20:35:28 +0100 Subject: Removed debugging code --- src/FurnaceRecipe.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/FurnaceRecipe.cpp') diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp index b4b3d34d9..ce9233bcc 100644 --- a/src/FurnaceRecipe.cpp +++ b/src/FurnaceRecipe.cpp @@ -102,7 +102,6 @@ void cFurnaceRecipe::ReloadRecipes(void) F.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth); F.BurnTime = IBurnTime; m_pState->Fuel.push_back(F); - printf("%i %i %i %i\n", IItemID, IItemCount, IItemHealth, IBurnTime); continue; } else if (isdigit(ParsingLine[0])) // Recipes start with a numeral :) -- cgit v1.2.3 From 4a01fba3aafef53ac8015bd5f6028fc677d6d245 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 22 Jun 2014 00:06:58 +0100 Subject: Suggestions --- src/FurnaceRecipe.cpp | 62 +++++++++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 36 deletions(-) (limited to 'src/FurnaceRecipe.cpp') diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp index ce9233bcc..448a4bfa8 100644 --- a/src/FurnaceRecipe.cpp +++ b/src/FurnaceRecipe.cpp @@ -54,21 +54,18 @@ void cFurnaceRecipe::ReloadRecipes(void) ClearRecipes(); LOGD("Loading furnace recipes..."); - std::ifstream F(FURNACE_RECIPE_FILE, std::ios::in); - if (!F.good()) + std::ifstream f(FURNACE_RECIPE_FILE, std::ios::in); + if (!f.good()) { - F.close(); + f.close(); LOG("Could not open the furnace recipes file \"%s\"", FURNACE_RECIPE_FILE); return; } - AString SyntaxError; unsigned int Line = 0; AString ParsingLine; - ASSERT(ParsingLine.empty()); - - while (std::getline(F, ParsingLine)) + while (std::getline(f, ParsingLine)) { Line++; ParsingLine.erase(std::remove_if(ParsingLine.begin(), ParsingLine.end(), isspace), ParsingLine.end()); // Remove whitespace @@ -89,12 +86,12 @@ void cFurnaceRecipe::ReloadRecipes(void) AString::size_type BeginPos = 1; // Begin at one after exclamation mark (bang) if ( - !ReadMandatoryNumber(BeginPos, ":", ParsingLine, SyntaxError, Line, IItemID) || // Read item ID - !ReadOptionalNumbers(BeginPos, ":", "=", ParsingLine, SyntaxError, Line, IItemCount, IItemHealth) || // Read item count (and optionally health) - !ReadMandatoryNumber(BeginPos, "0123456789", ParsingLine, SyntaxError, Line, IBurnTime, true) // Read item burn time - last value + !ReadMandatoryNumber(BeginPos, ":", ParsingLine, Line, IItemID) || // Read item ID + !ReadOptionalNumbers(BeginPos, ":", "=", ParsingLine, Line, IItemCount, IItemHealth) || // Read item count (and optionally health) + !ReadMandatoryNumber(BeginPos, "0123456789", ParsingLine, Line, IBurnTime, true) // Read item burn time - last value ) { - break; + return; } // Add to fuel list @@ -111,14 +108,14 @@ void cFurnaceRecipe::ReloadRecipes(void) AString::size_type BeginPos = 0; // Begin at start of line if ( - !ReadMandatoryNumber(BeginPos, ":", ParsingLine, SyntaxError, Line, IItemID) || // Read item ID - !ReadOptionalNumbers(BeginPos, ":", "@", ParsingLine, SyntaxError, Line, IItemCount, IItemHealth) || // Read item count (and optionally health) - !ReadMandatoryNumber(BeginPos, "=", ParsingLine, SyntaxError, Line, IBurnTime) || // Read item burn time - !ReadMandatoryNumber(BeginPos, ":", ParsingLine, SyntaxError, Line, OItemID) || // Read result ID - !ReadOptionalNumbers(BeginPos, ":", "012456789", ParsingLine, SyntaxError, Line, OItemCount, OItemHealth, true) // Read result count (and optionally health) - last value + !ReadMandatoryNumber(BeginPos, ":", ParsingLine, Line, IItemID) || // Read item ID + !ReadOptionalNumbers(BeginPos, ":", "@", ParsingLine, Line, IItemCount, IItemHealth) || // Read item count (and optionally health) + !ReadMandatoryNumber(BeginPos, "=", ParsingLine, Line, IBurnTime) || // Read item burn time + !ReadMandatoryNumber(BeginPos, ":", ParsingLine, Line, OItemID) || // Read result ID + !ReadOptionalNumbers(BeginPos, ":", "012456789", ParsingLine, Line, OItemCount, OItemHealth, true) // Read result count (and optionally health) - last value ) { - break; + return; } // Add to recipe list @@ -129,32 +126,25 @@ void cFurnaceRecipe::ReloadRecipes(void) m_pState->Recipes.push_back(R); } } - F.close(); + f.close(); - if (!SyntaxError.empty()) - { - LOGWARN("Error parsing furnace recipes at %s", SyntaxError.c_str()); - } - else - { - LOG("Loaded " SIZE_T_FMT " furnace recipes and " SIZE_T_FMT " fuels", m_pState->Recipes.size(), m_pState->Fuel.size()); - } + LOG("Loaded " SIZE_T_FMT " furnace recipes and " SIZE_T_FMT " fuels", m_pState->Recipes.size(), m_pState->Fuel.size()); } -void cFurnaceRecipe::SetParseError(AString & a_ErrorString, unsigned int a_Line, size_t a_Position, const AString & a_CharactersMissing) +void cFurnaceRecipe::PrintParseError(unsigned int a_Line, size_t a_Position, const AString & a_CharactersMissing) { - Printf(a_ErrorString, "line %i pos %i: missing '%s'", a_Line, a_Position, a_CharactersMissing.c_str()); + LOGWARN("Error parsing furnace recipes at line %i pos %i: missing '%s'", a_Line, a_Position, a_CharactersMissing.c_str()); } -bool cFurnaceRecipe::ReadMandatoryNumber(AString::size_type & a_Begin, const AString & a_Delimiter, const AString & a_Text, AString & a_ErrorString, unsigned int a_Line, int & a_Value, bool a_IsLastValue) +bool cFurnaceRecipe::ReadMandatoryNumber(AString::size_type & a_Begin, const AString & a_Delimiter, const AString & a_Text, unsigned int a_Line, int & a_Value, bool a_IsLastValue) { AString::size_type End; if (a_IsLastValue) @@ -166,7 +156,7 @@ bool cFurnaceRecipe::ReadMandatoryNumber(AString::size_type & a_Begin, const ASt End = a_Text.find_first_of(a_Delimiter, a_Begin); if (End == AString::npos) { - SetParseError(a_ErrorString, a_Line, a_Begin, a_Delimiter); + PrintParseError(a_Line, a_Begin, a_Delimiter); return false; } } @@ -174,7 +164,7 @@ bool cFurnaceRecipe::ReadMandatoryNumber(AString::size_type & a_Begin, const ASt // stoi won't throw an exception if the string is alphanumeric, we should check for this if (!DoesStringContainOnlyNumbers(a_Text.substr(a_Begin, End - a_Begin))) { - SetParseError(a_ErrorString, a_Line, a_Begin, "number"); + PrintParseError(a_Line, a_Begin, "number"); return false; } a_Value = std::stoi(a_Text.substr(a_Begin, End - a_Begin)); @@ -187,7 +177,7 @@ bool cFurnaceRecipe::ReadMandatoryNumber(AString::size_type & a_Begin, const ASt -bool cFurnaceRecipe::ReadOptionalNumbers(AString::size_type & a_Begin, const AString & a_DelimiterOne, const AString & a_DelimiterTwo, const AString & a_Text, AString & a_ErrorString, unsigned int a_Line, int & a_ValueOne, int & a_ValueTwo, bool a_IsLastValue) +bool cFurnaceRecipe::ReadOptionalNumbers(AString::size_type & a_Begin, const AString & a_DelimiterOne, const AString & a_DelimiterTwo, const AString & a_Text, unsigned int a_Line, int & a_ValueOne, int & a_ValueTwo, bool a_IsLastValue) { unsigned int End, Begin = a_Begin; @@ -208,7 +198,7 @@ bool cFurnaceRecipe::ReadOptionalNumbers(AString::size_type & a_Begin, const ASt End = a_Text.find_first_of(a_DelimiterTwo, Begin); if (End == AString::npos) { - SetParseError(a_ErrorString, a_Line, Begin, a_DelimiterTwo); + PrintParseError(a_Line, Begin, a_DelimiterTwo); return false; } } @@ -216,7 +206,7 @@ bool cFurnaceRecipe::ReadOptionalNumbers(AString::size_type & a_Begin, const ASt // stoi won't throw an exception if the string is alphanumeric, we should check for this if (!DoesStringContainOnlyNumbers(a_Text.substr(Begin, End - Begin))) { - SetParseError(a_ErrorString, a_Line, Begin, "number"); + PrintParseError(a_Line, Begin, "number"); return false; } a_ValueTwo = std::stoi(a_Text.substr(Begin, End - Begin)); @@ -226,11 +216,11 @@ bool cFurnaceRecipe::ReadOptionalNumbers(AString::size_type & a_Begin, const ASt } else { - return ReadMandatoryNumber(a_Begin, a_DelimiterTwo, a_Text, a_ErrorString, a_Line, a_ValueOne, a_IsLastValue); + return ReadMandatoryNumber(a_Begin, a_DelimiterTwo, a_Text, a_Line, a_ValueOne, a_IsLastValue); } } - return ReadMandatoryNumber(a_Begin, a_DelimiterTwo, a_Text, a_ErrorString, a_Line, a_ValueOne, a_IsLastValue); + return ReadMandatoryNumber(a_Begin, a_DelimiterTwo, a_Text, a_Line, a_ValueOne, a_IsLastValue); } -- cgit v1.2.3 From 63ce2e8b37444f96d7892d555cb296947b3afbe5 Mon Sep 17 00:00:00 2001 From: worktycho Date: Sun, 22 Jun 2014 12:30:37 +0100 Subject: Fixed compile errors --- src/FurnaceRecipe.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/FurnaceRecipe.cpp') diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp index 448a4bfa8..8040552cc 100644 --- a/src/FurnaceRecipe.cpp +++ b/src/FurnaceRecipe.cpp @@ -137,7 +137,7 @@ void cFurnaceRecipe::ReloadRecipes(void) void cFurnaceRecipe::PrintParseError(unsigned int a_Line, size_t a_Position, const AString & a_CharactersMissing) { - LOGWARN("Error parsing furnace recipes at line %i pos %i: missing '%s'", a_Line, a_Position, a_CharactersMissing.c_str()); + LOGWARN("Error parsing furnace recipes at line %i pos " SIZE_T_FMT ": missing '%s'", a_Line, a_Position, a_CharactersMissing.c_str()); } @@ -179,7 +179,7 @@ bool cFurnaceRecipe::ReadMandatoryNumber(AString::size_type & a_Begin, const ASt bool cFurnaceRecipe::ReadOptionalNumbers(AString::size_type & a_Begin, const AString & a_DelimiterOne, const AString & a_DelimiterTwo, const AString & a_Text, unsigned int a_Line, int & a_ValueOne, int & a_ValueTwo, bool a_IsLastValue) { - unsigned int End, Begin = a_Begin; + AString::size_type End, Begin = a_Begin; End = a_Text.find_first_of(a_DelimiterOne, Begin); if (End != AString::npos) -- cgit v1.2.3 From c476fc3cf5a2bbdb27b61fcad290c84029721462 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 22 Jun 2014 21:49:37 +0100 Subject: Suggestions --- src/FurnaceRecipe.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/FurnaceRecipe.cpp') diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp index 448a4bfa8..90b478285 100644 --- a/src/FurnaceRecipe.cpp +++ b/src/FurnaceRecipe.cpp @@ -57,7 +57,6 @@ void cFurnaceRecipe::ReloadRecipes(void) std::ifstream f(FURNACE_RECIPE_FILE, std::ios::in); if (!f.good()) { - f.close(); LOG("Could not open the furnace recipes file \"%s\"", FURNACE_RECIPE_FILE); return; } @@ -126,7 +125,6 @@ void cFurnaceRecipe::ReloadRecipes(void) m_pState->Recipes.push_back(R); } } - f.close(); LOG("Loaded " SIZE_T_FMT " furnace recipes and " SIZE_T_FMT " fuels", m_pState->Recipes.size(), m_pState->Fuel.size()); } @@ -146,6 +144,7 @@ void cFurnaceRecipe::PrintParseError(unsigned int a_Line, size_t a_Position, con bool cFurnaceRecipe::ReadMandatoryNumber(AString::size_type & a_Begin, const AString & a_Delimiter, const AString & a_Text, unsigned int a_Line, int & a_Value, bool a_IsLastValue) { + // TODO: replace atoi with std::stoi AString::size_type End; if (a_IsLastValue) { @@ -167,7 +166,7 @@ bool cFurnaceRecipe::ReadMandatoryNumber(AString::size_type & a_Begin, const ASt PrintParseError(a_Line, a_Begin, "number"); return false; } - a_Value = std::stoi(a_Text.substr(a_Begin, End - a_Begin)); + a_Value = atoi(a_Text.substr(a_Begin, End - a_Begin).c_str()); a_Begin = End + 1; // Jump over delimiter return true; @@ -179,6 +178,7 @@ bool cFurnaceRecipe::ReadMandatoryNumber(AString::size_type & a_Begin, const ASt bool cFurnaceRecipe::ReadOptionalNumbers(AString::size_type & a_Begin, const AString & a_DelimiterOne, const AString & a_DelimiterTwo, const AString & a_Text, unsigned int a_Line, int & a_ValueOne, int & a_ValueTwo, bool a_IsLastValue) { + // TODO: replace atoi with std::stoi unsigned int End, Begin = a_Begin; End = a_Text.find_first_of(a_DelimiterOne, Begin); @@ -186,7 +186,7 @@ bool cFurnaceRecipe::ReadOptionalNumbers(AString::size_type & a_Begin, const ASt { if (DoesStringContainOnlyNumbers(a_Text.substr(Begin, End - Begin))) { - a_ValueOne = std::stoi(a_Text.substr(Begin, End - Begin)); + a_ValueOne = std::atoi(a_Text.substr(Begin, End - Begin).c_str()); Begin = End + 1; if (a_IsLastValue) @@ -209,7 +209,7 @@ bool cFurnaceRecipe::ReadOptionalNumbers(AString::size_type & a_Begin, const ASt PrintParseError(a_Line, Begin, "number"); return false; } - a_ValueTwo = std::stoi(a_Text.substr(Begin, End - Begin)); + a_ValueTwo = atoi(a_Text.substr(Begin, End - Begin).c_str()); a_Begin = End + 1; // Jump over delimiter return true; @@ -229,7 +229,8 @@ bool cFurnaceRecipe::ReadOptionalNumbers(AString::size_type & a_Begin, const ASt bool cFurnaceRecipe::DoesStringContainOnlyNumbers(const AString & a_String) { - return std::all_of(a_String.begin(), a_String.end(), isdigit); + // TODO: replace this with std::all_of(a_String.begin(), a_String.end(), isdigit) + return a_String.find_first_not_of("0123456789") == AString::npos; } -- cgit v1.2.3 From 7a236921319c44de38246ff73d5343e174dd560f Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Mon, 23 Jun 2014 17:40:51 +0100 Subject: Parenthesised comparison --- src/FurnaceRecipe.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/FurnaceRecipe.cpp') diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp index d53854950..36dd2d5e9 100644 --- a/src/FurnaceRecipe.cpp +++ b/src/FurnaceRecipe.cpp @@ -230,7 +230,7 @@ bool cFurnaceRecipe::ReadOptionalNumbers(AString::size_type & a_Begin, const ASt bool cFurnaceRecipe::DoesStringContainOnlyNumbers(const AString & a_String) { // TODO: replace this with std::all_of(a_String.begin(), a_String.end(), isdigit) - return a_String.find_first_not_of("0123456789") == AString::npos; + return (a_String.find_first_not_of("0123456789") == AString::npos); } -- cgit v1.2.3 From b90b0a1dffff366df639f49445afb43ae1a8a73c Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 26 Jun 2014 17:51:19 +0200 Subject: FurnaceRecipe parser: Added an else branch, changed to a switch. --- src/FurnaceRecipe.cpp | 114 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 69 insertions(+), 45 deletions(-) (limited to 'src/FurnaceRecipe.cpp') diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp index 92b52c6e8..f8949d45f 100644 --- a/src/FurnaceRecipe.cpp +++ b/src/FurnaceRecipe.cpp @@ -68,64 +68,88 @@ void cFurnaceRecipe::ReloadRecipes(void) while (std::getline(f, ParsingLine)) { Line++; - ParsingLine.erase(std::remove_if(ParsingLine.begin(), ParsingLine.end(), isspace), ParsingLine.end()); // Remove whitespace + TrimString(ParsingLine); if (ParsingLine.empty()) { continue; } - // Comments - if (ParsingLine[0] == '#') + switch (ParsingLine[0]) { - continue; - } - - if (ParsingLine[0] == '!') // Fuels start with a bang :) - { - int IItemID = 0, IItemCount = 0, IItemHealth = 0, IBurnTime = 0; - AString::size_type BeginPos = 1; // Begin at one after exclamation mark (bang) - - if ( - !ReadMandatoryNumber(BeginPos, ":", ParsingLine, Line, IItemID) || // Read item ID - !ReadOptionalNumbers(BeginPos, ":", "=", ParsingLine, Line, IItemCount, IItemHealth) || // Read item count (and optionally health) - !ReadMandatoryNumber(BeginPos, "0123456789", ParsingLine, Line, IBurnTime, true) // Read item burn time - last value - ) + case '#': { - return; + // Comment + break; } - // Add to fuel list - Fuel F; - F.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth); - F.BurnTime = IBurnTime; - m_pState->Fuel.push_back(F); - continue; - } - else if (isdigit(ParsingLine[0])) // Recipes start with a numeral :) - { - int IItemID = 0, IItemCount = 0, IItemHealth = 0, IBurnTime = 0; - int OItemID = 0, OItemCount = 0, OItemHealth = 0; - AString::size_type BeginPos = 0; // Begin at start of line - - if ( - !ReadMandatoryNumber(BeginPos, ":", ParsingLine, Line, IItemID) || // Read item ID - !ReadOptionalNumbers(BeginPos, ":", "@", ParsingLine, Line, IItemCount, IItemHealth) || // Read item count (and optionally health) - !ReadMandatoryNumber(BeginPos, "=", ParsingLine, Line, IBurnTime) || // Read item burn time - !ReadMandatoryNumber(BeginPos, ":", ParsingLine, Line, OItemID) || // Read result ID - !ReadOptionalNumbers(BeginPos, ":", "012456789", ParsingLine, Line, OItemCount, OItemHealth, true) // Read result count (and optionally health) - last value + case '!': + { + // Fuel + int IItemID = 0, IItemCount = 0, IItemHealth = 0, IBurnTime = 0; + AString::size_type BeginPos = 1; // Begin at one after exclamation mark (bang) + + if ( + !ReadMandatoryNumber(BeginPos, ":", ParsingLine, Line, IItemID) || // Read item ID + !ReadOptionalNumbers(BeginPos, ":", "=", ParsingLine, Line, IItemCount, IItemHealth) || // Read item count (and optionally health) + !ReadMandatoryNumber(BeginPos, "0123456789", ParsingLine, Line, IBurnTime, true) // Read item burn time - last value ) + { + return; + } + + // Add to fuel list: + Fuel F; + F.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth); + F.BurnTime = IBurnTime; + m_pState->Fuel.push_back(F); + break; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { - return; + // Recipe + int IItemID = 0, IItemCount = 0, IItemHealth = 0, IBurnTime = 0; + int OItemID = 0, OItemCount = 0, OItemHealth = 0; + AString::size_type BeginPos = 0; // Begin at start of line + + if ( + !ReadMandatoryNumber(BeginPos, ":", ParsingLine, Line, IItemID) || // Read item ID + !ReadOptionalNumbers(BeginPos, ":", "@", ParsingLine, Line, IItemCount, IItemHealth) || // Read item count (and optionally health) + !ReadMandatoryNumber(BeginPos, "=", ParsingLine, Line, IBurnTime) || // Read item burn time + !ReadMandatoryNumber(BeginPos, ":", ParsingLine, Line, OItemID) || // Read result ID + !ReadOptionalNumbers(BeginPos, ":", "012456789", ParsingLine, Line, OItemCount, OItemHealth, true) // Read result count (and optionally health) - last value + ) + { + return; + } + + // Add to recipe list + Recipe R; + R.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth); + R.Out = new cItem((ENUM_ITEM_ID)OItemID, (char)OItemCount, (short)OItemHealth); + R.CookTime = IBurnTime; + m_pState->Recipes.push_back(R); + break; } - // Add to recipe list - Recipe R; - R.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth); - R.Out = new cItem((ENUM_ITEM_ID)OItemID, (char)OItemCount, (short)OItemHealth); - R.CookTime = IBurnTime; - m_pState->Recipes.push_back(R); - } - } + default: + { + LOGWARNING("Error in furnace recipes at line %d: Unexpected text: \"%s\". Ignoring line.", + Line, ParsingLine.c_str() + ); + break; + } + } // switch (ParsingLine[0]) + } // while (getline(ParsingLine)) LOG("Loaded " SIZE_T_FMT " furnace recipes and " SIZE_T_FMT " fuels", m_pState->Recipes.size(), m_pState->Fuel.size()); } -- cgit v1.2.3 From 67e3c645d3a648ebd4d797019a993ed9c27cdb5e Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 26 Jun 2014 17:52:37 +0200 Subject: FurnaceRecipe parser: Made the parser more forgiving. Errors don't cause a stop in the parsing, but rather just skip the offending line. --- src/FurnaceRecipe.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/FurnaceRecipe.cpp') diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp index f8949d45f..eff09a8d3 100644 --- a/src/FurnaceRecipe.cpp +++ b/src/FurnaceRecipe.cpp @@ -94,7 +94,7 @@ void cFurnaceRecipe::ReloadRecipes(void) !ReadMandatoryNumber(BeginPos, "0123456789", ParsingLine, Line, IBurnTime, true) // Read item burn time - last value ) { - return; + break; } // Add to fuel list: @@ -129,7 +129,7 @@ void cFurnaceRecipe::ReloadRecipes(void) !ReadOptionalNumbers(BeginPos, ":", "012456789", ParsingLine, Line, OItemCount, OItemHealth, true) // Read result count (and optionally health) - last value ) { - return; + break; } // Add to recipe list -- cgit v1.2.3 From 55bbdfa5d44a4bf7e66aa256ceba9ded3d2682dd Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 26 Jun 2014 18:18:41 +0200 Subject: FurnaceRecipe: Moved the parsing into separate functions for clarity. --- src/FurnaceRecipe.cpp | 120 +++++++++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 60 deletions(-) (limited to 'src/FurnaceRecipe.cpp') diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp index eff09a8d3..cc4098607 100644 --- a/src/FurnaceRecipe.cpp +++ b/src/FurnaceRecipe.cpp @@ -58,16 +58,16 @@ void cFurnaceRecipe::ReloadRecipes(void) std::ifstream f(FURNACE_RECIPE_FILE, std::ios::in); if (!f.good()) { - LOG("Could not open the furnace recipes file \"%s\"", FURNACE_RECIPE_FILE); + LOG("Could not open the furnace recipes file \"%s\". No furnace recipes are available.", FURNACE_RECIPE_FILE); return; } - unsigned int Line = 0; + unsigned int LineNum = 0; AString ParsingLine; while (std::getline(f, ParsingLine)) { - Line++; + LineNum++; TrimString(ParsingLine); if (ParsingLine.empty()) { @@ -84,68 +84,13 @@ void cFurnaceRecipe::ReloadRecipes(void) case '!': { - // Fuel - int IItemID = 0, IItemCount = 0, IItemHealth = 0, IBurnTime = 0; - AString::size_type BeginPos = 1; // Begin at one after exclamation mark (bang) - - if ( - !ReadMandatoryNumber(BeginPos, ":", ParsingLine, Line, IItemID) || // Read item ID - !ReadOptionalNumbers(BeginPos, ":", "=", ParsingLine, Line, IItemCount, IItemHealth) || // Read item count (and optionally health) - !ReadMandatoryNumber(BeginPos, "0123456789", ParsingLine, Line, IBurnTime, true) // Read item burn time - last value - ) - { - break; - } - - // Add to fuel list: - Fuel F; - F.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth); - F.BurnTime = IBurnTime; - m_pState->Fuel.push_back(F); - break; - } - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - // Recipe - int IItemID = 0, IItemCount = 0, IItemHealth = 0, IBurnTime = 0; - int OItemID = 0, OItemCount = 0, OItemHealth = 0; - AString::size_type BeginPos = 0; // Begin at start of line - - if ( - !ReadMandatoryNumber(BeginPos, ":", ParsingLine, Line, IItemID) || // Read item ID - !ReadOptionalNumbers(BeginPos, ":", "@", ParsingLine, Line, IItemCount, IItemHealth) || // Read item count (and optionally health) - !ReadMandatoryNumber(BeginPos, "=", ParsingLine, Line, IBurnTime) || // Read item burn time - !ReadMandatoryNumber(BeginPos, ":", ParsingLine, Line, OItemID) || // Read result ID - !ReadOptionalNumbers(BeginPos, ":", "012456789", ParsingLine, Line, OItemCount, OItemHealth, true) // Read result count (and optionally health) - last value - ) - { - break; - } - - // Add to recipe list - Recipe R; - R.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth); - R.Out = new cItem((ENUM_ITEM_ID)OItemID, (char)OItemCount, (short)OItemHealth); - R.CookTime = IBurnTime; - m_pState->Recipes.push_back(R); + AddFuelFromLine(ParsingLine, LineNum); break; } default: { - LOGWARNING("Error in furnace recipes at line %d: Unexpected text: \"%s\". Ignoring line.", - Line, ParsingLine.c_str() - ); + AddRecipeFromLine(ParsingLine, LineNum); break; } } // switch (ParsingLine[0]) @@ -158,6 +103,61 @@ void cFurnaceRecipe::ReloadRecipes(void) +void cFurnaceRecipe::AddFuelFromLine(const AString & a_Line, int a_LineNum) +{ + // Fuel + int IItemID = 0, IItemCount = 0, IItemHealth = 0, IBurnTime = 0; + AString::size_type BeginPos = 1; // Begin at one after exclamation mark (bang) + + if ( + !ReadMandatoryNumber(BeginPos, ":", a_Line, a_LineNum, IItemID) || // Read item ID + !ReadOptionalNumbers(BeginPos, ":", "=", a_Line, a_LineNum, IItemCount, IItemHealth) || // Read item count (and optionally health) + !ReadMandatoryNumber(BeginPos, "0123456789", a_Line, a_LineNum, IBurnTime, true) // Read item burn time - last value + ) + { + return; + } + + // Add to fuel list: + Fuel F; + F.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth); + F.BurnTime = IBurnTime; + m_pState->Fuel.push_back(F); +} + + + + + +void cFurnaceRecipe::AddRecipeFromLine(const AString & a_Line, int a_LineNum) +{ + int IItemID = 0, IItemCount = 0, IItemHealth = 0, IBurnTime = 0; + int OItemID = 0, OItemCount = 0, OItemHealth = 0; + AString::size_type BeginPos = 0; // Begin at start of line + + if ( + !ReadMandatoryNumber(BeginPos, ":", a_Line, a_LineNum, IItemID) || // Read item ID + !ReadOptionalNumbers(BeginPos, ":", "@", a_Line, a_LineNum, IItemCount, IItemHealth) || // Read item count (and optionally health) + !ReadMandatoryNumber(BeginPos, "=", a_Line, a_LineNum, IBurnTime) || // Read item burn time + !ReadMandatoryNumber(BeginPos, ":", a_Line, a_LineNum, OItemID) || // Read result ID + !ReadOptionalNumbers(BeginPos, ":", "012456789", a_Line, a_LineNum, OItemCount, OItemHealth, true) // Read result count (and optionally health) - last value + ) + { + return; + } + + // Add to recipe list + Recipe R; + R.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth); + R.Out = new cItem((ENUM_ITEM_ID)OItemID, (char)OItemCount, (short)OItemHealth); + R.CookTime = IBurnTime; + m_pState->Recipes.push_back(R); +} + + + + + void cFurnaceRecipe::PrintParseError(unsigned int a_Line, size_t a_Position, const AString & a_CharactersMissing) { LOGWARN("Error parsing furnace recipes at line %i pos " SIZE_T_FMT ": missing '%s'", a_Line, a_Position, a_CharactersMissing.c_str()); -- cgit v1.2.3 From ec1015112c969798bae3efe87998c17d130b271a Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 26 Jun 2014 18:20:12 +0200 Subject: Fixed misformed trimming. --- src/FurnaceRecipe.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/FurnaceRecipe.cpp') diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp index cc4098607..412402cbc 100644 --- a/src/FurnaceRecipe.cpp +++ b/src/FurnaceRecipe.cpp @@ -68,7 +68,7 @@ void cFurnaceRecipe::ReloadRecipes(void) while (std::getline(f, ParsingLine)) { LineNum++; - TrimString(ParsingLine); + ParsingLine = TrimString(ParsingLine); if (ParsingLine.empty()) { continue; -- cgit v1.2.3 From 0df644c9f7775862c6c359b238e3440536092e04 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 26 Jun 2014 18:28:10 +0200 Subject: FurnaceRecipe parsing: Fixed whitespace removing. --- src/FurnaceRecipe.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/FurnaceRecipe.cpp') diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp index 412402cbc..8add9610c 100644 --- a/src/FurnaceRecipe.cpp +++ b/src/FurnaceRecipe.cpp @@ -68,7 +68,7 @@ void cFurnaceRecipe::ReloadRecipes(void) while (std::getline(f, ParsingLine)) { LineNum++; - ParsingLine = TrimString(ParsingLine); + ParsingLine.erase(std::remove_if(ParsingLine.begin(), ParsingLine.end(), isspace), ParsingLine.end()); // Remove ALL whitespace from the line if (ParsingLine.empty()) { continue; -- cgit v1.2.3