using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using System.IO; using System.Windows.Forms; namespace cakePawn.Library { internal class LibraryFile { internal string FileName; internal string FileData; internal bool[] listExclude; internal List listEntries; internal LibraryFile(string path) { FileName = path; listEntries = new List(); } private LibraryEntry addEntry(string name, string description, LibraryEntry.DefinitionTypes type) { LibraryEntry lm = new LibraryEntry(name, description, type); listEntries.Add(lm); return lm; } private static int Count(string src, char find) { int ret = 0; foreach (char s in src) { if (s == find) { ++ret; } } return ret; } internal List getMethods() { List ret = new List(); foreach (LibraryEntry e in listEntries) { if (e.DefinitionType == LibraryEntry.DefinitionTypes.typeMethod) ret.Add(e); } return ret; } private bool parseMatchCheck(Match m) { for (int i = m.Index; i < m.Index + m.Length - 1; i++) { if (!parsePositionCheck(i)) return false; } return true; } private bool parsePositionCheck(int pos) { bool ret = !listExclude[pos]; return ret; } private void excludeRange(int start, int stop) { for (int i = start; i <= stop; i++) listExclude[i] = true; } private int parseIndexOf(string source, string sub, int start, bool backwards) { if (backwards && start > 0) start--; if (source.Length - start < 0) return -1; if (sub != null && source != null && sub.Length > 0 && sub.Length <= source.Length) { char searchChar = sub[0]; if (backwards) { for (int i = start; i > 0; i--) { if (source[i] == searchChar) { for (int j = 1; j < sub.Length; j++) { if (source[i + j] != sub[j]) { goto nextBack; } } return i; } nextBack: ; } } else { for (int i = start; i < (source.Length - sub.Length + 1); i++) { if (source[i] == searchChar) { for (int j = 1; j < sub.Length; j++) { if (source[i + j] != sub[j]) { goto nextForward; } } bool unmarked = parsePositionCheck(i); if (unmarked) { return i; } else { goto nextForward; } } nextForward: ; } } } return -1; } private bool countBrackets(string parseStr) { int start = 0; int stop = 0; for (int i = 0; i < parseStr.Length; i++) { char s = parseStr[i]; if (s == '{' && !listExclude[i]) { start++; } if (s == '}' && !listExclude[i]) { stop++; } } return (start == stop); } internal void parseString(string parseStr, bool verbose) { MatchCollection mc; Regex re = null; listExclude = new bool[parseStr.Length]; listEntries.Clear(); //Empty for re-read bool parseFault = false; for (int i = 1; i <= 3; i++) { switch (i) { case 1: re = new Regex("\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\/");//mark block comments break; case 2: re = new Regex("\\/\\/.*"); //mark line comments); break; case 3: re = new Regex("'(\\\\?).'"); //mark char constants to avoid parser confusion break; } mc = re.Matches(parseStr); foreach (Match m in mc) { excludeRange(m.Index, m.Index + m.Length - 1); } } int curPos = 0; int startDefinePos = 0; while ((startDefinePos = parseIndexOf(parseStr, "#define ", curPos, false)) != -1) { int endSearch = 0; int endPos = 0; int curEndPos = startDefinePos; while ((endSearch = parseStr.IndexOf("\n", curEndPos)) != -1) { string endStr = parseStr.Substring(endSearch - 2, 1); if (endStr != "\\") { endPos = endSearch; break; } else { curEndPos = endSearch + 1; } } curPos = endPos; //Set new start pos for next search excludeRange(startDefinePos, endPos); string define = parseStr.Substring(startDefinePos, endPos - startDefinePos); define = define.Trim(); int defineEnd = define.IndexOf(' ', 8); if (defineEnd == -1) { defineEnd = define.IndexOf('\t', 8); if (defineEnd == -1) defineEnd = define.Length; } string shortname = define.Substring(8, defineEnd - 8); LibraryEntry le = addEntry(shortname, define, LibraryEntry.DefinitionTypes.typeDefinition); le.StartPos = startDefinePos; le.EndPos = endPos; } //String literal crawler curPos = 0; startDefinePos = 0; while ((startDefinePos = parseIndexOf(parseStr, "\"", curPos, false)) != -1) { int endSearch = 0; int endPos = 0; int curEndPos = startDefinePos + 1; while ((endSearch = parseStr.IndexOf("\"", curEndPos)) != -1) { string endStr = ""; if (endSearch >= 2) endStr = parseStr.Substring(endSearch - 2, 2); if ((endSearch == 1) || (endStr[1] != '\\') || (endStr[0] == '\\' && endStr[1] == '\\')) //check so it's not an escaped char { endPos = endSearch; break; } else //is escaped { curEndPos = endSearch + 1; } } if (endPos == 0) { parseFault = true; //unterminated string break; } curPos = endPos + 1; //Set new start pos for next search excludeRange(startDefinePos + 1, endPos - 1); } //find and mark code blocks {...} int startPos; //always contains the top-level opening bracket. int lastBracketPos = 0; if (!countBrackets(parseStr)) parseFault = true; while ((startPos = parseIndexOf(parseStr, "{", lastBracketPos, false)) != -1 && !parseFault) //find any start bracket { int bracketLevel = 1; lastBracketPos = startPos; while (!parseFault && bracketLevel > 0) //crawl file for brackets { //Loop until we found all sub blocks int closingBracket = parseIndexOf(parseStr, "}", lastBracketPos + 1, false); //find next end bracket int substartBracket = parseIndexOf(parseStr, "{", lastBracketPos + 1, false); //find next start bracket if (closingBracket == -1 && substartBracket > -1) { parseFault = true; break; } else if (closingBracket > -1 && substartBracket == -1) { bracketLevel--; lastBracketPos = closingBracket; } else if (closingBracket > substartBracket) { bracketLevel++; lastBracketPos = substartBracket; } else if (closingBracket < substartBracket) { bracketLevel--; lastBracketPos = closingBracket; } else if (closingBracket == -1 && substartBracket == -1) { //bracket expected but none found parseFault = true; break; } } if (parseFault) break; excludeRange(startPos, lastBracketPos); ; //Remove block and sub blocks } if (parseFault) { if (verbose) MessageBox.Show("Error parsing " + FileName); } else { //update parsestring int writePos = 0; char[] newstr = new char[parseStr.Length]; int[] offsetMap = new int[parseStr.Length]; for (int i = 0; i < newstr.Length; i++) { if (!listExclude[i]) { newstr[writePos] = parseStr[i]; offsetMap[writePos] = i; writePos++; if (newstr[writePos - 1] == '\"') {//include string literals in the function def search while (listExclude[i + 1]) { newstr[writePos] = parseStr[i + 1]; writePos++; i++; } } } } parseStr = new String(newstr, 0, writePos); //Find method definitions string functionDefs = "[\\r\\n]\\s*(native |stock |public |static |forward |.+:)*\\s*@?\\w+?\\s*\\([^\\)]*\\)"; Regex reFd = new Regex(functionDefs); MatchCollection functionMatches = reFd.Matches(parseStr); Regex funcNameFinder = new Regex("\\w+\\("); int matches = functionMatches.Count; for (int i = 0; i < matches; i++) { Match m = functionMatches[i]; string line = m.Value.Replace("\r\n", "").Trim(); //remove linebreaks and trim spaces while (line != (line = line.Replace(" ", " "))) ; //Remove doublespaces if (line.StartsWith("forward")) { //forwards.Add(line); } else { //functions.Add(line); Match funcNameMatch = funcNameFinder.Match(line); if (funcNameMatch.Success) { LibraryEntry le = addEntry(funcNameMatch.Value.Substring(0, funcNameMatch.Value.Length - 1), line, LibraryEntry.DefinitionTypes.typeMethod); try { int spos = 0; while (m.Value[spos] == '\r' || m.Value[spos] == '\n' || m.Value[spos] == ' ') spos++; le.StartPos = offsetMap[m.Index + spos]; le.EndPos = offsetMap[m.Index + m.Length]; } catch { } } } } } } internal void parseFile() { //System.Console.WriteLine("parsing " + FileName); int incPos = FileName.LastIndexOf("include\\"); string shortName = FileName.Substring(incPos); frmSplash.setText(shortName); try { StreamReader streamReader1 = File.OpenText(FileName); FileData = streamReader1.ReadToEnd(); parseString(FileData, true); } catch { } } } }