1
/*******************************************************************************
2
* Copyright (c) 2004, 2011 IBM Corporation and others.
3
* All rights reserved. This program and the accompanying materials
4
* are made available under the terms of the Eclipse Public License v1.0
5
* which accompanies this distribution, and is available at
6
* http://www.eclipse.org/legal/epl-v10.html
9
* IBM - Initial API and implementation
10
* Markus Schorn (Wind River Systems)
11
* Gerhard Schaber (Wind River Systems) - bug 203059
12
*******************************************************************************/
13
package org.eclipse.cdt.make.internal.core.scannerconfig.gnu;
15
import java.util.ArrayList;
17
import org.eclipse.cdt.make.core.scannerconfig.IScannerInfoCollector;
18
import org.eclipse.cdt.make.core.scannerconfig.IScannerInfoConsoleParser;
19
import org.eclipse.cdt.make.internal.core.MakeMessages;
20
import org.eclipse.cdt.make.internal.core.scannerconfig.util.TraceUtil;
21
import org.eclipse.cdt.make.internal.core.scannerconfig2.SCProfileInstance;
22
import org.eclipse.cdt.make.internal.core.scannerconfig2.ScannerConfigProfileManager;
23
import org.eclipse.cdt.make.internal.core.scannerconfig2.ScannerConfigProfile.BuildOutputProvider;
24
import org.eclipse.core.resources.IProject;
27
* Common stuff for all GNU build output parsers
31
public abstract class AbstractGCCBOPConsoleParser implements IScannerInfoConsoleParser {
32
protected static final String[] COMPILER_INVOCATION = {
33
"gcc", "g++", "cc", "c++" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
35
protected static final String DASHIDASH= "-I-"; //$NON-NLS-1$
36
protected static final String DASHI= "-I"; //$NON-NLS-1$
37
protected static final String DASHD= "-D"; //$NON-NLS-1$
39
private IProject project;
40
protected IScannerInfoCollector collector;
42
private boolean bMultiline = false;
43
private String sMultiline = ""; //$NON-NLS-1$
45
protected String[] fCompilerCommands;
48
* @return Returns the project.
50
protected IProject getProject() {
54
* @return Returns the collector.
56
protected IScannerInfoCollector getCollector() {
60
public void startup(IProject project, IScannerInfoCollector collector) {
61
this.project = project;
62
this.collector = collector;
63
fCompilerCommands= computeCompilerCommands();
67
* Returns array of additional compiler commands to look for
71
private String[] computeCompilerCommands() {
72
if (project != null) {
73
SCProfileInstance profileInstance = ScannerConfigProfileManager.getInstance().
74
getSCProfileInstance(project, ScannerConfigProfileManager.NULL_PROFILE_ID);
75
BuildOutputProvider boProvider = profileInstance.getProfile().getBuildOutputProviderElement();
76
if (boProvider != null) {
77
String compilerCommandsString = boProvider.getScannerInfoConsoleParser().getCompilerCommands();
78
if (compilerCommandsString != null && compilerCommandsString.length() > 0) {
79
String[] compilerCommands = compilerCommandsString.split(",\\s*"); //$NON-NLS-1$
80
if (compilerCommands.length > 0) {
81
String[] compilerInvocation = new String[COMPILER_INVOCATION.length + compilerCommands.length];
82
System.arraycopy(COMPILER_INVOCATION, 0, compilerInvocation, 0, COMPILER_INVOCATION.length);
83
System.arraycopy(compilerCommands, 0, compilerInvocation, COMPILER_INVOCATION.length, compilerCommands.length);
84
return compilerInvocation;
89
return COMPILER_INVOCATION;
93
* @see org.eclipse.cdt.make.core.scannerconfig.IScannerInfoConsoleParser#processLine(java.lang.String)
95
public boolean processLine(String line) {
97
int lineBreakPos = line.length()-1;
98
char[] lineChars = line.toCharArray();
99
while(lineBreakPos >= 0 && Character.isWhitespace(lineChars[lineBreakPos])) {
102
if (lineBreakPos >= 0) {
103
if (lineChars[lineBreakPos] != '\\'
104
|| (lineBreakPos > 0 && lineChars[lineBreakPos-1] == '\\')) {
108
// check for multiline commands (ends with '\')
109
if (lineBreakPos >= 0) {
110
sMultiline += line.substring(0, lineBreakPos);
115
line = sMultiline + line;
117
sMultiline = ""; //$NON-NLS-1$
120
TraceUtil.outputTrace("AbstractGCCBOPConsoleParser parsing line: [", line, "]"); //$NON-NLS-1$ //$NON-NLS-2$
121
// make\[[0-9]*\]: error_desc
122
int firstColon= line.indexOf(':');
123
String make = line.substring(0, firstColon + 1);
124
if (firstColon != -1 && make.indexOf("make") != -1) { //$NON-NLS-1$
125
boolean enter = false;
126
String msg = line.substring(firstColon + 1).trim();
127
if ((enter = msg.startsWith(MakeMessages.getString("AbstractGCCBOPConsoleParser_EnteringDirectory"))) || //$NON-NLS-1$
128
(msg.startsWith(MakeMessages.getString("AbstractGCCBOPConsoleParser_LeavingDirectory")))) { //$NON-NLS-1$
129
int s = msg.indexOf('`');
130
int e = msg.indexOf('\'');
131
if (s != -1 && e != -1) {
132
String dir = msg.substring(s+1, e);
133
if (getUtility() != null) {
134
getUtility().changeMakeDirectory(dir, getDirectoryLevel(line), enter);
140
// call sublclass to process a single line
141
return processSingleLine(line.trim());
144
private int getDirectoryLevel(String line) {
145
int s = line.indexOf('[');
148
int e = line.indexOf(']');
149
String number = line.substring(s + 1, e).trim();
151
num = Integer.parseInt(number);
152
} catch (NumberFormatException exc) {
158
protected abstract AbstractGCCBOPConsoleParserUtility getUtility();
161
* @see org.eclipse.cdt.make.core.scannerconfig.IScannerInfoConsoleParser#shutdown()
163
public void shutdown() {
164
if (getUtility() != null) {
165
getUtility().reportProblems();
170
* Tokenizes a line into an array of commands. Commands are separated by
171
* ';', '&&' or '||'. Tokens are separated by whitespace unless found inside
172
* of quotes, back-quotes, or double quotes.
173
* Outside of single-, double- or back-quotes a backslash escapes white-spaces, all quotes,
174
* the backslash, '&' and '|'.
175
* A backslash used for escaping is removed.
176
* Quotes other than the back-quote plus '&&', '||', ';' are removed, also.
177
* @param line to tokenize
178
* @param escapeInsideDoubleQuotes if quotes need to be escaped [\"] in the resulting array of commands
179
* @return array of commands
181
protected String[][] tokenize(String line, boolean escapeInsideDoubleQuotes) {
182
ArrayList<String[]> commands= new ArrayList<String[]>();
183
ArrayList<String> tokens= new ArrayList<String>();
184
StringBuffer token= new StringBuffer();
186
final char[] input= line.toCharArray();
187
boolean nextEscaped= false;
188
char currentQuote= 0;
189
for (int i = 0; i < input.length; i++) {
190
final char c = input[i];
191
final boolean escaped= nextEscaped; nextEscaped= false;
193
if (currentQuote != 0) {
194
if (c == currentQuote) {
200
token.append(c); // preserve back-quotes
206
if (escapeInsideDoubleQuotes && currentQuote == '"' && c == '\\') {
207
nextEscaped= !escaped;
230
case '\'': case '"': case '`':
246
endCommand(token, tokens, commands);
250
if (escaped || i+1 >= input.length || input[i+1] != c) {
255
endCommand(token, tokens, commands);
260
if (Character.isWhitespace(c)) {
265
endToken(token, tokens);
270
token.append('\\'); // for windows put backslash back onto the token.
277
endCommand(token, tokens, commands);
278
return commands.toArray(new String[commands.size()][]);
281
private void endCommand(StringBuffer token, ArrayList<String> tokens, ArrayList<String[]> commands) {
282
endToken(token, tokens);
283
if (!tokens.isEmpty()) {
284
commands.add(tokens.toArray(new String[tokens.size()]));
288
private void endToken(StringBuffer token, ArrayList<String> tokens) {
289
if (token.length() > 0) {
290
tokens.add(token.toString());
295
protected boolean processSingleLine(String line) {
297
String[][] tokens= tokenize(line, true);
298
for (int i = 0; i < tokens.length; i++) {
299
String[] command = tokens[i];
300
if (processCommand(command)) {
303
else { // go inside quotes, if the compiler is called per wrapper or shell script
304
for (int j = 0; j < command.length; j++) {
305
String[][] subtokens= tokenize(command[j], true);
306
for (int k = 0; k < subtokens.length; k++) {
307
String[] subcommand = subtokens[k];
308
if (subcommand.length > 1) { // only proceed if there is any additional info
309
if (processCommand(subcommand)) {
320
protected int findCompilerInvocation(String[] tokens) {
321
for (int i = 0; i < tokens.length; i++) {
322
final String token = tokens[i].toLowerCase();
323
final int searchFromOffset= Math.max(token.lastIndexOf('/'), token.lastIndexOf('\\')) + 1;
324
for (int j=0; j < fCompilerCommands.length; j++) {
325
if (token.indexOf(fCompilerCommands[j], searchFromOffset) != -1) {
333
abstract protected boolean processCommand(String[] command);