#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(); }