private void ParseFunctionArgList(Symbol s, string content) { s.parameters.Clear(); int endIdx; content = FindStringInBetween(content, 0, "<table class=\"memname\">", "</table>", out endIdx); if (endIdx == -1) return; int startIdx = 0; while (startIdx < content.Length) { string paramType = FindStringInBetween(content, startIdx, "<td class=\"paramtype\">", "</td>", out endIdx); if (endIdx == -1) return; startIdx = endIdx+1; string paramName = FindStringInBetween(content, startIdx, "<td class=\"paramname\">", "</td>", out endIdx); if (endIdx == -1) return; startIdx = endIdx + 1; string strippedParamName = FindStringInBetween(paramName, 0, "<em>", "</em>", out endIdx); Parameter p = new Parameter(); p.type = paramType.StripHtmlCharacters().StripHtmlLinks(); p.name = strippedParamName.StripHtmlCharacters().StripHtmlLinks(); s.parameters.Add(p); } }
/* /// <summary> /// Each doxygen documentation file on a class contains a single class comment near the top of the page. /// </summary> /// <param name="dataString"></param> private void ParseDocumentationFileForClassComments(string dataString) { int endIndex; string className = FindStringInBetween(dataString, 0, "<!-- doxytag: class=\"", "\" -->", out endIndex); if (endIndex == -1) return; if (!symbols.ContainsKey(className)) return; Symbol classSymbol = symbols[className]; string classComments = FindStringInBetween(dataString, endIndex, "<hr/><a name=\"_details\"></a><h2>Detailed Description</h2>", "<hr/><h2>Member", out endIndex); if (endIndex != -1) { classSymbol.comments.AddRange(SplitToParagraphs(classComments)); } } */ /* /// <summary> /// Breaks down the single string form arglist into a member args list structure. /// </summary> /// <param name="s"></param> static private void GenerateArgList(Symbol s) { s.parameters.Clear(); string argList = s.argList; if (argList.StartsWith("(")) argList = argList.Substring(1); if (argList.EndsWith(")")) argList = argList.Substring(0, argList.Length - 1); if (argList.EndsWith(")=0")) argList = argList.Substring(0, argList.Length - 3); argList = argList.Trim(); if (argList.Length == 0) return; string[] args = argList.Split(','); foreach (string arg in args) { string a = arg.Trim(); // int lastSpace = a.LastIndexOf(' '); Parameter p = new Parameter(); p.type = a.StripHtmlCharacters().StripHtmlLinks();// a.Substring(0, lastSpace).Trim(); // p.name = a.Substring(lastSpace + 1, a.Length - (lastSpace + 1)).Trim(); s.parameters.Add(p); } } private void ParseFunctionArgList(Symbol s, string content) { s.parameters.Clear(); int endIdx; content = FindStringInBetween(content, 0, "<table class=\"memname\">", "</table>", out endIdx); if (endIdx == -1) return; int startIdx = 0; while (startIdx < content.Length) { string paramType = FindStringInBetween(content, startIdx, "<td class=\"paramtype\">", "</td>", out endIdx); if (endIdx == -1) return; startIdx = endIdx+1; string paramName = FindStringInBetween(content, startIdx, "<td class=\"paramname\">", "</td>", out endIdx); if (endIdx == -1) return; startIdx = endIdx + 1; string strippedParamName = FindStringInBetween(paramName, 0, "<em>", "</em>", out endIdx); Parameter p = new Parameter(); p.type = paramType.StripHtmlCharacters().StripHtmlLinks(); p.name = strippedParamName.StripHtmlCharacters().StripHtmlLinks(); s.parameters.Add(p); } } private void ParseFunctionParameterComments(Symbol s, string memdocContent) { int endIdx; string memberData = FindStringInBetween(memdocContent, 0, "<dl><dt><b>Parameters:</b></dt><dd>", "</table>", out endIdx); if (endIdx == -1) return; int startIdx = 0; while(startIdx < memberData.Length) { string row = FindStringInBetween(memberData, startIdx, "<tr>", "</tr>", out endIdx); if (endIdx == -1) return; startIdx = endIdx+1; int paramNameEnd; string paramName = FindStringInBetween(row, 0, "<em>", "</em>", out paramNameEnd); paramName = paramName.Trim(); if (paramNameEnd == -1) continue; int cmEnd; string comment = FindStringInBetween(row, paramNameEnd, "<td>", "</td>", out cmEnd); if (cmEnd == -1) continue; Parameter param = s.FindParamByName(paramName); if (param == null) continue; param.comment = comment.Trim(); } } private void ParseFunctionReturnValueComments(Symbol s, string memdocContent) { int endIdx; string memberData = FindStringInBetween(memdocContent, 0, "<dl class=\"return\"><dt><b>Returns:</b></dt><dd>", "</dd></dl>", out endIdx); if (endIdx == -1) return; s.returnComment = memberData; } private void ParseDocumentationFileForBriefMemberComments(string dataString) { int startIdx = 0; while(startIdx < dataString.Length) { int endIdx; string elemRefStr = "<tr><td class=\"memItemLeft\" align=\"right\" valign=\"top\">"; string memberLine1 = FindStringInBetween(dataString, startIdx, elemRefStr, "</tr>", out endIdx); if (endIdx == -1) return; startIdx = endIdx + 1; int endIdx2; int nextElemRefEnd; string nextElemRef = FindStringInBetween(dataString, endIdx+1, elemRefStr, "</tr>", out nextElemRefEnd); string memberLine2 = FindStringInBetween(dataString, endIdx + 1, "<tr><td class=\"mdescLeft\">", "</tr>", out endIdx2); if (endIdx2 == -1) continue; if (endIdx2 >= nextElemRefEnd) continue; // Parsed too far with the comment line. startIdx = endIdx2 + 1; // Find the ref this brief comment is for. string refString = FindStringInBetween(memberLine1, 0, " ref=\"", "\"", out endIdx); if (endIdx == -1) continue; if (!symbolsByAnchor.ContainsKey(refString)) continue; Symbol s = symbolsByAnchor[refString]; string briefComment = FindStringInBetween(memberLine2, 0, "<td class=\"mdescRight\">", "</td>", out endIdx); if (endIdx == -1) continue; s.comments.Add(briefComment); } } private void ParseDocumentationFile(string filename) { // Console.WriteLine("Parsing documentation from file \"" + filename + "\""); TextReader t; try { t = new StreamReader(filename); } catch(System.IO.FileNotFoundException) { return; } string dataString = t.ReadToEnd(); ParseDocumentationFileForClassComments(dataString); ParseDocumentationFileForBriefMemberComments(dataString); int startIndex = 0; int strLen = dataString.Length; while (startIndex < strLen) { int index = dataString.IndexOf("doxytag:", startIndex); if (index == -1) break; startIndex = index + 1; int refStartIndex = dataString.IndexOf(" ref=\"", startIndex); if (refStartIndex == -1) break; int refIndex = refStartIndex + 6; int refEndIndex = dataString.IndexOf("\"", refIndex); if (refEndIndex == -1) break; startIndex = refEndIndex + 1; string anchorRef = dataString.Substring(refIndex, refEndIndex - refIndex); if (!symbolsByAnchor.ContainsKey(anchorRef)) continue; Symbol s = symbolsByAnchor[anchorRef]; // Try to find memdoc content (detailed comment block). int memdocEnd; string memdocContent; bool success = FindMemdocContent(dataString, startIndex, out memdocContent, out memdocEnd); if (success) { s.comments.AddRange(SplitToParagraphs(memdocContent)); if (s.kind == "function") { int protoEndIdx; string memProto = FindStringInBetween(dataString, startIndex, "<div class=\"memproto\">", "</div>", out protoEndIdx); if (protoEndIdx != -1) ParseFunctionArgList(s, memProto); ParseFunctionParameterComments(s, memdocContent); ParseFunctionReturnValueComments(s, memdocContent); } startIndex = memdocEnd + 1; } else { success = FindBriefdocContent(dataString, startIndex, out memdocContent, out memdocEnd); if (success) { s.comments.AddRange(SplitToParagraphs(memdocContent)); startIndex = memdocEnd + 1; } } } foreach (Symbol s in symbolsByAnchor.Values) ProcessDocGeneratorCommentDirectives(s); // XmlDocument doc = new XmlDocument(); // doc.XmlResolver = null; // doc.LoadXml(dataString); /* HTMLDocument doc = new HTMLDocument(); IHTMLDocument2 doc2 = (IHTMLDocument2)doc; doc2.write(dataString); doc.get */ // WebBrowser wb = new WebBrowser(); // wb.DocumentText = dataString; // HtmlDocument doc = wb.Document;// new HtmlDocument(); // doc. // doc. /* List<XmlElement> anchorElements = new List<XmlElement>(); FindAnchorElements(doc.DocumentElement, anchorElements); foreach (XmlElement n in anchorElements) { XmlElement memDocSibling = FindMemDocSibling(n); Symbol s = symbolsByAnchor[memDocSibling.GetAttribute("id")]; List<XmlElement> paragraphs = GetChildElementsByName(memDocSibling, "p"); foreach (XmlElement p in paragraphs) { s.comments.Add(p.InnerXml); } } */ // } public void ParseSectionDefElement(Symbol parent, XmlElement e) { foreach(XmlElement child in e.ChildNodes) { if (child.Name == "memberdef") { Symbol member = new Symbol(); member.parent = parent; member.id = child.GetAttribute("id"); member.kind = child.GetAttribute("kind"); member.visibilityLevel = ParseVisibilityLevel(child.GetAttribute("prot")); member.isStatic = (child.GetAttribute("static") == "yes"); member.isConst = (child.GetAttribute("const") == "yes"); member.isMutable = (child.GetAttribute("mutable") == "yes"); member.isExplicit = (child.GetAttribute("explicit") == "yes"); member.virtualness = ParseVirtualness(child.GetAttribute("virt")); member.type = GetXmlElementChildNodeValue(child, "type", true); member.fullDefinition = GetXmlElementChildNodeValue(child, "definition"); member.argList = GetXmlElementChildNodeValue(child, "argsstring"); member.classMemberIndexTitle = member.name = GetXmlElementChildNodeValue(child, "name"); if (member.name.StartsWith("@")) continue; // Doxygen creates items with names starting with '@' at least for unnamed unions, ignore those altogether. symbols[member.id] = member; // symbolsByName[member.name] = member; parent.children.Add(member); // Function parameters. foreach(XmlElement param in child.ChildNodes.OfType<XmlElement>()) if (param.Name == "param") { Parameter p = new Parameter(); if (member.kind == "define") // This is a #define macro. { p.type = ""; p.name = GetXmlElementChildNodeValue(param, "defname"); } else // This is a real function { p.type = GetXmlElementChildNodeValue(param, "type", true); p.name = GetXmlElementChildNodeValue(param, "declname"); } member.parameters.Add(p); } // If this is a #define macro, get the macro body code. if (member.kind == "define") { member.macroBody = GetXmlElementChildNodeValue(child, "initializer"); // Create the argList from scratch, because it is not present in the xml in same form than for functions. member.argList = member.ArgStringWithoutTypes(); } // Function parameter comments. List<XmlElement> parameters = child.AllGrandChildElementsOfTypeAndAttribute("parameterlist", "kind", "param"); if (parameters != null && parameters.Count > 0) { foreach (XmlElement paramNode in parameters.OfType<XmlElement>()) { foreach (XmlElement param in paramNode.ChildNodes.OfType<XmlElement>()) { if (param.Name == "parameteritem") { string paramName = param.FirstChildElementOfType("parameternamelist").FirstChildElementOfType("parametername").InnerText.Trim(); Parameter p = member.FindParamByName(paramName); if (p != null) p.comment = param.FirstChildElementOfType("parameterdescription").InnerText; } } // Remove the parameterlist from the detailed description node so that it won't appear in the 'detailedDescription' documentation string. // The detailed description is created manually. paramNode.ParentNode.RemoveChild(paramNode); } } // TODOs ^ BUGs List<XmlElement> xrefsects = child.AllGrandChildElementsOfType("xrefsect"); if (xrefsects != null) { foreach (XmlElement elem in xrefsects) { if (GetXmlElementChildNodeValue(elem, "xreftitle") == "Todo") member.todos.Add(GetXmlElementChildNodeValue(elem, "xrefdescription")); if (GetXmlElementChildNodeValue(elem, "xreftitle") == "Bug") member.bugs.Add(GetXmlElementChildNodeValue(elem, "xrefdescription")); elem.ParentNode.RemoveChild(elem); } } // @notes. List<XmlElement> notesects = child.AllGrandChildElementsOfTypeAndAttribute("simplesect", "kind", "note"); if (notesects != null) { foreach (XmlElement elem in notesects) { member.notes.Add(elem.InnerText); elem.ParentNode.RemoveChild(elem); } } // Function return value. XmlElement retVal = child.FirstGrandChildElementOfTypeAndAttribute("simplesect", "kind", "return"); if (retVal != null) { member.returnComment = retVal.InnerText; retVal.ParentNode.RemoveChild(retVal); } // The "see also" section. XmlElement see = child.FirstGrandChildElementOfTypeAndAttribute("simplesect", "kind", "see"); if (see != null) { member.seeAlsoDocumentation = see.InnerXml; see.ParentNode.RemoveChild(see); } member.briefDescription = GetXmlElementChildNodeValue(child, "briefdescription").Trim(); member.inbodyDescription = GetXmlElementChildNodeValue(child, "inbodydescription").Trim(); member.detailedDescription = GetXmlElementChildNodeValue(child, "detaileddescription").Trim(); XmlElement loc = child.FirstChildElementOfType("location"); if (loc != null) { member.sourceFilename = loc.GetAttribute("bodyfile"); int.TryParse(loc.GetAttribute("bodystart"), out member.sourceFileStartLine); int.TryParse(loc.GetAttribute("bodyend"), out member.sourceFileEndLine); if (member.sourceFileEndLine == -1) member.sourceFileEndLine = member.sourceFileStartLine; } ProcessDocGeneratorCommentDirectives(member); ///\todo Add location. } } }
/// <summary> /// Breaks down the single string form arglist into a member args list structure. /// </summary> /// <param name="s"></param> private static void GenerateArgList(Symbol s) { s.parameters.Clear(); string argList = s.argList; if (argList.StartsWith("(")) argList = argList.Substring(1); if (argList.EndsWith(")")) argList = argList.Substring(0, argList.Length - 1); if (argList.EndsWith(")=0")) argList = argList.Substring(0, argList.Length - 3); argList = argList.Trim(); if (argList.Length == 0) return; string[] args = argList.Split(','); foreach (string arg in args) { string a = arg.Trim(); // int lastSpace = a.LastIndexOf(' '); Parameter p = new Parameter(); p.type = a.StripHtmlCharacters().StripHtmlLinks();// a.Substring(0, lastSpace).Trim(); // p.name = a.Substring(lastSpace + 1, a.Length - (lastSpace + 1)).Trim(); s.parameters.Add(p); } }