diff options
author | Jeff Johnston | 2014-08-08 22:11:06 +0000 |
---|---|---|
committer | Alexander Kurtakov | 2014-08-12 18:59:44 +0000 |
commit | 94a114eb8503463214e225d5863b86bab36b2484 (patch) | |
tree | 50dcbb5a5741e07d66dd6b77825a0b594f288d74 /libhover/org.eclipse.linuxtools.cdt.libhover.devhelp | |
parent | a2532b8e8f6580c45d2b3f89f685c4ab694d9a04 (diff) | |
download | org.eclipse.linuxtools-94a114eb8503463214e225d5863b86bab36b2484.tar.gz org.eclipse.linuxtools-94a114eb8503463214e225d5863b86bab36b2484.tar.xz org.eclipse.linuxtools-94a114eb8503463214e225d5863b86bab36b2484.zip |
Bug 440843 - High CPU usage for library hover generation at startup
- add check for modification time of the devhelp libhover file
compared to the input directory
- rewrite the devhelp parser to collect all the function links
based on file name and then to process each file one at a time
and gather the whole set of functions at once
- bump up the minor release of the devhelp plug-in and libhover feature
Change-Id: I5fb8c55da2d59ccb0007843634635baa8f97e23b
Reviewed-on: https://git.eclipse.org/r/31327
Reviewed-by: Alexander Kurtakov <akurtako@redhat.com>
Tested-by: Alexander Kurtakov <akurtako@redhat.com>
Diffstat (limited to 'libhover/org.eclipse.linuxtools.cdt.libhover.devhelp')
4 files changed, 479 insertions, 411 deletions
diff --git a/libhover/org.eclipse.linuxtools.cdt.libhover.devhelp/META-INF/MANIFEST.MF b/libhover/org.eclipse.linuxtools.cdt.libhover.devhelp/META-INF/MANIFEST.MF index 9ec46a401e..80fa4f4bfb 100644 --- a/libhover/org.eclipse.linuxtools.cdt.libhover.devhelp/META-INF/MANIFEST.MF +++ b/libhover/org.eclipse.linuxtools.cdt.libhover.devhelp/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %bundleName Bundle-SymbolicName: org.eclipse.linuxtools.cdt.libhover.devhelp; singleton:=true -Bundle-Version: 1.0.0.qualifier +Bundle-Version: 1.1.0.qualifier Bundle-Activator: org.eclipse.linuxtools.internal.cdt.libhover.devhelp.DevHelpPlugin Bundle-Localization: plugin Require-Bundle: org.eclipse.ui, diff --git a/libhover/org.eclipse.linuxtools.cdt.libhover.devhelp/pom.xml b/libhover/org.eclipse.linuxtools.cdt.libhover.devhelp/pom.xml index 17e1a54ccd..53d8b4e072 100644 --- a/libhover/org.eclipse.linuxtools.cdt.libhover.devhelp/pom.xml +++ b/libhover/org.eclipse.linuxtools.cdt.libhover.devhelp/pom.xml @@ -18,7 +18,7 @@ </parent> <artifactId>org.eclipse.linuxtools.cdt.libhover.devhelp</artifactId> - <version>1.0.0-SNAPSHOT</version> + <version>1.1.0-SNAPSHOT</version> <packaging>eclipse-plugin</packaging> <name>Linux Tools Devhelp Libhover Plug-in</name> diff --git a/libhover/org.eclipse.linuxtools.cdt.libhover.devhelp/src/org/eclipse/linuxtools/internal/cdt/libhover/devhelp/DevHelpPlugin.java b/libhover/org.eclipse.linuxtools.cdt.libhover.devhelp/src/org/eclipse/linuxtools/internal/cdt/libhover/devhelp/DevHelpPlugin.java index 83edd24daa..36e5cf5bb2 100644 --- a/libhover/org.eclipse.linuxtools.cdt.libhover.devhelp/src/org/eclipse/linuxtools/internal/cdt/libhover/devhelp/DevHelpPlugin.java +++ b/libhover/org.eclipse.linuxtools.cdt.libhover.devhelp/src/org/eclipse/linuxtools/internal/cdt/libhover/devhelp/DevHelpPlugin.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2013 Red Hat Inc. and others. + * Copyright (c) 2012-2014 Red Hat Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -19,6 +19,7 @@ import java.util.Collection; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.preference.IPreferenceStore; @@ -116,6 +117,29 @@ public class DevHelpPlugin extends AbstractUIPlugin implements IStartup { return Status.CANCEL_STATUS; IPreferenceStore ps = DevHelpPlugin.getDefault() .getPreferenceStore(); + String devhelpDir = ps.getString(PreferenceConstants.DEVHELP_DIRECTORY); + IPath devhelpPath = new Path(devhelpDir); + File devhelp = devhelpPath.toFile(); + if (!devhelp.exists()) { + // No input data to process so quit now + monitor.done(); + return Status.OK_STATUS; + } + long ltime = devhelp.lastModified(); + IPath libhoverPath = LibhoverPlugin.getDefault() + .getStateLocation().append("C").append("devhelp.libhover"); //$NON-NLS-1$ //$NON-NLS-2$ + File libhoverDir = new File(libhoverPath.toOSString()); + if (libhoverDir.exists()) { + long ltime2 = libhoverDir.lastModified(); + // Check the last modified time of the devhelp libhover file compared to the + // devhelp directory we use to parse the data + if (ltime < ltime2) { + // Our devhelp info is up to date and is older than the last modification to + // the devhelp input data so stop now + monitor.done(); + return Status.OK_STATUS; + } + } ParseDevHelp.DevHelpParser p = new ParseDevHelp.DevHelpParser( ps.getString(PreferenceConstants.DEVHELP_DIRECTORY)); LibHoverInfo hover = p.parse(monitor); diff --git a/libhover/org.eclipse.linuxtools.cdt.libhover.devhelp/src/org/eclipse/linuxtools/internal/cdt/libhover/devhelp/ParseDevHelp.java b/libhover/org.eclipse.linuxtools.cdt.libhover.devhelp/src/org/eclipse/linuxtools/internal/cdt/libhover/devhelp/ParseDevHelp.java index 03b35f05bd..433c03582f 100644 --- a/libhover/org.eclipse.linuxtools.cdt.libhover.devhelp/src/org/eclipse/linuxtools/internal/cdt/libhover/devhelp/ParseDevHelp.java +++ b/libhover/org.eclipse.linuxtools.cdt.libhover.devhelp/src/org/eclipse/linuxtools/internal/cdt/libhover/devhelp/ParseDevHelp.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 Red Hat Inc. and others. + * Copyright (c) 2011, 2014 Red Hat Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -20,6 +20,9 @@ import java.io.ObjectOutputStream; import java.io.StringReader; import java.util.Arrays; import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -53,430 +56,471 @@ import org.xml.sax.SAXException; public class ParseDevHelp { - private final static String PARSING_MSG = "Libhover.Devhelp.Parsing.msg"; //$NON-NLS-1$ - private final static String PARSING_FMT_MSG = "Libhover.Devhelp.Parsing.fmt.msg"; //$NON-NLS-1$ - private static class HTMLSaxParser extends AbstractSAXParser { + private final static String PARSING_MSG = "Libhover.Devhelp.Parsing.msg"; //$NON-NLS-1$ + private final static String PARSING_FMT_MSG = "Libhover.Devhelp.Parsing.fmt.msg"; //$NON-NLS-1$ + private static class HTMLSaxParser extends AbstractSAXParser { - private String func; - private boolean begin; - private boolean refsect2; - private boolean returnType; - private boolean protoStart; - private boolean parmStart; - private boolean descStart; - private boolean rowIgnore; - private boolean valid = true; - private String returnValue; - private String funcName; - private String rowTag; - private StringBuilder prototype = new StringBuilder(); - private StringBuilder description = new StringBuilder(); - private int divCounter; - private int rowItemCount; + private boolean begin; + private boolean refsect2; + private boolean returnType; + private boolean protoStart; + private boolean parmStart; + private boolean descStart; + private boolean rowIgnore; + private boolean valid = true; + private HashMap<String, String> funcs; + private String returnValue; + private String funcName; + private String rowTag; + private StringBuilder prototype = new StringBuilder(); + private StringBuilder description = new StringBuilder(); + private int divCounter; + private int rowItemCount; + private TreeMap<String, FunctionInfo> infos = new TreeMap<>(); - public HTMLSaxParser(String func, String funcName) { - super(new HTMLConfiguration()); - this.func = func; - this.funcName = funcName.trim(); - if (this.funcName.endsWith("()")) { //$NON-NLS-1$ - // Remove () at end of function name and remove all space chars which might be - // non-breaking space chars which unfortunately do not get caught by the trim() method. - this.funcName = this.funcName.replaceAll("\\(\\)", "").replaceAll("\\p{javaSpaceChar}",""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - } - } + public HTMLSaxParser(HashMap<String, String> funcs) { + super(new HTMLConfiguration()); + this.funcs = funcs; + } - @Override - public void startElement(QName name, XMLAttributes a, Augmentations aug) { - if ("A".equals(name.rawname)) { //$NON-NLS-1$ - String fname = a.getValue("name"); //$NON-NLS-1$ - if (func.equals(fname)) { - begin = true; - divCounter = refsect2 ? 1 : 0; - refsect2 = false; - } - } - if (begin) { - if ("DIV".equals(name.rawname)) { //$NON-NLS-1$ - ++divCounter; - } - if (!descStart) { - if ("SPAN".equals(name.rawname)) { //$NON-NLS-1$ - String type = a.getValue("class"); //$NON-NLS-1$ - if (returnValue == null && type != null && - type.equals("returnvalue")) { //$NON-NLS-1$ - returnType = true; - } - } else if ("PRE".equals(name.rawname)) { //$NON-NLS-1$ - String type = a.getValue("class"); //$NON-NLS-1$ - if (type != null && type.equals("programlisting")) { //$NON-NLS-1$ - returnType = true; - } - } - } - if (protoStart) { - if ("P".equals(name.rawname)) { //$NON-NLS-1$ - protoStart = false; - descStart = true; - description.append("<p>"); //$NON-NLS-1$ - } - } else if (descStart) { - if ("P".equals(name.rawname)) { //$NON-NLS-1$ - description.append("<p>"); //$NON-NLS-1$ - } else if ("TABLE".equals(name.rawname)) { //$NON-NLS-1$ - description.append("<dl>"); //$NON-NLS-1$ - } else if ("TR".equals(name.rawname)) { //$NON-NLS-1$ - rowItemCount = 0; - } else if ("TD".equals(name.rawname)) { //$NON-NLS-1$ - String type = a.getValue("class"); //$NON-NLS-1$ - if (type != null && type.equals("listing_lines")) { //$NON-NLS-1$ - rowIgnore = true; - } else { - rowIgnore = false; - if (rowItemCount++ == 0) { - rowTag = "<dt>"; //$NON-NLS-1$ - } else { - rowTag = "<dd>"; //$NON-NLS-1$ - } - description.append(rowTag); - } - } else if ("H4".equals(name.rawname)) { //$NON-NLS-1$ - description.append("<br><br>"); //$NON-NLS-1$ - } - } - } else { - if ("DIV".equals(name.rawname)) { //$NON-NLS-1$ - String className = a.getValue("class"); //$NON-NLS-1$ - if ("refsect2".equals(className)) { //$NON-NLS-1$ - refsect2 = true; - } else { - refsect2 = false; - } - } - } - } - - @Override - public void endElement(QName name, Augmentations aug) { - if (begin) { - if ("DIV".equals(name.rawname)) { //$NON-NLS-1$ - --divCounter; - if (divCounter <= 0) { - begin = false; - descStart = false; - parmStart = false; - protoStart = false; - throw new FuncFoundSaxException(); // indicate we are done and stop parser - } - } - if (descStart) { - if ("P".equals(name.rawname)) {//$NON-NLS-1$ - description.append("</p>"); //$NON-NLS-1$ - } else if ("TABLE".equals(name.rawname)) { //$NON-NLS-1$ - description.append("</dl>"); //$NON-NLS-1$ - } else if ("TR".equals(name.rawname)) { //$NON-NLS-1$ - rowItemCount = 0; - } else if ("TD".equals(name.rawname)) { //$NON-NLS-1$ - if (!rowIgnore) { - if (rowTag != null && rowTag.equals("<dt>")) {//$NON-NLS-1$ - description.append("</dt>"); //$NON-NLS-1$ - } else { - description.append("</dd>"); //$NON-NLS-1$ - } - } - rowIgnore = false; - } else if ("H4".equals(name.rawname)) { //$NON-NLS-1$ - description.append("</br></br>"); //$NON-NLS-1$ - } - } - } - } + @Override + public void startElement(QName name, XMLAttributes a, Augmentations aug) { + // look for a tag that matches one of the functions we are trying to find + if ("A".equals(name.rawname)) { //$NON-NLS-1$ + String fname = a.getValue("name"); //$NON-NLS-1$ + String mapName = funcs.get(fname); + if (mapName != null) { + // We have found one of the functions we are looking for. + // Register the name for later and allow function parsing to begin. + funcName = mapName.trim(); + if (funcName.endsWith("()")) { //$NON-NLS-1$ + // Remove () at end of function name and remove all space chars which might be + // non-breaking space chars which unfortunately do not get caught by the trim() method. + funcName = this.funcName.replaceAll("\\(\\)", "").replaceAll("\\p{javaSpaceChar}",""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } + begin = true; + funcs.remove(fname); // take name off our list to do + divCounter = refsect2 ? 1 : 0; + refsect2 = false; + } + } + if (begin) { + if ("DIV".equals(name.rawname)) { //$NON-NLS-1$ + ++divCounter; + } + if (!descStart) { + if ("SPAN".equals(name.rawname)) { //$NON-NLS-1$ + String type = a.getValue("class"); //$NON-NLS-1$ + if (returnValue == null && type != null && + type.equals("returnvalue")) { //$NON-NLS-1$ + returnType = true; + } + } else if ("PRE".equals(name.rawname)) { //$NON-NLS-1$ + String type = a.getValue("class"); //$NON-NLS-1$ + if (type != null && type.equals("programlisting")) { //$NON-NLS-1$ + returnType = true; + } + } + } + if (protoStart) { + if ("P".equals(name.rawname)) { //$NON-NLS-1$ + protoStart = false; + descStart = true; + description.append("<p>"); //$NON-NLS-1$ + } + } else if (descStart) { + if ("P".equals(name.rawname)) { //$NON-NLS-1$ + description.append("<p>"); //$NON-NLS-1$ + } else if ("TABLE".equals(name.rawname)) { //$NON-NLS-1$ + description.append("<dl>"); //$NON-NLS-1$ + } else if ("TR".equals(name.rawname)) { //$NON-NLS-1$ + rowItemCount = 0; + } else if ("TD".equals(name.rawname)) { //$NON-NLS-1$ + String type = a.getValue("class"); //$NON-NLS-1$ + if (type != null && type.equals("listing_lines")) { //$NON-NLS-1$ + rowIgnore = true; + } else { + rowIgnore = false; + if (rowItemCount++ == 0) { + rowTag = "<dt>"; //$NON-NLS-1$ + } else { + rowTag = "<dd>"; //$NON-NLS-1$ + } + description.append(rowTag); + } + } else if ("H4".equals(name.rawname)) { //$NON-NLS-1$ + description.append("<br><br>"); //$NON-NLS-1$ + } + } + } else { + if ("DIV".equals(name.rawname)) { //$NON-NLS-1$ + String className = a.getValue("class"); //$NON-NLS-1$ + if ("refsect2".equals(className)) { //$NON-NLS-1$ + refsect2 = true; + } else { + refsect2 = false; + } + } + } + } - @Override - public void characters(XMLString data, Augmentations aug) { - if (begin) { - if (returnType) { - returnValue = ""; //$NON-NLS-1$ - String tmp = data.toString().trim(); - boolean completed = false; - if (tmp.endsWith(");")) { //$NON-NLS-1$ - completed = true; - tmp = tmp.substring(0, tmp.length() - 2); - } - String tokens[] = tmp.split("\\s+"); //$NON-NLS-1$ - String separator = ""; //$NON-NLS-1$ - protoStart = true; - for (int i = 0; i < tokens.length; ++i) { - String token = tokens[i]; - if (!token.equals(funcName)) { - returnValue += separator + token; - separator = " "; //$NON-NLS-1$ - } else { - separator = ""; //$NON-NLS-1$ - for (int j = i + 1; j < tokens.length; ++j) { - String jtoken = tokens[j]; - if (j == i + 1 && jtoken.charAt(0) == '(') { - jtoken = jtoken.substring(1); - parmStart = true; - protoStart = false; - } - prototype.append(separator).append(jtoken); - separator = " "; //$NON-NLS-1$ - } - if (parmStart && completed) { - parmStart = false; - descStart = true; - } - break; - } - } - returnType = false; - } else if (protoStart) { - String temp = data.toString().trim(); - boolean completed = false; - if (temp.endsWith(");")) { //$NON-NLS-1$ - completed = true; - temp = temp.substring(0, temp.length() - 2); - } - String separator = " "; //$NON-NLS-1$ - while (temp.startsWith("*") || temp.startsWith("const")) { //$NON-NLS-1$ //$NON-NLS-2$ - if (temp.charAt(0) == '*') { - returnValue += separator + "*"; //$NON-NLS-1$ - temp = temp.substring(1).trim(); - separator = ""; //$NON-NLS-1$ - } else { - returnValue += "const"; //$NON-NLS-1$ - temp = temp.substring(5).trim(); - separator = " "; //$NON-NLS-1$ - } - } - int index = temp.lastIndexOf('('); - int index2 = temp.lastIndexOf(')'); - if (index2 < index) { - if (index + 1 < temp.length()) { - temp = temp.substring(index + 1).trim(); - prototype.append(temp); - } - parmStart = true; - protoStart = false; - } - if (parmStart && completed) { - parmStart = false; - descStart = true; - } - } else if (parmStart) { - String parmData = data.toString().trim(); - int index = parmData.indexOf(')'); - if (index >= 0) { - parmStart = false; - descStart = true; - parmData = parmData.substring(0, index); - } - if (prototype.length() == 0) { - if (!parmData.equals(",") && !parmData.isEmpty()) { //$NON-NLS-1$ - parmData = " " + parmData; //$NON-NLS-1$ - } - } - prototype.append(parmData); - } else if (descStart) { - if (!rowIgnore) { - description.append(String.valueOf(data)); - } - } - } - } + @Override + public void endElement(QName name, Augmentations aug) { + if (begin) { + if ("DIV".equals(name.rawname)) { //$NON-NLS-1$ + --divCounter; + if (divCounter <= 0) { + // We have finished parsing the current function, reset all flags + begin = false; + descStart = false; + parmStart = false; + protoStart = false; + // If valid, create and save the function info + if (valid && returnValue != null && + !returnValue.startsWith("#") && //$NON-NLS-1$ + !returnValue.startsWith("typedef ")) { //$NON-NLS-1$ + FunctionInfo info = new FunctionInfo(funcName); + info.setReturnType(returnValue); + info.setPrototype(prototype.toString()); + info.setDescription(description.toString()); + infos.put(funcName, info); + // Clear the description and prototype strings for next function + description.setLength(0); + prototype.setLength(0); + if (funcs.isEmpty()) + throw new FuncFoundSaxException(); // indicate we are done and stop parser + } + } + } + if (descStart) { + if ("P".equals(name.rawname)) {//$NON-NLS-1$ + description.append("</p>"); //$NON-NLS-1$ + } else if ("TABLE".equals(name.rawname)) { //$NON-NLS-1$ + description.append("</dl>"); //$NON-NLS-1$ + } else if ("TR".equals(name.rawname)) { //$NON-NLS-1$ + rowItemCount = 0; + } else if ("TD".equals(name.rawname)) { //$NON-NLS-1$ + if (!rowIgnore) { + if (rowTag != null && rowTag.equals("<dt>")) {//$NON-NLS-1$ + description.append("</dt>"); //$NON-NLS-1$ + } else { + description.append("</dd>"); //$NON-NLS-1$ + } + } + rowIgnore = false; + } else if ("H4".equals(name.rawname)) { //$NON-NLS-1$ + description.append("</br></br>"); //$NON-NLS-1$ + } + } + } + } - private FunctionInfo getFunctionInfo() { - if (!valid || returnValue == null || - returnValue.startsWith("#") || //$NON-NLS-1$ - returnValue.startsWith("typedef ")) { //$NON-NLS-1$ - return null; - } - FunctionInfo info = new FunctionInfo(funcName); - info.setReturnType(returnValue); - info.setPrototype(prototype.toString()); - info.setDescription(description.toString()); - return info; - } + @Override + public void characters(XMLString data, Augmentations aug) { + if (begin) { + if (returnType) { + returnValue = ""; //$NON-NLS-1$ + String tmp = data.toString().trim(); + boolean completed = false; + if (tmp.endsWith(");")) { //$NON-NLS-1$ + completed = true; + tmp = tmp.substring(0, tmp.length() - 2); + } + String tokens[] = tmp.split("\\s+"); //$NON-NLS-1$ + String separator = ""; //$NON-NLS-1$ + protoStart = true; + for (int i = 0; i < tokens.length; ++i) { + String token = tokens[i]; + if (!token.equals(funcName)) { + returnValue += separator + token; + separator = " "; //$NON-NLS-1$ + } else { + separator = ""; //$NON-NLS-1$ + for (int j = i + 1; j < tokens.length; ++j) { + String jtoken = tokens[j]; + if (j == i + 1 && jtoken.charAt(0) == '(') { + jtoken = jtoken.substring(1); + parmStart = true; + protoStart = false; + } + prototype.append(separator).append(jtoken); + separator = " "; //$NON-NLS-1$ + } + if (parmStart && completed) { + parmStart = false; + descStart = true; + } + break; + } + } + returnType = false; + } else if (protoStart) { + String temp = data.toString().trim(); + boolean completed = false; + if (temp.endsWith(");")) { //$NON-NLS-1$ + completed = true; + temp = temp.substring(0, temp.length() - 2); + } + String separator = " "; //$NON-NLS-1$ + while (temp.startsWith("*") || temp.startsWith("const")) { //$NON-NLS-1$ //$NON-NLS-2$ + if (temp.charAt(0) == '*') { + returnValue += separator + "*"; //$NON-NLS-1$ + temp = temp.substring(1).trim(); + separator = ""; //$NON-NLS-1$ + } else { + returnValue += "const"; //$NON-NLS-1$ + temp = temp.substring(5).trim(); + separator = " "; //$NON-NLS-1$ + } + } + int index = temp.lastIndexOf('('); + int index2 = temp.lastIndexOf(')'); + if (index2 < index) { + if (index + 1 < temp.length()) { + temp = temp.substring(index + 1).trim(); + prototype.append(temp); + } + parmStart = true; + protoStart = false; + } + if (parmStart && completed) { + parmStart = false; + descStart = true; + } + } else if (parmStart) { + String parmData = data.toString().trim(); + int index = parmData.indexOf(')'); + if (index >= 0) { + parmStart = false; + descStart = true; + parmData = parmData.substring(0, index); + } + if (prototype.length() == 0) { + if (!parmData.equals(",") && !parmData.isEmpty()) { //$NON-NLS-1$ + parmData = " " + parmData; //$NON-NLS-1$ + } + } + prototype.append(parmData); + } else if (descStart) { + if (!rowIgnore) { + description.append(String.valueOf(data)); + } + } + } + } - private String getFuncName() { - return funcName; - } + private TreeMap<String, FunctionInfo> getFunctionInfos() { + return infos; + } - @Override - public String toString() { - return "funcName: <" + funcName + "> returnType: <" + returnValue + //$NON-NLS-1$ //$NON-NLS-2$ - "> prototype: <" + prototype + "> description: " + description; //$NON-NLS-1$ //$NON-NLS-2$ - } - } + @Override + public String toString() { + return "funcName: <" + funcName + "> returnType: <" + returnValue + //$NON-NLS-1$ //$NON-NLS-2$ + "> prototype: <" + prototype + "> description: " + description; //$NON-NLS-1$ //$NON-NLS-2$ + } + } - public static class DevHelpParser { + public static class DevHelpParser { - private static final class NullEntityResolver implements EntityResolver { - @Override - public InputSource resolveEntity(String publicId, String systemId) { - return new InputSource(new StringReader("")); //$NON-NLS-1$ - } - } + private static final class NullEntityResolver implements EntityResolver { + @Override + public InputSource resolveEntity(String publicId, String systemId) { + return new InputSource(new StringReader("")); //$NON-NLS-1$ + } + } - private static final class FilenameComparator implements - Comparator<IFileStore> { - @Override - public int compare(IFileStore arg0, IFileStore arg1) { - return (arg0.getName().compareToIgnoreCase(arg1.getName())); - } - } + private static final class FilenameComparator implements + Comparator<IFileStore> { + @Override + public int compare(IFileStore arg0, IFileStore arg1) { + return (arg0.getName().compareToIgnoreCase(arg1.getName())); + } + } - private String dirName; - private LibHoverInfo libhover; - private boolean debug; - private FilenameComparator filenameComparator = new FilenameComparator(); - private NullEntityResolver entityResolver = new NullEntityResolver(); - private DocumentBuilderFactory factory; + private String dirName; + private LibHoverInfo libhover; + private boolean debug; + private FilenameComparator filenameComparator = new FilenameComparator(); + private NullEntityResolver entityResolver = new NullEntityResolver(); + private DocumentBuilderFactory factory; - public DevHelpParser(String dirName) { - this(dirName, false); - } + public DevHelpParser(String dirName) { + this(dirName, false); + } - public DevHelpParser(String dirName, boolean debug) { - this.dirName = dirName; - this.libhover = new LibHoverInfo(); - this.debug = debug; - factory = DocumentBuilderFactory.newInstance(); - factory.setValidating(false); - } + public DevHelpParser(String dirName, boolean debug) { + this.dirName = dirName; + this.libhover = new LibHoverInfo(); + this.debug = debug; + factory = DocumentBuilderFactory.newInstance(); + factory.setValidating(false); + } - public LibHoverInfo getLibHoverInfo() { - return libhover; - } + public LibHoverInfo getLibHoverInfo() { + return libhover; + } - public LibHoverInfo parse(IProgressMonitor monitor) { - try { - IFileSystem fs = EFS.getLocalFileSystem(); - IPath dirPath = new Path(dirName); - IFileStore htmlDir = fs.getStore(dirPath); - IFileStore[] files = htmlDir.childStores(EFS.NONE, null); - monitor.beginTask(LibHoverMessages.getString(PARSING_MSG), files.length); - Arrays.sort(files, filenameComparator); - for (int i = 0; i < files.length; ++i) { - IFileStore file = files[i]; - String name = file.fetchInfo().getName(); - if (monitor.isCanceled()) { - return null; - } - monitor.setTaskName(LibHoverMessages.getFormattedString(PARSING_FMT_MSG, - new String[]{name})); - File f = new File(dirPath.append(name).append(name + ".devhelp2").toOSString()); //$NON-NLS-1$ - if (f.exists()) { - parse(f.getAbsolutePath(), - monitor); - } else { - parse(dirPath.append(name) - .append(name + ".devhelp").toOSString(), //$NON-NLS-1$ - monitor); - } - monitor.worked(1); - } - } catch (CoreException e) { - e.printStackTrace(); - } - return libhover; - } + public LibHoverInfo parse(IProgressMonitor monitor) { + try { + IFileSystem fs = EFS.getLocalFileSystem(); + IPath dirPath = new Path(dirName); + IFileStore htmlDir = fs.getStore(dirPath); + IFileStore[] files = htmlDir.childStores(EFS.NONE, null); + monitor.beginTask(LibHoverMessages.getString(PARSING_MSG), files.length); + Arrays.sort(files, filenameComparator); + for (int i = 0; i < files.length; ++i) { + IFileStore file = files[i]; + String name = file.fetchInfo().getName(); + if (monitor.isCanceled()) { + return null; + } + monitor.setTaskName(LibHoverMessages.getFormattedString(PARSING_FMT_MSG, + new String[]{name})); + File f = new File(dirPath.append(name).append(name + ".devhelp2").toOSString()); //$NON-NLS-1$ + if (f.exists()) { + parse(f.getAbsolutePath(), + monitor); + } else { + parse(dirPath.append(name) + .append(name + ".devhelp").toOSString(), //$NON-NLS-1$ + monitor); + } + monitor.worked(1); + } + } catch (CoreException e) { + e.printStackTrace(); + } + return libhover; + } - private void parseLink(Node link, Node name, IPath path, LibHoverInfo libhover) { - String linkValue = link.getNodeValue(); - String[] linkParts = linkValue.split("#"); //$NON-NLS-1$ - InputStream reader = null; - HTMLSaxParser parser = null; - if (linkParts.length == 2) { - try { - String nameString = name.getNodeValue(); - nameString = nameString.replaceAll("\\(.*\\);+", "").trim(); //$NON-NLS-1$ //$NON-NLS-2$ - if (nameString.contains("::") || nameString.startsWith("enum ") //$NON-NLS-1$ //$NON-NLS-2$ - || nameString.contains("\"")) { //$NON-NLS-1$ - return; - } - reader = new FileInputStream(path.removeLastSegments(1).toOSString() - + "/" + linkParts[0]); //$NON-NLS-1$ - parser = new HTMLSaxParser(linkParts[1], nameString); - try { - parser.parse(new InputSource(reader)); - } catch (FuncFoundSaxException e) { - // ignore because this is just how we shorten parse time - } - reader.close(); - FunctionInfo finfo = parser.getFunctionInfo(); - if (finfo != null) { - if (debug) { - System.out.println(parser.toString()); - } - libhover.functions.put(parser.getFuncName(), parser.getFunctionInfo()); - } - } catch (IOException e) { - // ignore - } catch (SAXException e) { - e.printStackTrace(); - } - } - } + private void parseLinks(HashMap<String, String> funcMap, String fileName, IPath path, LibHoverInfo libhover) { + InputStream reader = null; + HTMLSaxParser parser = null; + try { + reader = new FileInputStream(path.removeLastSegments(1).toOSString() + + "/" + fileName); //$NON-NLS-1$ + parser = new HTMLSaxParser(funcMap); + try { + parser.parse(new InputSource(reader)); + } catch (FuncFoundSaxException e) { + // ignore because this is just how we shorten parse time + } + reader.close(); + TreeMap<String, FunctionInfo> finfos = parser.getFunctionInfos(); + if (finfos != null) { + if (debug) { + System.out.println(parser.toString()); + } + libhover.functions.putAll(finfos); + } + } catch (IOException e) { + // ignore + } catch (SAXException e) { + e.printStackTrace(); + } + } - private void parse(String fileName, IProgressMonitor monitor) { - try { - Path path = new Path(fileName); - File f = new File(fileName); - FileInputStream stream = new FileInputStream(f); - DocumentBuilder builder = factory.newDocumentBuilder(); - builder.setEntityResolver(entityResolver); - Document doc = builder.parse(stream); - NodeList bookNodes = doc.getElementsByTagName("book"); //$NON-NLS-1$ - for (int x = 0; x < bookNodes.getLength(); ++x) { - Node n = bookNodes.item(x); - NamedNodeMap m = n.getAttributes(); - Node language = m.getNamedItem("language"); //$NON-NLS-1$ - if (language != null && !language.getNodeValue().equals("c")) { //$NON-NLS-1$ - return; - } - } - if (path.getFileExtension().equals("devhelp")) { //$NON-NLS-1$ - NodeList nl = doc.getElementsByTagName("function"); // $NON-NLS-1$ //$NON-NLS-1$ - for (int i = 0; i < nl.getLength(); ++i) { - if (monitor.isCanceled()) { - return; - } - Node n = nl.item(i); - NamedNodeMap m = n.getAttributes(); - Node name = m.getNamedItem("name"); // $NON-NLS-1$ //$NON-NLS-1$ - Node link = m.getNamedItem("link"); // $NON-NLS-1$ //$NON-NLS-1$ - if (link != null) { - parseLink(link, name, path, libhover); - } - } - } else if (path.getFileExtension().equals("devhelp2")) { //$NON-NLS-1$ - NodeList nl = doc.getElementsByTagName("keyword"); // $NON-NLS-1$ //$NON-NLS-1$ - for (int i = 0; i < nl.getLength(); ++i) { - if (monitor.isCanceled()) - return; - Node n = nl.item(i); - NamedNodeMap m = n.getAttributes(); - Node type = m.getNamedItem("type"); // $NON-NLS-1$ //$NON-NLS-1$ - if (type != null) { - String typeName = type.getNodeValue(); - if (typeName.equals("function")) { //$NON-NLS-1$ - Node name = m.getNamedItem("name"); // $NON-NLS-1$ //$NON-NLS-1$ - Node link = m.getNamedItem("link"); // $NON-NLS-1$ //$NON-NLS-1$ - if (link != null) { - parseLink(link, name, path, libhover); - } - } - } - } - } - } catch (FileNotFoundException e1) { - // ignore - } catch (ParserConfigurationException|SAXException|IOException e) { - e.printStackTrace(); - } - } - } + private void parse(String fileName, IProgressMonitor monitor) { + try { + HashMap<String, HashMap<String,String>> files = new HashMap<>(); + Path path = new Path(fileName); + File f = new File(fileName); + FileInputStream stream = new FileInputStream(f); + DocumentBuilder builder = factory.newDocumentBuilder(); + builder.setEntityResolver(entityResolver); + Document doc = builder.parse(stream); + NodeList bookNodes = doc.getElementsByTagName("book"); //$NON-NLS-1$ + for (int x = 0; x < bookNodes.getLength(); ++x) { + Node n = bookNodes.item(x); + NamedNodeMap m = n.getAttributes(); + Node language = m.getNamedItem("language"); //$NON-NLS-1$ + if (language != null && !language.getNodeValue().equals("c")) { //$NON-NLS-1$ + return; + } + } + if (path.getFileExtension().equals("devhelp")) { //$NON-NLS-1$ + // Get all function nodes + NodeList nl = doc.getElementsByTagName("function"); // $NON-NLS-1$ //$NON-NLS-1$ + for (int i = 0; i < nl.getLength(); ++i) { + if (monitor.isCanceled()) { + return; + } + Node n = nl.item(i); + NamedNodeMap m = n.getAttributes(); + // For each function node, get its associated link + Node name = m.getNamedItem("name"); // $NON-NLS-1$ //$NON-NLS-1$ + Node link = m.getNamedItem("link"); // $NON-NLS-1$ //$NON-NLS-1$ + if (name != null && link != null) { + String nameValue = name.getNodeValue(); + nameValue = nameValue.replaceAll("\\(.*\\);+", "").trim(); //$NON-NLS-1$ //$NON-NLS-2$ + if (!nameValue.contains("::") && !nameValue.startsWith("enum ") //$NON-NLS-1$ //$NON-NLS-2$ + && !nameValue.contains("\"")) { //$NON-NLS-1$ + String linkValue = link.getNodeValue(); + String[] linkParts = linkValue.split("#"); //$NON-NLS-1$ + // Check if the file referred to by the link has been seen before + // If not, create a new function list for it + HashMap<String, String> funcMap = files.get(linkParts[0]); + if (funcMap == null) { + funcMap = new HashMap<>(); + files.put(linkParts[0], funcMap); + } + // Add the function to the function list for the link file + funcMap.put(linkParts[1], nameValue); + } + } + } + } else if (path.getFileExtension().equals("devhelp2")) { //$NON-NLS-1$ + NodeList nl = doc.getElementsByTagName("keyword"); // $NON-NLS-1$ //$NON-NLS-1$ + for (int i = 0; i < nl.getLength(); ++i) { + if (monitor.isCanceled()) + return; + Node n = nl.item(i); + NamedNodeMap m = n.getAttributes(); + Node type = m.getNamedItem("type"); // $NON-NLS-1$ //$NON-NLS-1$ + if (type != null) { + String typeName = type.getNodeValue(); + // Look for all function references in the devhelp file + if (typeName.equals("function")) { //$NON-NLS-1$ + // Each function reference will have a link associated with it + Node name = m.getNamedItem("name"); // $NON-NLS-1$ //$NON-NLS-1$ + Node link = m.getNamedItem("link"); // $NON-NLS-1$ //$NON-NLS-1$ + if (name != null && link != null) { + // Clean up the name and make sure it isn't a non-C-function + String nameValue = name.getNodeValue(); + nameValue = nameValue.replaceAll("\\(.*\\);+", "").trim(); //$NON-NLS-1$ //$NON-NLS-2$ + if (!nameValue.contains("::") && !nameValue.startsWith("enum ") //$NON-NLS-1$ //$NON-NLS-2$ + && !nameValue.contains("\"")) { //$NON-NLS-1$ + String linkValue = link.getNodeValue(); + String[] linkParts = linkValue.split("#"); //$NON-NLS-1$ + // Check to see if the file referred to by the link has been seen before + // If not, create a new function list for it + HashMap<String, String> funcMap = files.get(linkParts[0]); + if (funcMap == null) { + funcMap = new HashMap<>(); + files.put(linkParts[0], funcMap); + } + // Add the function to the function list for the link file + funcMap.put(linkParts[1], nameValue); + } + } + } + } + } + } + // For each different file found in function links in the devhelp file, + // parse it and get all function info that is referred to + for (Map.Entry<String, HashMap<String, String>> entry : files.entrySet()) { + String fname = entry.getKey(); + HashMap<String, String> funcMap = entry.getValue(); + parseLinks(funcMap, fname, path, libhover); + } + } catch (FileNotFoundException e1) { + // ignore + } catch (ParserConfigurationException|SAXException|IOException e) { + e.printStackTrace(); + } + } + } public static void main(String[] args) { long startParse = System.currentTimeMillis(); |