refactor(ini): Make the INI code cleaner and more consistent#2596
refactor(ini): Make the INI code cleaner and more consistent#2596Caball009 wants to merge 7 commits intoTheSuperHackers:mainfrom
Conversation
|
| Filename | Overview |
|---|---|
| Core/GameEngine/Include/Common/INI.h | Central class interface change: 5 separator/end-token member variables removed and replaced with static methods; getNextToken/getNextTokenOrNull/getNextSubToken promoted to static; destructor declaration removed; copy-protection declarations removed without = delete replacement (flagged separately). |
| Core/GameEngine/Source/Common/INI/INI.cpp | Implementation updated to match header: member variable initializations removed, empty destructor removed, m_seps/m_blockEndToken references replaced with static calls, while→for loop conversions, token != nullptr → token simplifications, and constexpr added to local SEPS constant. |
| Generals/Code/GameEngine/Source/GameLogic/Object/Update/AutoDepositUpdate.cpp | getNextTokenOrNull + manual null-check + throw replaced with getNextToken (which throws internally); semantically equivalent and cleaner. |
| GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/OCLUpdate.cpp | Same getNextTokenOrNull + null-check + throw → getNextToken simplification as AutoDepositUpdate.cpp; only present in GeneralsMD version. |
| Generals/Code/GameEngine/Source/GameLogic/Object/ObjectCreationList.cpp | Loop variable renamed debrisName→token; double-advance pattern preserved unchanged (pre-existing behavior, separate PR planned per prior thread). |
Class Diagram
%%{init: {'theme': 'neutral'}}%%
classDiagram
class INI_Before {
-const char* m_seps
-const char* m_sepsPercent
-const char* m_sepsColon
-const char* m_sepsQuote
-const char* m_blockEndToken
+getSeps() const char*
+getSepsPercent() const char*
+getSepsColon() const char*
+getSepsQuote() const char*
+getNextToken(seps=nullptr) const char*
+getNextTokenOrNull(seps=nullptr) const char*
+getNextSubToken(expected) const char*
~INI()
}
class INI_After {
+getSeps()$ const char*
+getSepsPercent()$ const char*
+getSepsColon()$ const char*
+getSepsQuote()$ const char*
+getEndToken()$ const char*
+getNextToken(seps=getSeps())$ const char*
+getNextTokenOrNull(seps=getSeps())$ const char*
+getNextSubToken(expected)$ const char*
}
note for INI_After "$ = static\nMember vars removed\nDestructor is compiler-generated"
Reviews (3): Last reviewed commit: "Fixed forgotten change." | Re-trigger Greptile
| INI(const INI&); | ||
| INI& operator=(const INI&); | ||
|
|
||
| public: |
There was a problem hiding this comment.
Missing
= delete for copy/assignment after removing private declarations
The PR removes the private INI(const INI&) / INI& operator=(const INI&) declarations without replacing them with = delete. m_readBuffer is heap-allocated (file->readEntireAndClose()) and released via delete[] m_readBuffer in unPrepFile(). With no copy protection, the compiler will generate a shallow-copy constructor and assignment operator, meaning two INI instances could share the same m_readBuffer pointer. When either calls unPrepFile(), the other is left with a dangling pointer — use-after-free or double-delete follows.
// Suggested fix — add in the public or class body:
INI(const INI&) = delete;
INI& operator=(const INI&) = delete;Prompt To Fix With AI
This is a comment left during a code review.
Path: Core/GameEngine/Include/Common/INI.h
Line: 163
Comment:
**Missing `= delete` for copy/assignment after removing private declarations**
The PR removes the private `INI(const INI&)` / `INI& operator=(const INI&)` declarations without replacing them with `= delete`. `m_readBuffer` is heap-allocated (`file->readEntireAndClose()`) and released via `delete[] m_readBuffer` in `unPrepFile()`. With no copy protection, the compiler will generate a shallow-copy constructor and assignment operator, meaning two INI instances could share the same `m_readBuffer` pointer. When either calls `unPrepFile()`, the other is left with a dangling pointer — use-after-free or double-delete follows.
```cpp
// Suggested fix — add in the public or class body:
INI(const INI&) = delete;
INI& operator=(const INI&) = delete;
```
How can I resolve this? If you propose a fix, please make it concise.|
|
||
| this will *never* return null; if there are no more tokens, an exception will be thrown. | ||
| */ | ||
| const char* getNextToken(const char* seps = nullptr); |
There was a problem hiding this comment.
I wonder if we should only have one token retrieving function and let external code handle an invalid return depending on where the check is being performed, i don't like the idea of it just throwing an error due to a malformed ini, it should more gracefully handle it and warn the user.
There was a problem hiding this comment.
Yeah, maybe, but would require a larger change.
I'm working on a large overhaul of the INI code, but it's a significant endeavor so I'm not sure it'll work out.
There was a problem hiding this comment.
No worries, it's just nasty that the original token retrieval code throws in the first place.
| class INI | ||
| { | ||
| INI(const INI&); | ||
| INI& operator=(const INI&); |
There was a problem hiding this comment.
prob best to keep the copy and copy move constructors private.
There was a problem hiding this comment.
the INI class is not a simple class, it has internal data handled on the heap.
The default copy constructor will only make a shallow copy of the INI, so if the original is deleted the pointed at memory in m_framebuffer will dangle to invalid memory.
the manual destructor tbh should remain but also call unprep to clear the frame buffer too.
|
|
||
| //------------------------------------------------------------------------------------------------- | ||
| /*static*/ const char* INI::getNextToken(const char* seps) | ||
| /*static*/ const char* INI::getNextToken(const char* seps /*= getSeps()*/) |
There was a problem hiding this comment.
No need to block comment the default argument.
| { | ||
| SlowDeathBehaviorModuleData* self = (SlowDeathBehaviorModuleData*)instance; | ||
| SlowDeathPhaseType sdphase = (SlowDeathPhaseType)INI::scanIndexList(ini->getNextToken(), TheSlowDeathPhaseNames); | ||
| for (const char* token = ini->getNextToken(); token != nullptr; token = ini->getNextTokenOrNull()) |
| const char* SEPS = " \t,="; | ||
| const char *c = ini->getNextTokenOrNull(SEPS); | ||
| while ( c ) | ||
| constexpr const char* SEPS = " \t,="; |
A handful of miscellaneous changes to the INI code. Should have zero change in behavior.
Generals and Zero Hour code are not separated, but the commit diffs are pretty clean.