using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Windows.Forms; using System.Drawing; namespace Rose { enum ElementType {None, String, Ident, Number, SpecialChar}; class ParserPos { public int index; public Point pos; } class Parser { public string content; int index; int prevIndex; Point pos; Point prevPos; ElementType elementType; public char ReadChar() { prevPos = pos; prevIndex = index; char result = content[index]; index++; if (result == '\n') { pos.Y++; pos.X = 1; } else pos.X++; return result; } public Parser() { Clear(); } public void Clear() { pos = new Point(1, 1); prevPos = pos; index = 0; } public bool IsSpecialChar(char character) { return (character == '(') || (character == ')') || (character == '\r') || (character == '|') || (character == ','); } public string ReadNext() { string result = ""; bool finished = false; elementType = ElementType.None; while ((index < content.Length) && !finished) { char character = ReadChar(); if (elementType == ElementType.String) { if (character == '\"') { finished = true; break; } else { result = result + character; } } else if (elementType == ElementType.Ident) { if (char.IsLetterOrDigit(character) || (character == '_')) { result = result + character; } else { index = prevIndex; pos = prevPos; finished = true; break; } } else if (elementType == ElementType.Number) { if (char.IsNumber(character) || (character == '.')) { result = result + character; } else { index = prevIndex; pos = prevPos; finished = true; break; } } else { if (IsSpecialChar(character)) { result = result + character; break; } else if (char.IsWhiteSpace(character)) { if (result == "") { } else { break; } } else if (char.IsLetter(character) || (character == '_') || (character == '@')) { result = result + character; elementType = ElementType.Ident; } else if (char.IsNumber(character) || (character == '-')) { result = result + character; elementType = ElementType.Number; } else if (character == '\"') { elementType = ElementType.String; } else { ErrorMessage("Unsupported character '" + character + "'"); } } } return result; } public bool CheckNext(string text) { ParserPos oldPos = GetPos(); string element = ReadNext(); SetPos(oldPos); return element == text; } public void Expect(string text) { string element = ReadNext(); if (element != text) { ErrorMessage("Expected '" + text + "' but '" + element + "' found."); } } public string ReadUntil(char character) { string result = ""; while ((index < content.Length) && (content[index] != character)) { result += ReadChar(); } return result; } public void ErrorMessage(string Text) { throw new Exception("Parsing error: " + Text + " (" + pos.X.ToString() + "," + pos.Y.ToString() + ")"); } public ParserPos GetPos() { ParserPos result = new ParserPos(); result.pos = pos; result.index = index; return result; } public void SetPos(ParserPos parserPos) { pos = parserPos.pos; index = parserPos.index; } } class RoseItem { public string name; public RoseItem parent; public virtual string GetAsString(int indent = 0) { return string.Concat(Enumerable.Repeat(" ", indent)) + "name: " + name + Environment.NewLine; } public virtual List Find(string text, bool exact = true) { return new List(); } } class RoseString: RoseItem { public string value; public RoseString(string value) { this.value = value; } public override string GetAsString(int indent = 0) { return base.GetAsString(indent) + string.Concat(Enumerable.Repeat(" ", indent)) + "value: " + value + Environment.NewLine; } public override List Find(string text, bool exact = true) { List result = new List(); if (((text == value) && exact) || ((value.Contains(text)) && !exact)) result.Add(this); return result; } } class RosePoint : RoseItem { public Point value; public RosePoint() { this.value = new Point(0, 0); } public virtual bool Parse(Parser parser) { ParserPos oldPos = parser.GetPos(); parser.Expect("("); Int32 output; if(int.TryParse(parser.ReadNext(), out output)) value.X = output; if (!parser.CheckNext(",")) { parser.SetPos(oldPos); return false; } parser.Expect(","); if (int.TryParse(parser.ReadNext(), out output)) value.Y = output; parser.Expect(")"); return true; } public override string GetAsString(int indent = 0) { return base.GetAsString(indent) + string.Concat(Enumerable.Repeat(" ", indent)) + "pos: " + value.ToString() + Environment.NewLine; } } class RoseValue : RoseItem { public string value; public RoseValue() { value = ""; } public bool Parse(Parser parser) { ParserPos oldPos = parser.GetPos(); parser.Expect("("); if (!parser.CheckNext("value")) { parser.SetPos(oldPos); return false; } parser.Expect("value"); name = parser.ReadNext(); if (parser.CheckNext("\r")) { parser.Expect("\r"); while (parser.CheckNext("|")) { parser.Expect("|"); value += parser.ReadUntil('\r') + Environment.NewLine; parser.Expect("\r"); } } else { value = parser.ReadNext(); } parser.Expect(")"); return true; } public override string GetAsString(int indent = 0) { return base.GetAsString(indent) + string.Concat(Enumerable.Repeat(" ", indent)) + "value: " + value + Environment.NewLine; } public override List Find(string text, bool exact = true) { List result = new List(); if (((text == value) && exact) || ((value.Contains(text)) && !exact)) result.Add(this); return result; } } class RoseList : RoseItem { public List items; public RoseList() { items = new List(); } public bool Parse(Parser parser) { ParserPos oldPos = parser.GetPos(); parser.Expect("("); if (!parser.CheckNext("list")) { parser.SetPos(oldPos); return false; } parser.Expect("list"); if (!parser.CheckNext("\r")) { name = parser.ReadNext(); } else name = ""; if (!parser.CheckNext(")")) { parser.Expect("\r"); while (!parser.CheckNext(")")) { RoseObject obj = new RoseObject(); if (obj.Parse(parser)) { obj.parent = this; items.Add(obj); } else { if (parser.CheckNext("(")) { RosePoint point = new RosePoint(); point.Parse(parser); point.parent = this; items.Add(point); } else { // Read string RoseString str = new RoseString(parser.ReadNext()); } } if (parser.CheckNext(")")) { break; } else { parser.Expect("\r"); } } } parser.Expect(")"); return true; } public override string GetAsString(int indent = 0) { string result = string.Concat(Enumerable.Repeat(" ", indent)) + "list (" + Environment.NewLine; foreach(RoseItem item in items) { result += item.GetAsString(indent + 1); } result = result + string.Concat(Enumerable.Repeat(" ", indent)) + ")" + Environment.NewLine; return result; } public override List Find(string text, bool exact = true) { List result = new List(); if (name == text) result.Add(this); int i = 0; while (i < items.Count) { result.AddRange(items[i].Find(text, exact)); i++; } return result; } } class RoseObject : RoseItem { public string text; // kind public string text2; // name public string text3; public string reference; public List> items; public RoseObject() { items = new List>(); text = ""; text2 = ""; reference = ""; } public bool Parse(Parser parser) { ParserPos oldPos = parser.GetPos(); if (!parser.CheckNext("(")) { parser.SetPos(oldPos); return false; } parser.Expect("("); if (!parser.CheckNext("object")) { parser.SetPos(oldPos); return false; } parser.Expect("object"); name = parser.ReadNext(); if (!parser.CheckNext("\r")) { text = parser.ReadNext(); if (!parser.CheckNext("\r")) { text2 = parser.ReadNext(); if ((text2 != "") && (text2[0] == '@')) { reference = text2; text2 = ""; } else if (!parser.CheckNext("\r")) { text3 = parser.ReadNext(); if ((text3 != "") && (text3[0] == '@')) { reference = text3; text3 = ""; } else if (!parser.CheckNext("\r")) { reference = parser.ReadNext(); } } } } parser.Expect("\r"); while (!parser.CheckNext(")")) { string key = parser.ReadNext(); if (parser.CheckNext("(")) { RoseObject obj = new RoseObject(); if (obj.Parse(parser)) { obj.parent = this; items.Add(new KeyValuePair(key, obj)); } else { RoseList list = new RoseList(); if (list.Parse(parser)) { list.parent = this; items.Add(new KeyValuePair(key, list)); } else { RoseValue value = new RoseValue(); if (value.Parse(parser)) { value.parent = this; items.Add(new KeyValuePair(key, value)); } else { RosePoint point = new RosePoint(); if (point.Parse(parser)) { point.parent = this; items.Add(new KeyValuePair(key, point)); } else { do { value.value = parser.ReadNext(); if (parser.CheckNext(")")) break; } while (true); parser.Expect(")"); } } } } } else if (parser.CheckNext("\r")) { RoseString value = new RoseString(""); parser.Expect("\r"); while(parser.CheckNext("|")) { parser.Expect("|"); value.value += parser.ReadUntil('\r') + Environment.NewLine; parser.Expect("\r"); } items.Add(new KeyValuePair(key, value)); } else { RoseString value = new RoseString(parser.ReadNext()); items.Add(new KeyValuePair(key, value)); } if (parser.CheckNext(")")) { break; } else { while (parser.CheckNext("\r")) parser.Expect("\r"); } } parser.Expect(")"); return true; } public override string GetAsString(int indent = 0) { string result = string.Concat(Enumerable.Repeat(" ", indent)) + "object (" + Environment.NewLine; if (name != "") result += string.Concat(Enumerable.Repeat(" ", indent + 1)) + "name: " + name + Environment.NewLine; if (text != "") result += string.Concat(Enumerable.Repeat(" ", indent + 1)) + "text: " + text + Environment.NewLine; if (text2 != "") result += string.Concat(Enumerable.Repeat(" ", indent + 1)) + "text2: " + text2 + Environment.NewLine; if (reference != "") result += string.Concat(Enumerable.Repeat(" ", indent + 1)) + "reference: " + reference + Environment.NewLine; foreach (var item in items) { result += string.Concat(Enumerable.Repeat(" ", indent + 1)) + "key: " + item.Key + " (" + Environment.NewLine + item.Value.GetAsString(indent + 2); result += string.Concat(Enumerable.Repeat(" ", indent + 1)) + ")" + Environment.NewLine; } result = result + string.Concat(Enumerable.Repeat(" ", indent)) + ")" + Environment.NewLine; return result; } public override List Find(string text, bool exact = true) { List result = new List(); if ((((text == this.name) && exact) || ((this.text.Contains(name)) && !exact)) || (((text == this.text) && exact) || ((this.text.Contains(text)) && !exact)) || (((text == this.text2) && exact) || ((this.text2.Contains(text)) && !exact)) || (((text == this.reference) && exact) || ((this.reference.Contains(text)) && !exact))) result.Add(this); int i = 0; while (i < items.Count) { result.AddRange(items[i].Value.Find(text, exact)); i++; } return result; } } class RoseModel { public List objects; public RoseModel() { objects = new List(); } public void ParseFile(string fileName) { //try //{ objects.Clear(); Parser parser = new Parser(); parser.content = File.ReadAllText(fileName, Encoding.Default); // Skip zero size files. They are probably files not accessible from current ClearCase view. if (parser.content.Length == 0) return; do { RoseObject obj = new RoseObject(); if (parser.CheckNext("\r")) parser.Expect("\r"); obj.Parse(parser); objects.Add(obj); parser.Expect("\r"); } while (parser.CheckNext("\r")); //} catch (Exception e) //{ // MessageBox.Show(e.ToString(), "Error"); //} } public string GetAsString() { string result = ""; foreach (var obj in objects) { result += obj.GetAsString() + Environment.NewLine; } return result; } public List Find(string text, bool exact = true) { List result = new List(); int i = 0; while (i < objects.Count) { result.AddRange(objects[i].Find(text, exact)); i++; } return result; } } }