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

View File

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

View File

@ -35,7 +35,6 @@ namespace Ui
{ {
const int LISTMAXDISPLAY = 20; // maximum number of visible lines 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); void SetBlink(bool bEnable);
bool GetBlink(); bool GetBlink();
void SetItemName(int i, const char* name); void SetItemName(int i, const std::string& name);
char* GetItemName(int i); const std::string& GetItemName(int i);
void SetCheck(int i, bool bMode); void SetCheck(int i, bool bMode);
bool GetCheck(int i); bool GetCheck(int i);
@ -93,7 +92,7 @@ protected:
void UpdateButton(); void UpdateButton();
void UpdateScroll(); void UpdateScroll();
void MoveScroll(); 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: private:
// Overridden to avoid warning about hiding the virtual function // Overridden to avoid warning about hiding the virtual function
@ -116,11 +115,11 @@ protected:
struct Item struct Item
{ {
char text[100] = {}; std::string text = "";
bool check = false; bool check = false;
bool enable = true; 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; CWindow* pw;
CList* pl; CList* pl;
std::string name; std::string name;
char* gamer; std::string gamer;
switch( event.type ) switch( event.type )
{ {
@ -289,7 +289,7 @@ void CScreenPlayerSelect::UpdateNameList()
for ( i=0 ; i<total ; i++ ) for ( i=0 ; i<total ; i++ )
{ {
// TODO: stricmp? // TODO: stricmp?
if ( strcmp(name, pl->GetItemName(i)) == 0 ) if ( name == pl->GetItemName(i) )
{ {
pl->SetSelect(i); pl->SetSelect(i);
pl->ShowSelect(false); pl->ShowSelect(false);
@ -307,7 +307,7 @@ void CScreenPlayerSelect::UpdateNameEdit()
CWindow* pw; CWindow* pw;
CList* pl; CList* pl;
CEdit* pe; CEdit* pe;
char* name; std::string name;
int sel; int sel;
pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5)); pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
@ -326,8 +326,8 @@ void CScreenPlayerSelect::UpdateNameEdit()
else else
{ {
name = pl->GetItemName(sel); name = pl->GetItemName(sel);
pe->SetText(name); pe->SetText(name.c_str());
pe->SetCursor(strlen(name), 0); pe->SetCursor(name.length(), 0);
} }
UpdateNameControl(); UpdateNameControl();
@ -434,7 +434,7 @@ void CScreenPlayerSelect::NameDelete()
return; return;
} }
char* gamer = pl->GetItemName(sel); std::string gamer = pl->GetItemName(sel);
m_main->SelectPlayer(gamer); m_main->SelectPlayer(gamer);
if (!m_main->GetPlayerProfile()->Delete()) if (!m_main->GetPlayerProfile()->Delete())