Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 10 additions & 20 deletions Core/GameEngine/Include/Common/INI.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,8 @@ typedef void (*BuildMultiIniFieldProc)(MultiIniFieldParse& p);
//-------------------------------------------------------------------------------------------------
class INI
{
INI(const INI&);
INI& operator=(const INI&);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prob best to keep the copy and copy move constructors private.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is that?

Copy link
Copy Markdown

@Mauller Mauller Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

greptile also warned about that.


public:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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.


INI();
~INI();

// TheSuperHackers @feature xezon 19/08/2025
// Load a specific INI file by name and/or INI files from a directory (and its subdirectories).
Expand Down Expand Up @@ -251,11 +246,12 @@ class INI
AsciiString getFilename() const { return m_filename; }
INILoadType getLoadType() const { return m_loadType; }
UnsignedInt getLineNum() const { return m_lineNum; }
const char *getSeps() const { return m_seps; }
const char *getSepsPercent() const { return m_sepsPercent; }
const char *getSepsColon() const { return m_sepsColon; }
const char *getSepsQuote() { return m_sepsQuote; }
Bool isEOF() const { return m_endOfFile; }
static const char *getSeps() { return " \n\r\t="; } ///< default delimiters for strtok parsing
static const char *getSepsPercent() { return " \n\r\t=%%"; } ///< default delimiters & percent delimiter
static const char *getSepsColon() { return " \n\r\t=:"; } ///< default delimiters & colon delimiter
static const char *getSepsQuote() { return "\"\n="; } ///< delimiters to represent a quoted ascii string
static const char *getEndToken() { return "End"; } ///< token to represent an end of data block

void initFromINI( void *what, const FieldParse* parseTable );
void initFromINIMulti( void *what, const MultiIniFieldParse& parseTableList );
Expand Down Expand Up @@ -321,20 +317,19 @@ class INI
static void parseVeterancyLevelFlags(INI* ini, void* instance, void* store, const void* userData);
static void parseSoundsList( INI* ini, void *instance, void *store, const void* /*userData*/ );


/**
return the next token. if seps is null (or omitted), the standard seps are used.
return the next token. if seps is not specified, the standard seps are used.

this will *never* return null; if there are no more tokens, an exception will be thrown.
*/
const char* getNextToken(const char* seps = nullptr);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, it's just nasty that the original token retrieval code throws in the first place.

static const char* getNextToken(const char* seps = getSeps());

/**
just like getNextToken(), except that null is returned if no more tokens are present
(rather than throwing an exception). usually you should call getNextToken(),
but for some cases this is handier (ie, parsing a variable-length number of tokens).
*/
const char* getNextTokenOrNull(const char* seps = nullptr);
static const char* getNextTokenOrNull(const char* seps = getSeps());

/**
This is called when the next thing you expect is something like:
Expand All @@ -346,7 +341,7 @@ class INI

If "Tag" is not the next token, an error is thrown.
*/
const char* getNextSubToken(const char* expected);
static const char* getNextSubToken(const char* expected);

/**
return the next ascii string. this is usually the same the result of getNextToken(),
Expand Down Expand Up @@ -400,14 +395,9 @@ class INI
unsigned m_readBufferUsed; ///< number of bytes in read buffer

AsciiString m_filename; ///< filename of file currently loading
INILoadType m_loadType; ///< load time for current file
INILoadType m_loadType; ///< load type for current file
UnsignedInt m_lineNum; ///< current line number that's been read
char m_buffer[ INI_MAX_CHARS_PER_LINE+1 ];///< buffer to read file contents into
const char *m_seps; ///< for strtok parsing
const char *m_sepsPercent; ///< m_seps with percent delimiter as well
const char *m_sepsColon; ///< m_seps with colon delimiter as well
const char *m_sepsQuote; ///< token to represent a quoted ascii string
const char *m_blockEndToken; ///< token to represent end of data block
Bool m_endOfFile; ///< TRUE when we've hit EOF
#ifdef DEBUG_CRASHING
char m_curBlockStart[ INI_MAX_CHARS_PER_LINE+1 ]; ///< first line of cur block
Expand Down
42 changes: 13 additions & 29 deletions Core/GameEngine/Source/Common/INI/INI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,26 +180,14 @@ INI::INI()
m_filename = "None";
m_loadType = INI_LOAD_INVALID;
m_lineNum = 0;
m_seps = " \n\r\t="; ///< make sure you update m_sepsPercent/m_sepsColon as well
m_sepsPercent = " \n\r\t=%%";
m_sepsColon = " \n\r\t=:";
m_sepsQuote = "\"\n="; ///< stop at " = EOL
m_blockEndToken = "END";
m_endOfFile = FALSE;
m_buffer[0] = 0;
m_endOfFile = FALSE;
#ifdef DEBUG_CRASHING
m_curBlockStart[0] = 0;
#endif

}

//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
INI::~INI()
{

}

//-------------------------------------------------------------------------------------------------
UnsignedInt INI::loadFileDirectory( AsciiString fileDirName, INILoadType loadType, Xfer *pXfer, Bool subdirs )
{
Expand Down Expand Up @@ -397,7 +385,7 @@ UnsignedInt INI::load( AsciiString filename, INILoadType loadType, Xfer *pXfer )
AsciiString currentLine = m_buffer;

// the first word is the type of data we're processing
const char *token = strtok( m_buffer, m_seps );
const char *token = strtok( m_buffer, getSeps() );
if( token )
{
INIBlockParse parse = findBlockParse(token);
Expand Down Expand Up @@ -710,7 +698,7 @@ void INI::parseAsciiStringVector( INI* ini, void * /*instance*/, void *store, co
{
std::vector<AsciiString>* asv = (std::vector<AsciiString>*)store;
asv->clear();
for (const char *token = ini->getNextTokenOrNull(); token != nullptr; token = ini->getNextTokenOrNull())
for (const char *token = ini->getNextTokenOrNull(); token; token = ini->getNextTokenOrNull())
{
asv->push_back(token);
}
Expand All @@ -723,7 +711,7 @@ void INI::parseAsciiStringVectorAppend( INI* ini, void * /*instance*/, void *sto
std::vector<AsciiString>* asv = (std::vector<AsciiString>*)store;
// nope, don't clear. duh.
// asv->clear();
for (const char *token = ini->getNextTokenOrNull(); token != nullptr; token = ini->getNextTokenOrNull())
for (const char *token = ini->getNextTokenOrNull(); token; token = ini->getNextTokenOrNull())
{
asv->push_back(token);
}
Expand All @@ -735,7 +723,7 @@ void INI::parseAsciiStringVectorAppend( INI* ini, void * /*instance*/, void *sto
{
ScienceVec* asv = (ScienceVec*)store;
asv->clear();
for (const char *token = ini->getNextTokenOrNull(); token != nullptr; token = ini->getNextTokenOrNull())
for (const char *token = ini->getNextTokenOrNull(); token; token = ini->getNextTokenOrNull())
{
if (stricmp(token, "None") == 0)
{
Expand Down Expand Up @@ -952,7 +940,7 @@ void INI::parseBitString32( INI* ini, void * /*instance*/, void *store, const vo
Bool foundAddOrSub = false;

// loop through all tokens
for (const char *token = ini->getNextTokenOrNull(); token != nullptr; token = ini->getNextTokenOrNull())
for (const char *token = ini->getNextTokenOrNull(); token; token = ini->getNextTokenOrNull())
{
if (stricmp(token, "NONE") == 0)
{
Expand Down Expand Up @@ -1528,7 +1516,7 @@ void INI::initFromINIMulti( void *what, const MultiIniFieldParse& parseTableList
if( field )
{

if( stricmp( field, m_blockEndToken ) == 0 )
if( stricmp( field, getEndToken() ) == 0 )
{
done = TRUE;
}
Expand Down Expand Up @@ -1580,7 +1568,7 @@ void INI::initFromINIMulti( void *what, const MultiIniFieldParse& parseTableList

done = TRUE;
DEBUG_CRASH( ("Error parsing block '%s', in INI file '%s'. Missing '%s' token",
m_curBlockStart, getFilename().str(), m_blockEndToken) );
m_curBlockStart, getFilename().str(), getEndToken()) );
throw INI_MISSING_END_TOKEN;

}
Expand All @@ -1590,19 +1578,17 @@ void INI::initFromINIMulti( void *what, const MultiIniFieldParse& parseTableList
}

//-------------------------------------------------------------------------------------------------
/*static*/ const char* INI::getNextToken(const char* seps)
/*static*/ const char* INI::getNextToken(const char* seps /*= getSeps()*/)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to block comment the default argument.

{
if (!seps) seps = getSeps();
const char *token = ::strtok(nullptr, seps);
if (!token)
throw INI_INVALID_DATA;
return token;
}

//-------------------------------------------------------------------------------------------------
/*static*/ const char* INI::getNextTokenOrNull(const char* seps)
/*static*/ const char* INI::getNextTokenOrNull(const char* seps /*= getSeps()*/)
{
if (!seps) seps = getSeps();
const char *token = ::strtok(nullptr, seps);
return token;
}
Expand Down Expand Up @@ -1867,12 +1853,10 @@ void INI::parseSoundsList( INI* ini, void *instance, void *store, const void* /*
std::vector<AsciiString> *vec = (std::vector<AsciiString>*) store;
vec->clear();

const char* SEPS = " \t,=";
const char *c = ini->getNextTokenOrNull(SEPS);
while ( c )
constexpr const char* SEPS = " \t,=";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or Seps

for (const char* token = ini->getNextTokenOrNull(SEPS); token; token = ini->getNextTokenOrNull(SEPS))
{
vec->push_back( c );
c = ini->getNextTokenOrNull(SEPS);
vec->push_back(token);
}
}

Expand Down
2 changes: 1 addition & 1 deletion Generals/Code/GameEngine/Include/Common/BitFlagsIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ void BitFlags<NUMBITS>::parse(INI* ini, AsciiString* str)
Bool foundAddOrSub = false;

// loop through all tokens
for (const char *token = ini->getNextTokenOrNull(); token != nullptr; token = ini->getNextTokenOrNull())
for (const char *token = ini->getNextTokenOrNull(); token; token = ini->getNextTokenOrNull())
{
if (str)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ static void parsePrerequisiteUnit( INI* ini, void *instance, void * /*store*/, c

ProductionPrerequisite prereq;
Bool orUnitWithPrevious = FALSE;
for (const char *token = ini->getNextToken(); token != nullptr; token = ini->getNextTokenOrNull())
for (const char *token = ini->getNextToken(); token; token = ini->getNextTokenOrNull())
{
prereq.addUnitPrereq( AsciiString( token ), orUnitWithPrevious );
orUnitWithPrevious = TRUE;
Expand Down
4 changes: 1 addition & 3 deletions Generals/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,10 @@ TurretAIData::TurretAIData()
static void parseTWS(INI* ini, void * /*instance*/, void * store, const void* /*userData*/)
{
UnsignedInt* tws = (UnsignedInt*)store;
const char* token = ini->getNextToken();
while (token != nullptr)
for (const char* token = ini->getNextToken(); token; token = ini->getNextTokenOrNull())
{
WeaponSlotType wslot = (WeaponSlotType)INI::scanIndexList(token, TheWeaponSlotTypeNames);
*tws |= (1 << wslot);
token = ini->getNextTokenOrNull();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ InstantDeathBehaviorModuleData::InstantDeathBehaviorModuleData()
static void parseFX( INI* ini, void *instance, void * /*store*/, const void* /*userData*/ )
{
InstantDeathBehaviorModuleData* self = (InstantDeathBehaviorModuleData*)instance;
for (const char* token = ini->getNextToken(); token != nullptr; token = ini->getNextTokenOrNull())
for (const char* token = ini->getNextToken(); token; token = ini->getNextTokenOrNull())
{
const FXList *fxl = TheFXListStore->findFXList((token)); // could be null! this is OK!
self->m_fx.push_back(fxl);
Expand All @@ -73,7 +73,7 @@ static void parseFX( INI* ini, void *instance, void * /*store*/, const void* /*u
static void parseOCL( INI* ini, void *instance, void * /*store*/, const void* /*userData*/ )
{
InstantDeathBehaviorModuleData* self = (InstantDeathBehaviorModuleData*)instance;
for (const char* token = ini->getNextToken(); token != nullptr; token = ini->getNextTokenOrNull())
for (const char* token = ini->getNextToken(); token; token = ini->getNextTokenOrNull())
{
const ObjectCreationList *ocl = TheObjectCreationListStore->findObjectCreationList(token); // could be null! this is OK!
self->m_ocls.push_back(ocl);
Expand All @@ -84,7 +84,7 @@ static void parseOCL( INI* ini, void *instance, void * /*store*/, const void* /*
static void parseWeapon( INI* ini, void *instance, void * /*store*/, const void* /*userData*/ )
{
InstantDeathBehaviorModuleData* self = (InstantDeathBehaviorModuleData*)instance;
for (const char* token = ini->getNextToken(); token != nullptr; token = ini->getNextTokenOrNull())
for (const char* token = ini->getNextToken(); token; token = ini->getNextTokenOrNull())
{
const WeaponTemplate *wt = TheWeaponStore->findWeaponTemplate(token); // could be null! this is OK!
self->m_weapons.push_back(wt);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ static void parseFX( INI* ini, void *instance, void * /*store*/, const void* /*u
{
SlowDeathBehaviorModuleData* self = (SlowDeathBehaviorModuleData*)instance;
SlowDeathPhaseType sdphase = (SlowDeathPhaseType)INI::scanIndexList(ini->getNextToken(), TheSlowDeathPhaseNames);
for (const char* token = ini->getNextToken(); token != nullptr; token = ini->getNextTokenOrNull())
for (const char* token = ini->getNextToken(); token; token = ini->getNextTokenOrNull())
{
const FXList *fxl = TheFXListStore->findFXList((token)); // could be null! this is OK!
self->m_fx[sdphase].push_back(fxl);
Expand All @@ -95,7 +95,7 @@ static void parseOCL( INI* ini, void *instance, void * /*store*/, const void* /*
{
SlowDeathBehaviorModuleData* self = (SlowDeathBehaviorModuleData*)instance;
SlowDeathPhaseType sdphase = (SlowDeathPhaseType)INI::scanIndexList(ini->getNextToken(), TheSlowDeathPhaseNames);
for (const char* token = ini->getNextToken(); token != nullptr; token = ini->getNextTokenOrNull())
for (const char* token = ini->getNextToken(); token; token = ini->getNextTokenOrNull())
{
const ObjectCreationList *ocl = TheObjectCreationListStore->findObjectCreationList(token); // could be null! this is OK!
self->m_ocls[sdphase].push_back(ocl);
Expand All @@ -109,7 +109,7 @@ static void parseWeapon( INI* ini, void *instance, void * /*store*/, const void*
{
SlowDeathBehaviorModuleData* self = (SlowDeathBehaviorModuleData*)instance;
SlowDeathPhaseType sdphase = (SlowDeathPhaseType)INI::scanIndexList(ini->getNextToken(), TheSlowDeathPhaseNames);
for (const char* token = ini->getNextToken(); token != nullptr; token = ini->getNextTokenOrNull())
for (const char* token = ini->getNextToken(); token; token = ini->getNextTokenOrNull())
{
const WeaponTemplate *wt = TheWeaponStore->findWeaponTemplate(token); // could be null! this is OK!
self->m_weapons[sdphase].push_back(wt);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1351,12 +1351,12 @@ class GenericObjectCreationNugget : public ObjectCreationNugget
static void parseDebrisObjectNames( INI* ini, void *instance, void *store, const void* /*userData*/ )
{
GenericObjectCreationNugget* debrisNugget = (GenericObjectCreationNugget*)instance;
for (const char* debrisName = ini->getNextToken(); debrisName; debrisName = ini->getNextTokenOrNull())
for (const char* token = ini->getNextToken(); token; token = ini->getNextTokenOrNull())
{
if (TheGlobalData->m_preloadAssets)
debrisModelNamesGlobalHack.push_back(debrisName);
debrisNugget->m_names.push_back(AsciiString(debrisName));
debrisName = ini->getNextTokenOrNull();
debrisModelNamesGlobalHack.push_back(token);
debrisNugget->m_names.push_back(AsciiString(token));
token = ini->getNextTokenOrNull();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,16 +172,16 @@ const LocomotorTemplateVector* AIUpdateModuleData::findLocomotorTemplateVector(L
}

self->m_locomotorTemplates[set].clear();
for (const char* locoName = ini->getNextToken(); locoName; locoName = ini->getNextTokenOrNull())
for (const char* token = ini->getNextToken(); token; token = ini->getNextTokenOrNull())
{
if (!*locoName || stricmp(locoName, "None") == 0)
if (!*token || stricmp(token, "None") == 0)
continue;

NameKeyType locoKey = NAMEKEY(locoName);
NameKeyType locoKey = NAMEKEY(token);
const LocomotorTemplate* lt = TheLocomotorStore->findLocomotorTemplate(locoKey);
if (!lt)
{
DEBUG_CRASH(("Locomotor %s not found!",locoName));
DEBUG_CRASH(("Locomotor %s not found!",token));
throw INI_INVALID_DATA;
}
self->m_locomotorTemplates[set].push_back(lt);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,9 @@ void parseUpgradePair( INI *ini, void *instance, void *store, const void *userDa
info.amount = 0;

const char *token = ini->getNextToken( ini->getSepsColon() );

if ( stricmp(token, "UpgradeType") == 0 )
{
token = ini->getNextTokenOrNull( ini->getSepsColon() );
if (!token) throw INI_INVALID_DATA;

token = ini->getNextToken( ini->getSepsColon() );
info.type = token;
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ static void parseFX( INI* ini, void *instance, void * /*store*/, const void* /*u
{
StructureCollapseUpdateModuleData* self = (StructureCollapseUpdateModuleData*)instance;
StructureCollapsePhaseType scphase = (StructureCollapsePhaseType)INI::scanIndexList(ini->getNextToken(), TheStructureCollapsePhaseNames);
for (const char* token = ini->getNextToken(); token != nullptr; token = ini->getNextTokenOrNull())
for (const char* token = ini->getNextToken(); token; token = ini->getNextTokenOrNull())
{
const FXList *fxl = TheFXListStore->findFXList((token)); // could be null! this is OK!
self->m_fxs[scphase].push_back(fxl);
Expand All @@ -96,7 +96,7 @@ static void parseOCL( INI* ini, void *instance, void * /*store*/, const void* /*
{
StructureCollapseUpdateModuleData* self = (StructureCollapseUpdateModuleData*)instance;
StructureCollapsePhaseType stphase = (StructureCollapsePhaseType)INI::scanIndexList(ini->getNextToken(), TheStructureCollapsePhaseNames);
for (const char* token = ini->getNextToken(); token != nullptr; token = ini->getNextTokenOrNull())
for (const char* token = ini->getNextToken(); token; token = ini->getNextTokenOrNull())
{
const ObjectCreationList *ocl = TheObjectCreationListStore->findObjectCreationList(token); // could be null! this is OK!
self->m_ocls[stphase].push_back(ocl);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ static void parseOCL( INI* ini, void *instance, void * /*store*/, const void* /*
{
StructureToppleUpdateModuleData* self = (StructureToppleUpdateModuleData*)instance;
StructureTopplePhaseType stphase = (StructureTopplePhaseType)INI::scanIndexList(ini->getNextToken(), TheStructureTopplePhaseNames);
for (const char* token = ini->getNextToken(); token != nullptr; token = ini->getNextTokenOrNull())
for (const char* token = ini->getNextToken(); token; token = ini->getNextTokenOrNull())
{
const ObjectCreationList *ocl = TheObjectCreationListStore->findObjectCreationList(token); // could be null! this is OK!
self->m_ocls[stphase].push_back(ocl);
Expand Down
2 changes: 1 addition & 1 deletion GeneralsMD/Code/GameEngine/Include/Common/BitFlagsIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ void BitFlags<NUMBITS>::parse(INI* ini, AsciiString* str)
Bool foundAddOrSub = false;

// loop through all tokens
for (const char *token = ini->getNextTokenOrNull(); token != nullptr; token = ini->getNextTokenOrNull())
for (const char *token = ini->getNextTokenOrNull(); token; token = ini->getNextTokenOrNull())
{
if (str)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ static void parsePrerequisiteUnit( INI* ini, void *instance, void * /*store*/, c

ProductionPrerequisite prereq;
Bool orUnitWithPrevious = FALSE;
for (const char *token = ini->getNextToken(); token != nullptr; token = ini->getNextTokenOrNull())
for (const char *token = ini->getNextToken(); token; token = ini->getNextTokenOrNull())
{
prereq.addUnitPrereq( AsciiString( token ), orUnitWithPrevious );
orUnitWithPrevious = TRUE;
Expand Down
Loading
Loading