e88a6bb3100eed44a4e55704e70ded27c138089c
[phpeclipse.git] / net.sourceforge.phpeclipse.externaltools / src / net / sourceforge / phpdt / externaltools / actions / ExternalPHPParser.java
1 package net.sourceforge.phpdt.externaltools.actions;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.text.MessageFormat;
6 import java.util.Hashtable;
7
8 import net.sourceforge.phpdt.externaltools.util.StringUtil;
9 import net.sourceforge.phpeclipse.externaltools.ExternalToolsPlugin;
10 import net.sourceforge.phpeclipse.externaltools.PHPConsole;
11
12 import org.eclipse.core.resources.IFile;
13 import org.eclipse.core.resources.IMarker;
14 import org.eclipse.core.runtime.CoreException;
15 import org.eclipse.jface.dialogs.MessageDialog;
16 import org.eclipse.jface.preference.IPreferenceStore;
17 import org.eclipse.ui.texteditor.MarkerUtilities;
18
19 /**
20  * Calls the external parser and generates problem markers if necessary
21  */
22 public class ExternalPHPParser {
23         private final static String PROBLEM_ID = "net.sourceforge.phpeclipse.problem";
24
25         // strings for external parser call
26         private static final String PARSE_ERROR_STRING = "Parse error"; //$NON-NLS-1$
27
28         private static final String PARSE_WARNING_STRING = "Warning"; //$NON-NLS-1$
29
30         public static final int ERROR = 2;
31
32         public static final int WARNING = 1;
33
34         public static final int INFO = 0;
35
36         public static final int TASK = 3;
37
38         // TODO design error? Analyze why fileToParse must be static ???
39         final protected IFile fFileToParse;
40
41         public ExternalPHPParser(IFile file) {
42                 fFileToParse = file;
43         }
44
45         /**
46          * Call the php parse command ( php -l -f <filename> ) and create
47          * markers according to the external parser output.
48          * 
49          * @param file
50          *            the file that will be parsed
51          */
52         public void phpExternalParse() {
53                 // IFile file = (IFile) resource;
54                 // final IPath path = file.getFullPath();
55                 final IPreferenceStore store = ExternalToolsPlugin.getDefault()
56                                 .getPreferenceStore();
57                 final String filename = fFileToParse.getFullPath().toString();
58
59                 final String[] arguments = { filename };
60                 final MessageFormat form = new MessageFormat(store
61                                 .getString(ExternalToolsPlugin.EXTERNAL_PARSER_PREF));
62                 final String command = form.format(arguments);
63
64                 final String parserResult = getParserOutput(command,
65                                 "External parser: ");
66
67                 try {
68                         // parse the buffer to find the errors and warnings
69                         createMarkers(parserResult, fFileToParse);
70                 } catch (CoreException e) {
71                 }
72         }
73
74         /**
75          * Create markers according to the external parser output.
76          * 
77          * @param output
78          *            the external parser output
79          * @param file
80          *            the file that was parsed.
81          */
82         protected void createMarkers(final String output, final IFile file)
83                         throws CoreException {
84                 // delete all markers
85                 file.deleteMarkers(PROBLEM_ID, false, 0);
86
87                 int indx = 0;
88                 int brIndx;
89                 boolean flag = true;
90                 while ((brIndx = output.indexOf("<br />", indx)) != -1) {
91                         // newer php error output (tested with 4.2.3)
92                         scanLine(output, file, indx, brIndx);
93                         indx = brIndx + 6;
94                         flag = false;
95                 }
96                 if (flag) {
97                         while ((brIndx = output.indexOf("<br>", indx)) != -1) {
98                                 // older php error output (tested with 4.2.3)
99                                 scanLine(output, file, indx, brIndx);
100                                 indx = brIndx + 4;
101                         }
102                 }
103         }
104
105         private void scanLine(final String output, final IFile file,
106                         final int indx, final int brIndx) throws CoreException {
107                 String current;
108                 // String outLineNumberString; never used
109                 final StringBuffer lineNumberBuffer = new StringBuffer(10);
110                 char ch;
111                 current = output.substring(indx, brIndx);
112
113                 if (current.indexOf(PARSE_WARNING_STRING) != -1
114                                 || current.indexOf(PARSE_ERROR_STRING) != -1) {
115                         final int onLine = current.indexOf("on line <b>");
116                         if (onLine != -1) {
117                                 lineNumberBuffer.delete(0, lineNumberBuffer.length());
118                                 for (int i = onLine; i < current.length(); i++) {
119                                         ch = current.charAt(i);
120                                         if ('0' <= ch && '9' >= ch) {
121                                                 lineNumberBuffer.append(ch);
122                                         }
123                                 }
124
125                                 final int lineNumber = Integer.parseInt(lineNumberBuffer
126                                                 .toString());
127
128                                 final Hashtable attributes = new Hashtable();
129
130                                 current = StringUtil.replaceAll(current, "\n", "");
131                                 current = StringUtil.replaceAll(current, "<b>", "");
132                                 current = StringUtil.replaceAll(current, "</b>", "");
133                                 MarkerUtilities.setMessage(attributes, current);
134
135                                 if (current.indexOf(PARSE_ERROR_STRING) != -1)
136                                         attributes.put(IMarker.SEVERITY, new Integer(
137                                                         IMarker.SEVERITY_ERROR));
138                                 else if (current.indexOf(PARSE_WARNING_STRING) != -1)
139                                         attributes.put(IMarker.SEVERITY, new Integer(
140                                                         IMarker.SEVERITY_WARNING));
141                                 else
142                                         attributes.put(IMarker.SEVERITY, new Integer(
143                                                         IMarker.SEVERITY_INFO));
144                                 MarkerUtilities.setLineNumber(attributes, lineNumber);
145                                 MarkerUtilities.createMarker(file, attributes, PROBLEM_ID);
146                         }
147                 }
148         }
149
150         /**
151          * This will set a marker.
152          * 
153          * @param file
154          *            the file that generated the marker
155          * @param message
156          *            the message
157          * @param charStart
158          *            the starting character
159          * @param charEnd
160          *            the end character
161          * @param errorLevel
162          *            the error level ({@link ExternalPHPParser#ERROR},{@link ExternalPHPParser#INFO},{@link ExternalPHPParser#WARNING}),
163          *            {@link ExternalPHPParser#TASK})
164          * @throws CoreException
165          *             an exception throwed by the MarkerUtilities
166          */
167         private void setMarker(final IFile file, final String message,
168                         final int charStart, final int charEnd, final int errorLevel)
169                         throws CoreException {
170                 if (file != null) {
171                         final Hashtable attributes = new Hashtable();
172                         MarkerUtilities.setMessage(attributes, message);
173                         switch (errorLevel) {
174                         case ERROR:
175                                 attributes.put(IMarker.SEVERITY, new Integer(
176                                                 IMarker.SEVERITY_ERROR));
177                                 break;
178                         case WARNING:
179                                 attributes.put(IMarker.SEVERITY, new Integer(
180                                                 IMarker.SEVERITY_WARNING));
181                                 break;
182                         case INFO:
183                                 attributes.put(IMarker.SEVERITY, new Integer(
184                                                 IMarker.SEVERITY_INFO));
185                                 break;
186                         case TASK:
187                                 attributes.put(IMarker.SEVERITY, new Integer(IMarker.TASK));
188                                 break;
189                         }
190                         MarkerUtilities.setCharStart(attributes, charStart);
191                         MarkerUtilities.setCharEnd(attributes, charEnd);
192                         MarkerUtilities.createMarker(file, attributes, PROBLEM_ID);
193                 }
194         }
195
196         /**
197          * This will set a marker.
198          * 
199          * @param file
200          *            the file that generated the marker
201          * @param message
202          *            the message
203          * @param line
204          *            the line number
205          * @param errorLevel
206          *            the error level ({@link ExternalPHPParser#ERROR},{@link ExternalPHPParser#INFO},{@link ExternalPHPParser#WARNING})
207          * @throws CoreException
208          *             an exception throwed by the MarkerUtilities
209          */
210         private void setMarker(final IFile file, final String message,
211                         final int line, final int errorLevel, final String location)
212                         throws CoreException {
213                 if (file != null) {
214                         String markerKind = PROBLEM_ID;
215                         final Hashtable attributes = new Hashtable();
216                         MarkerUtilities.setMessage(attributes, message);
217                         switch (errorLevel) {
218                         case ERROR:
219                                 attributes.put(IMarker.SEVERITY, new Integer(
220                                                 IMarker.SEVERITY_ERROR));
221                                 break;
222                         case WARNING:
223                                 attributes.put(IMarker.SEVERITY, new Integer(
224                                                 IMarker.SEVERITY_WARNING));
225                                 break;
226                         case INFO:
227                                 attributes.put(IMarker.SEVERITY, new Integer(
228                                                 IMarker.SEVERITY_INFO));
229                                 break;
230                         case TASK:
231                                 attributes.put(IMarker.SEVERITY, new Integer(
232                                                 IMarker.SEVERITY_INFO));
233                                 markerKind = IMarker.TASK;
234                                 break;
235                         }
236                         attributes.put(IMarker.LOCATION, location);
237                         MarkerUtilities.setLineNumber(attributes, line);
238                         MarkerUtilities.createMarker(file, attributes, markerKind);
239                 }
240         }
241
242         /**
243          * This will set a marker.
244          * 
245          * @param message
246          *            the message
247          * @param charStart
248          *            the starting character
249          * @param charEnd
250          *            the end character
251          * @param errorLevel
252          *            the error level ({@link ExternalPHPParser#ERROR},{@link ExternalPHPParser#INFO},{@link ExternalPHPParser#WARNING})
253          * @throws CoreException
254          *             an exception throwed by the MarkerUtilities
255          */
256         private void setMarker(final String message, final int charStart,
257                         final int charEnd, final int errorLevel, final String location)
258                         throws CoreException {
259                 if (fFileToParse != null) {
260                         setMarker(fFileToParse, message, charStart, charEnd, errorLevel,
261                                         location);
262                 }
263         }
264
265         /**
266          * This will set a marker.
267          * 
268          * @param file
269          *            the file that generated the marker
270          * @param message
271          *            the message
272          * @param charStart
273          *            the starting character
274          * @param charEnd
275          *            the end character
276          * @param errorLevel
277          *            the error level ({@link ExternalPHPParser#ERROR},{@link ExternalPHPParser#INFO},{@link ExternalPHPParser#WARNING})
278          * @param location
279          *            the location of the error
280          * @throws CoreException
281          *             an exception throwed by the MarkerUtilities
282          */
283         private void setMarker(final IFile file, final String message,
284                         final int charStart, final int charEnd, final int errorLevel,
285                         final String location) throws CoreException {
286                 if (file != null) {
287                         final Hashtable attributes = new Hashtable();
288                         MarkerUtilities.setMessage(attributes, message);
289                         switch (errorLevel) {
290                         case ERROR:
291                                 attributes.put(IMarker.SEVERITY, new Integer(
292                                                 IMarker.SEVERITY_ERROR));
293                                 break;
294                         case WARNING:
295                                 attributes.put(IMarker.SEVERITY, new Integer(
296                                                 IMarker.SEVERITY_WARNING));
297                                 break;
298                         case INFO:
299                                 attributes.put(IMarker.SEVERITY, new Integer(
300                                                 IMarker.SEVERITY_INFO));
301                                 break;
302                         case TASK:
303                                 attributes.put(IMarker.SEVERITY, new Integer(IMarker.TASK));
304                                 break;
305                         }
306                         attributes.put(IMarker.LOCATION, location);
307                         MarkerUtilities.setCharStart(attributes, charStart);
308                         MarkerUtilities.setCharEnd(attributes, charEnd);
309                         MarkerUtilities.createMarker(file, attributes, PROBLEM_ID); // IMarker.PROBLEM);
310                 }
311         }
312
313         private String getParserOutput(String command, String consoleMessage) {
314                 try {
315                         PHPConsole console = new PHPConsole();
316                         try {
317                                 console.println(consoleMessage + command);
318                         } catch (Throwable th) {
319
320                         }
321
322                         Runtime runtime = Runtime.getRuntime();
323
324                         // runs the command
325                         Process p = runtime.exec(command);
326
327                         // gets the input stream to have the post-compile-time information
328                         InputStream stream = p.getInputStream();
329
330                         // get the string from Stream
331                         String consoleOutput = PHPConsole.getStringFromStream(stream);
332
333                         // prints out the information
334                         if (console != null) {
335                                 console.print(consoleOutput);
336                         }
337                         return consoleOutput;
338
339                 } catch (IOException e) {
340                         MessageDialog
341                                         .openInformation(null, "IOException: ", e.getMessage());
342                 }
343                 return "";
344         }
345 }