Fixes to variable list in CBot debugger

* fixed stack overflow with circular references (closes #434)
* fixed displaying boolean variables
* fixed buffer overflows with entries longer than 100 characters
* removed hard-limit to 100 entries with at most 100 characters in CList (this also allows you to have more than 100 programs in a robot, up to 999)
dev-time-step
krzys-h 2016-03-15 20:34:00 +01:00
parent 4479a196f9
commit fef8a8e355
4 changed files with 68 additions and 74 deletions

View File

@ -490,79 +490,71 @@ bool CScript::GetCursor(int &cursor1, int &cursor2)
// Put of the variables in a list.
void PutList(const char *baseName, bool bArray, CBot::CBotVar *var, Ui::CList *list, int &rankList)
void PutList(const std::string& baseName, bool bArray, CBot::CBotVar *var, Ui::CList *list, int &rankList, std::set<CBot::CBotVar*>& previous)
{
CBot::CBotVar *svar, *pStatic;
char varName[100];
char buffer[100];
std::string p;
int index, type;
if ( var == nullptr && baseName[0] != 0 )
if ( var == nullptr && !baseName.empty() )
{
sprintf(buffer, "%s = null;", baseName);
list->SetItemName(rankList++, buffer);
list->SetItemName(rankList++, StrUtils::Format("%s = null;", baseName.c_str()).c_str());
return;
}
index = 0;
while ( var != nullptr )
int index = 0;
while (var != nullptr)
{
var->Update(nullptr);
pStatic = var->GetStaticVar(); // finds the static element
CBot::CBotVar* pStatic = var->GetStaticVar(); // finds the static element
p = pStatic->GetName(); // variable name
//? if ( strcmp(p, "this") == 0 )
//? {
//? var = var->GetNext();
//? continue;
//? }
if ( baseName[0] == 0 )
std::string varName;
if (baseName.empty())
{
sprintf(varName, "%s", p.c_str());
varName = StrUtils::Format("%s", pStatic->GetName().c_str());
}
else
{
if ( bArray )
if (bArray)
{
sprintf(varName, "%s[%d]", baseName, index);
varName = StrUtils::Format("%s[%d]", baseName.c_str(), index);
}
else
{
sprintf(varName, "%s.%s", baseName, p.c_str());
varName = StrUtils::Format("%s.%s", baseName.c_str(), pStatic->GetName().c_str());
}
}
type = pStatic->GetType();
if ( type < CBot::CBotTypBoolean )
if (previous.find(pStatic) != previous.end())
{
p = pStatic->GetValString();
sprintf(buffer, "%s = %s;", varName, p.c_str());
list->SetItemName(rankList++, buffer);
}
else if ( type == CBot::CBotTypString )
{
p = pStatic->GetValString();
sprintf(buffer, "%s = \"%s\";", varName, p.c_str());
list->SetItemName(rankList++, buffer);
}
else if ( type == CBot::CBotTypArrayPointer )
{
svar = pStatic->GetItemList();
PutList(varName, true, svar, list, rankList);
}
else if ( type == CBot::CBotTypClass ||
type == CBot::CBotTypPointer )
{
svar = pStatic->GetItemList();
PutList(varName, false, svar, list, rankList);
list->SetItemName(rankList++, StrUtils::Format("%s = [circular reference]", varName.c_str()).c_str());
}
else
{
sprintf(buffer, "%s = ?;", varName);
list->SetItemName(rankList++, buffer);
int type = pStatic->GetType();
if (type <= CBot::CBotTypBoolean)
{
list->SetItemName(rankList++, StrUtils::Format("%s = %s;", varName.c_str(), pStatic->GetValString().c_str()).c_str());
}
else if (type == CBot::CBotTypString)
{
list->SetItemName(rankList++, StrUtils::Format("%s = \"%s\";", varName.c_str(), pStatic->GetValString().c_str()).c_str());
}
else if (type == CBot::CBotTypArrayPointer)
{
previous.insert(pStatic);
PutList(varName, true, pStatic->GetItemList(), list, rankList, previous);
previous.erase(pStatic);
}
else if (type == CBot::CBotTypClass ||
type == CBot::CBotTypPointer)
{
previous.insert(pStatic);
PutList(varName, false, pStatic->GetItemList(), list, rankList, previous);
previous.erase(pStatic);
}
else
{
//list->SetItemName(rankList++, StrUtils::Format("%s = ?;", varName.c_str()).c_str());
assert(false);
}
}
index ++;
@ -589,13 +581,15 @@ void CScript::UpdateList(Ui::CList* list)
level = 0;
rank = 0;
std::set<CBot::CBotVar*> previous;
while ( true )
{
var = m_botProg->GetStackVars(funcName, level--);
if ( funcName != progName ) break;
PutList("", false, var, list, rank);
PutList("", false, var, list, rank, previous);
}
assert(previous.empty());
if ( total == list->GetTotal() ) // same total?
{

View File

@ -354,7 +354,7 @@ void CList::Draw()
float dp;
int i;
char text[100];
char *pb, *pe;
const char *pb, *pe;
if ((m_state & STATE_VISIBLE) == 0)
return;
@ -451,14 +451,14 @@ void CList::Draw()
ppos.y = pos.y + dim.y * 0.5f;
ppos.y -= m_engine->GetText()->GetHeight(m_fontType, m_fontSize) / 2.0f;
ddim.x = dim.x-dim.y;
DrawCase(m_items[i + m_firstLine].text, ppos, ddim.x, Gfx::TEXT_ALIGN_LEFT);
DrawCase(m_items[i + m_firstLine].text.c_str(), ppos, ddim.x, Gfx::TEXT_ALIGN_LEFT);
}
else
{
ppos.x = pos.x + dim.y * 0.5f;
ppos.y = pos.y + dim.y * 0.5f;
ppos.y -= m_engine->GetText()->GetHeight(m_fontType, m_fontSize) / 2.0f;
pb = m_items[i + m_firstLine].text;
pb = m_items[i + m_firstLine].text.c_str();
for (int j = 0; j < 10; j++)
{
pe = strchr(pb, '\t');
@ -548,7 +548,7 @@ void CList::Draw()
// Displays text in a box.
void CList::DrawCase(char *text, Math::Point pos, float width, Gfx::TextAlign justif)
void CList::DrawCase(const char* text, Math::Point pos, float width, Gfx::TextAlign justif)
{
if (justif == Gfx::TEXT_ALIGN_CENTER)
pos.x += width / 2.0f;
@ -651,18 +651,19 @@ bool CList::GetBlink()
// Specifies the text of a line.
void CList::SetItemName(int i, const char* name)
void CList::SetItemName(int i, const std::string& name)
{
if ( i < 0 || i >= LISTMAXTOTAL )
if ( i < 0 )
return;
if ( i >= m_totalLine )
m_totalLine = i+1; // expands the list
if ( name[0] == 0 )
strcpy(m_items[i].text, " ");
m_items.resize(m_totalLine);
if ( name.empty() )
m_items[i].text = " ";
else
strcpy(m_items[i].text, name);
m_items[i].text = name;
UpdateButton();
UpdateScroll();
@ -670,10 +671,10 @@ void CList::SetItemName(int i, const char* name)
// Returns the text of a line.
char* CList::GetItemName(int i)
const std::string& CList::GetItemName(int i)
{
if ( i < 0 || i >= m_totalLine )
return nullptr;
assert(false);
return m_items[i].text;
}

View File

@ -35,7 +35,6 @@ namespace Ui
{
const int LISTMAXDISPLAY = 20; // maximum number of visible lines
const int LISTMAXTOTAL = 100; // maximum total number of lines
@ -71,8 +70,8 @@ public:
void SetBlink(bool bEnable);
bool GetBlink();
void SetItemName(int i, const char* name);
char* GetItemName(int i);
void SetItemName(int i, const std::string& name);
const std::string& GetItemName(int i);
void SetCheck(int i, bool bMode);
bool GetCheck(int i);
@ -93,7 +92,7 @@ protected:
void UpdateButton();
void UpdateScroll();
void MoveScroll();
void DrawCase(char *text, Math::Point pos, float width, Gfx::TextAlign justif);
void DrawCase(const char* text, Math::Point pos, float width, Gfx::TextAlign justif);
private:
// Overridden to avoid warning about hiding the virtual function
@ -116,11 +115,11 @@ protected:
struct Item
{
char text[100] = {};
std::string text = "";
bool check = false;
bool enable = true;
};
std::array<Item, LISTMAXTOTAL> m_items;
std::vector<Item> m_items;
};

View File

@ -153,7 +153,7 @@ bool CScreenPlayerSelect::EventProcess(const Event &event)
CWindow* pw;
CList* pl;
std::string name;
char* gamer;
std::string gamer;
switch( event.type )
{
@ -289,7 +289,7 @@ void CScreenPlayerSelect::UpdateNameList()
for ( i=0 ; i<total ; i++ )
{
// TODO: stricmp?
if ( strcmp(name, pl->GetItemName(i)) == 0 )
if ( name == pl->GetItemName(i) )
{
pl->SetSelect(i);
pl->ShowSelect(false);
@ -307,7 +307,7 @@ void CScreenPlayerSelect::UpdateNameEdit()
CWindow* pw;
CList* pl;
CEdit* pe;
char* name;
std::string name;
int sel;
pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
@ -326,8 +326,8 @@ void CScreenPlayerSelect::UpdateNameEdit()
else
{
name = pl->GetItemName(sel);
pe->SetText(name);
pe->SetCursor(strlen(name), 0);
pe->SetText(name.c_str());
pe->SetCursor(name.length(), 0);
}
UpdateNameControl();
@ -434,7 +434,7 @@ void CScreenPlayerSelect::NameDelete()
return;
}
char* gamer = pl->GetItemName(sel);
std::string gamer = pl->GetItemName(sel);
m_main->SelectPlayer(gamer);
if (!m_main->GetPlayerProfile()->Delete())