mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-17 14:16:10 -06:00
401 lines
6.7 KiB
C++
401 lines
6.7 KiB
C++
#include "MIValue.h"
|
|
|
|
static MIValue &NullMIValue(void)
|
|
{
|
|
static MIValue v;
|
|
return v;
|
|
}
|
|
|
|
static MIValue &ErrorMIValue(String const &msg)
|
|
{
|
|
static MIValue v;
|
|
v.SetError(msg);
|
|
return v;
|
|
}
|
|
|
|
int MIValue::ParsePair(String &name, MIValue &val, String const &s, int i)
|
|
{
|
|
name.Clear();
|
|
val.Clear();
|
|
while(s[i] && (s[i] != '=') && s[i] != ']' && s[i] != '}')
|
|
name.Cat(s[i++]);
|
|
if(s[i] != '=')
|
|
return i;
|
|
i++;
|
|
switch(s[i])
|
|
{
|
|
case '"':
|
|
{
|
|
i = val.ParseString(s, i);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case '[':
|
|
i = val.ParseArray(s, i);
|
|
break;
|
|
|
|
case '{':
|
|
i = val.ParseTuple(s, i);
|
|
break;
|
|
|
|
default:
|
|
NEVER();
|
|
}
|
|
return i;
|
|
}
|
|
|
|
int MIValue::ParseTuple(String const &s, int i)
|
|
{
|
|
Clear();
|
|
type = MITuple;
|
|
|
|
// drop opening delimiter
|
|
if(s[i] != '{')
|
|
{
|
|
SetError(Format("Expected '{' at pos %d in '%s'", i, s));
|
|
return s.GetCount();
|
|
}
|
|
i++;
|
|
while(s[i] && s[i] != '}')
|
|
{
|
|
String name;
|
|
MIValue val;
|
|
i = ParsePair(name, val, s, i);
|
|
tuple.Add(name, val);
|
|
if(s[i] == '}')
|
|
break;
|
|
if(s[i] != ',')
|
|
{
|
|
SetError(Format("Expected ',' at pos %d in '%s'", i, s));
|
|
return s.GetCount();
|
|
}
|
|
i++;
|
|
}
|
|
return i + 1;
|
|
}
|
|
|
|
int MIValue::ParseArray(String const &s, int i)
|
|
{
|
|
Clear();
|
|
type = MIArray;
|
|
|
|
// drop opening delimiter
|
|
if(s[i] != '[')
|
|
{
|
|
SetError(Format("Expected '[' at pos %d in '%s'", i, s));
|
|
return s.GetCount();
|
|
}
|
|
i++;
|
|
while(s[i] && s[i] != ']')
|
|
{
|
|
String name;
|
|
MIValue val;
|
|
if(s[i] == '[')
|
|
i = val.ParseArray(s, i);
|
|
else if(s[i] == '{')
|
|
i = val.ParseTuple(s, i);
|
|
else if(s[i] == '"')
|
|
i = val.ParseString(s, i);
|
|
else
|
|
i = ParsePair(name, val, s, i);
|
|
array.Add(val);
|
|
if(s[i] == ']')
|
|
break;
|
|
if(s[i] != ',')
|
|
{
|
|
SetError(Format("Expected ',' at pos %d in '%s'", i, s));
|
|
return s.GetCount();
|
|
}
|
|
i++;
|
|
}
|
|
return i + 1;
|
|
}
|
|
|
|
int MIValue::ParseString(String const &s, int i)
|
|
{
|
|
Clear();
|
|
type = MIString;
|
|
|
|
char c;
|
|
if(s[i] != '"')
|
|
{
|
|
SetError(Format("Expected '\"' at pos %d in '%s'", i, s));
|
|
return s.GetCount();
|
|
}
|
|
i++;
|
|
while( (c = s[i++]) != 0)
|
|
{
|
|
// verbatim if escaped
|
|
if(c == '\\')
|
|
string.Cat(s[i++]);
|
|
else if(c == '"')
|
|
break;
|
|
else
|
|
string.Cat(c);
|
|
}
|
|
if(c != '"')
|
|
{
|
|
SetError(Format("Expected '\"' at pos %d in '%s'", i, s));
|
|
return s.GetCount();
|
|
}
|
|
return i;
|
|
}
|
|
|
|
int MIValue::Parse(String const &s, int i)
|
|
{
|
|
// if starts with '"', it's a string
|
|
// if starts with '[', it's an array
|
|
// if starts with '{', it's a tuple
|
|
// otherwise, it can be a sequence of pair name="value" which is stored like a tuple
|
|
// latter case is an example o bad design of MI interface....
|
|
Clear();
|
|
if(s[i] == '"')
|
|
return ParseString(s, i);
|
|
else if(s[i] == '[')
|
|
return ParseArray(s, i);
|
|
else if(s[i] == '{')
|
|
return ParseTuple(s, i);
|
|
else
|
|
{
|
|
String name;
|
|
MIValue val;
|
|
type = MITuple;
|
|
while(s[i])
|
|
{
|
|
i = ParsePair(name, val, s, i);
|
|
tuple.Add(name, val);
|
|
if(s[i] != ',')
|
|
break;
|
|
i++;
|
|
}
|
|
return i;
|
|
}
|
|
}
|
|
|
|
MIValue &MIValue::operator=(pick_ MIValue &v)
|
|
{
|
|
Clear();
|
|
type = v.type;
|
|
switch(type)
|
|
{
|
|
case MIString:
|
|
string = v.string;
|
|
break;
|
|
case MIArray:
|
|
array = v.array;
|
|
break;
|
|
case MITuple:
|
|
tuple = v.tuple;
|
|
break;
|
|
default:
|
|
SetError("Unknown MIValue type");
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
MIValue::MIValue()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
MIValue::MIValue(MIValue pick_ &v)
|
|
{
|
|
Clear();
|
|
type = v.type;
|
|
switch(type)
|
|
{
|
|
case MIString:
|
|
string = v.string;
|
|
break;
|
|
case MIArray:
|
|
array = v.array;
|
|
break;
|
|
case MITuple:
|
|
tuple = v.tuple;
|
|
break;
|
|
default:
|
|
SetError("Unknown MIValue type");
|
|
}
|
|
}
|
|
|
|
MIValue::MIValue(String const &s)
|
|
{
|
|
Parse(s);
|
|
}
|
|
|
|
MIValue &MIValue::operator=(String const &s)
|
|
{
|
|
Parse(s);
|
|
return *this;
|
|
}
|
|
|
|
void MIValue::Clear()
|
|
{
|
|
type = MIString;
|
|
string = "";
|
|
array.Clear();
|
|
tuple.Clear();
|
|
}
|
|
|
|
// sets value to an error condition
|
|
MIValue &MIValue::SetError(String const &msg)
|
|
{
|
|
type = MIString;
|
|
string = "error:" + msg;
|
|
return *this;
|
|
}
|
|
|
|
// check if value contains an error
|
|
bool MIValue::IsError(void) const
|
|
{
|
|
return type == MIString && string.StartsWith("error:");
|
|
}
|
|
|
|
// check for emptyness
|
|
bool MIValue::IsEmpty(void) const
|
|
{
|
|
return type == MIString && string == "";
|
|
}
|
|
|
|
// simple accessors
|
|
int MIValue::GetCount(void) const
|
|
{
|
|
if(IsError())
|
|
return 0;
|
|
if(type == MIArray)
|
|
return array.GetCount();
|
|
else if(type == MITuple)
|
|
return tuple.GetCount();
|
|
else
|
|
return string.GetCount();
|
|
}
|
|
|
|
int MIValue::Find(const char *key) const
|
|
{
|
|
if(type != MITuple)
|
|
return -1;
|
|
return tuple.Find(key);
|
|
}
|
|
|
|
MIValue &MIValue::Get(int i)
|
|
{
|
|
if(IsError())
|
|
return *this;
|
|
if(type != MIArray)
|
|
return ErrorMIValue("Not an Array value type");
|
|
return array[i];
|
|
}
|
|
|
|
MIValue &MIValue::Get(const char *key)
|
|
{
|
|
if(type != MITuple)
|
|
return ErrorMIValue("Not a Tuple value type");
|
|
return tuple.Get(key);
|
|
}
|
|
|
|
String &MIValue::Get(void)
|
|
{
|
|
if(type != MIString)
|
|
return ErrorMIValue("Not a String value type");
|
|
return string;
|
|
}
|
|
|
|
String const &MIValue::Get(void) const
|
|
{
|
|
if(type != MIString)
|
|
return ErrorMIValue("Not a String value type");
|
|
return string;
|
|
}
|
|
|
|
// tuple string member accessor with default value if not found
|
|
String MIValue::Get(const char *key, const char *def) const
|
|
{
|
|
if(type != MITuple)
|
|
return ErrorMIValue("Not a Tuple value type");
|
|
int i = tuple.Find(key);
|
|
if(i >= 0)
|
|
{
|
|
if(tuple[i].type != MIString)
|
|
return def;
|
|
return tuple[i].Get();
|
|
}
|
|
else
|
|
return def;
|
|
}
|
|
|
|
// data dump
|
|
String MIValue::Dump(int level) const
|
|
{
|
|
String spacer(' ', level);
|
|
switch(type)
|
|
{
|
|
case MIString:
|
|
return spacer + string;
|
|
|
|
case MITuple:
|
|
{
|
|
String s = spacer + "{\n";
|
|
level += 4;
|
|
spacer = String(' ', level);
|
|
for(int i = 0; i < tuple.GetCount(); i++)
|
|
{
|
|
String s1 = spacer + tuple.GetKey(i) + "=";
|
|
s += s1;
|
|
MIValue const &val = tuple[i];
|
|
if(val.type == MIString)
|
|
s += val.Dump();
|
|
else
|
|
{
|
|
s += '\n' + val.Dump(level + 4);
|
|
s = s.Left(s.GetCount()-1);
|
|
}
|
|
if(i < tuple.GetCount() - 1)
|
|
s += ',';
|
|
s += '\n';
|
|
}
|
|
level -= 4;
|
|
spacer = String(' ', level);
|
|
s += spacer + "}\n";
|
|
return s;
|
|
}
|
|
|
|
case MIArray:
|
|
{
|
|
String s = spacer + "[ \n";
|
|
level += 4;
|
|
for(int i = 0; i < array.GetCount(); i++)
|
|
{
|
|
MIValue const &val = array[i];
|
|
s += val.Dump(level);
|
|
if(val.type != MIString)
|
|
s = s.Left(s.GetCount()-1);
|
|
if(i < array.GetCount() - 1)
|
|
s += ',';
|
|
s += '\n';
|
|
}
|
|
s += spacer + "]\n";
|
|
return s;
|
|
}
|
|
|
|
default:
|
|
return spacer + "*UNKNOWN MIVALUE TYPE*";
|
|
}
|
|
}
|
|
|
|
// finds breakpoint data given file and line
|
|
MIValue &MIValue::FindBreakpoint(String const &file, int line)
|
|
{
|
|
MIValue &body = Get("body");
|
|
if(body.IsError() || !body.IsArray())
|
|
return NullMIValue();
|
|
for(int i = 0; i < body.GetCount(); i++)
|
|
{
|
|
MIValue &bp = body[i];
|
|
if(bp.IsError() || !bp.IsTuple())
|
|
return NullMIValue();
|
|
if(bp["file"] == file && atoi(bp["line"].Get()) == line)
|
|
return bp;
|
|
}
|
|
return NullMIValue();
|
|
}
|