Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[cdt-patch] Resubmitted: CDT2.0 Scanner Configuration discovery - initial work

This is the resubmission of the initial patch.

This patch contains initial work for Scanner Configuration discovery 
feature. Also there is a simple UI interface (preference, project property 
and New Standard Make project wizard pages). The feature is disabled by 
default so it does not affect existing projects inadvertently. If turned 
on, it will populate C/C++ Make Project's Paths and Symbols tab with 
discovered info (preserving user specified entries). The discovered 
cygpath include paths are now translated to the absolute paths. Relative 
include paths are still not handled properly. 
Further refinements are coming along.

Please, apply to the head branch.

Thanks,
Vladimir Hirsl
Rational Software - IBM Software Group
Ottawa, Ontario, Canada

[attachment "cdt.make.core.txt" deleted by Vladimir Hirsl/Ottawa/IBM] 
[attachment "cdt.make.ui.txt" deleted by Vladimir Hirsl/Ottawa/IBM] 

Index: plugin.properties
===================================================================
retrieving revision 1.2
diff -u -r1.2 plugin.properties
--- plugin.properties	19 Aug 2003 20:17:28 -0000	1.2
+++ plugin.properties	18 Feb 2004 21:46:42 -0000
@@ -3,4 +3,13 @@
 
 extensionTargetBuilder.name=Target Builder Extension
 natureMake.name=CDT Make Nature
-builderMake.name=CDT Makefile Builder
\ No newline at end of file
+builderMake.name=CDT Makefile Builder
+
+natureScannerConfig.name=Scanner Configuration Nature
+builderScannerConfig.name=Scanner Configuration Builder
+extensionSpecsBuilder.name=C/C++ Compiler Specs Builder Extension
+specsBuilder.name=Specs Builder
+
+epGnuCommandLine.name=CDT GNU C/C++ Scanner Info Parser
+epGnuCompilerSpecs.name=CDT GNU C/C++ Specs Parser
+spGnuSpecsBuilder.name=CDT GNU C/C++ Specs Builder
Index: plugin.xml
===================================================================
retrieving revision 1.11
diff -u -r1.11 plugin.xml
--- plugin.xml	5 Jan 2004 20:26:09 -0000	1.11
+++ plugin.xml	18 Feb 2004 21:46:42 -0000
@@ -21,6 +21,7 @@
 
 
    <extension-point id="MakeTargetBuilder" name="%extensionTargetBuilder.name" schema="schema/MakeTargetBuilder.exsd"/>
+   <extension-point id="SpecsBuilder" name="%extensionSpecsBuilder.name" schema="schema/SpecsBuilder.exsd"/>
 
    <extension
          id="MakeScannerProvider"
@@ -76,6 +77,74 @@
             builderID="org.eclipse.cdt.make.core.makeBuilder"
             id="org.eclipse.cdt.make.MakeTargetBuilder">
       </builder>
+   </extension>
+   <extension
+         id="GCCCommandLineParser"
+         name="%epGnuCommandLine.name"
+         point="org.eclipse.cdt.core.ErrorParser">
+      <errorparser
+            class="org.eclipse.cdt.make.core.scannerconfig.gnu.GCCScannerInfoParser">
+      </errorparser>
+   </extension>
+   <extension
+         id="GCCSpecsParser"
+         name="%epGnuCompilerSpecs.name"
+         point="org.eclipse.cdt.core.ErrorParser">
+      <errorparser
+            class="org.eclipse.cdt.make.core.scannerconfig.gnu.GCCCompilerSpecsParser">
+      </errorparser>
+   </extension>
+   <extension
+         id="ScannerConfigNature"
+         name="%natureScannerConfig.name"
+         point="org.eclipse.core.resources.natures">
+      <requires-nature
+            id="org.eclipse.cdt.make.core.makeNature">
+      </requires-nature>
+      <runtime>
+         <run
+               class="org.eclipse.cdt.make.core.scannerconfig.ScannerConfigNature">
+         </run>
+      </runtime>
+      <builder
+            id="org.eclipse.cdt.make.core.ScannerConfigBuilder">
+      </builder>
+   </extension>
+   <extension
+         id="ScannerConfigBuilder"
+         name="%builderScannerConfig.name"
+         point="org.eclipse.core.resources.builders">
+      <builder
+            hasNature="true">
+         <run
+               class="org.eclipse.cdt.make.core.scannerconfig.ScannerConfigBuilder">
+         </run>
+      </builder>
+   </extension>
+   <extension
+         point="org.eclipse.cdt.make.core.MakeTargetBuilder">
+      <builder
+            builderID="org.eclipse.cdt.make.core.scannerconfig.ScannerConfigBuilder"
+            id="org.eclipse.cdt.make.core.scannerconfig.ScannerConfigTargetBuilder">
+      </builder>
+   </extension>
+   <extension
+         id="GCCSpecsBuilder"
+         name="%spGnuSpecsBuilder.name"
+         point="org.eclipse.cdt.make.core.SpecsBuilder">
+      <specsbuilder>
+         <run
+               class="org.eclipse.cdt.make.core.scannerconfig.gnu.GCCSpecsBuilder">
+            <parameter
+                  name="defaultCommand"
+                  value="gcc">
+            </parameter>
+            <parameter
+                  name="defaultAttributes"
+                  value="-c -v">
+            </parameter>
+         </run>
+      </specsbuilder>
    </extension>
 
 </plugin>
Index: src/org/eclipse/cdt/make/core/MakeCorePlugin.java
===================================================================
retrieving revision 1.11
diff -u -r1.11 MakeCorePlugin.java
--- src/org/eclipse/cdt/make/core/MakeCorePlugin.java	24 Sep 2003 18:03:36 -0000	1.11
+++ src/org/eclipse/cdt/make/core/MakeCorePlugin.java	18 Feb 2004 21:46:42 -0000
@@ -1,5 +1,5 @@
 /**********************************************************************
- * Copyright (c) 2002,2003 QNX Software Systems and others.
+ * Copyright (c) 2002,2004 QNX Software Systems and others.
  * All rights reserved.   This program and the accompanying materials
  * are made available under the terms of the Common Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,6 +10,8 @@
 ***********************************************************************/
 package org.eclipse.cdt.make.core;
 
+import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
 import java.text.MessageFormat;
@@ -19,13 +21,21 @@
 
 import org.eclipse.cdt.core.CCorePlugin;
 import org.eclipse.cdt.make.core.makefile.IMakefile;
+import org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo;
+import org.eclipse.cdt.make.core.scannerconfig.ISpecsBuilder;
+import org.eclipse.cdt.make.core.scannerconfig.ScannerConfigBuilder;
 import org.eclipse.cdt.make.internal.core.BuildInfoFactory;
 import org.eclipse.cdt.make.internal.core.MakeTargetManager;
 import org.eclipse.cdt.make.internal.core.makefile.gnu.GNUMakefile;
+import org.eclipse.cdt.make.internal.core.scannerconfig.ScannerConfigInfoFactory;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IPluginDescriptor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Path;
@@ -40,6 +50,13 @@
 	public static final String MAKE_PROJECT_ID = MakeCorePlugin.getUniqueIdentifier() + ".make";
 	private MakeTargetManager fTargetManager;
 	public static final String OLD_BUILDER_ID = "org.eclipse.cdt.core.cbuilder"; //$NON-NLS-1$
+
+	public static final String SPECS_BUILDER_SIMPLE_ID = "SpecsBuilder"; //$NON-NLS-1$
+	public static final String GCC_SPECS_BUILDER_ID = MakeCorePlugin.getUniqueIdentifier() + ".GCCSpecsBuilder"; //$NON-NLS-1$
+	
+	public static final String CPP_SPECS_FILE = "specs.cpp"; //$NON-NLS-1$ 
+	public static final String C_SPECS_FILE = "specs.c";  //$NON-NLS-1$
+
 	//The shared instance.
 	private static MakeCorePlugin plugin;
 	//Resource bundle.
@@ -56,6 +73,7 @@
 		} catch (MissingResourceException x) {
 			resourceBundle = null;
 		}
+		createSpecs();
 	}
 
 	/**
@@ -131,6 +149,16 @@
 		} catch (CoreException e) {
 		}
 		getPluginPreferences().setDefault(CCorePlugin.PREF_BINARY_PARSER, CCorePlugin.PLUGIN_ID + ".ELF"); //$NON-NLS-1$
+
+		// default plugin preferences for scanner configuration discovery
+		IScannerConfigBuilderInfo scInfo = createScannerConfigBuildInfo(getPluginPreferences(), ScannerConfigBuilder.BUILDER_ID, true);
+		try {
+			scInfo.setAutoDiscoveryEnabled(false);
+			scInfo.setUseDefaultSpecsCmd(true);
+			scInfo.setSpecsCommand(new Path("gcc")); //$NON-NLS-1$
+			scInfo.setSpecsArguments("-c -v");	//$NON-NLS-1$
+		} catch (CoreException e) {
+		}
 	}
 	
 	public static IMakeBuilderInfo createBuildInfo(Preferences prefs, String builderID, boolean useDefaults) {
@@ -177,6 +205,85 @@
 			fTargetManager.shutdown();
 			fTargetManager = null;
 		}
+	}
+
+	/*
+	 * Following methods create IScannerConfigBuilderInfo
+	 * Delegating requests to ScannerConfigInfoFactory
+	 */
+	public static IScannerConfigBuilderInfo createScannerConfigBuildInfo(
+			Preferences prefs, String builderID, boolean useDefaults) {
+		return ScannerConfigInfoFactory.create(prefs, builderID, useDefaults);
+	}
+
+	public static IScannerConfigBuilderInfo createScannerConfigBuildInfo(
+			IProject project, String builderID) throws CoreException {
+		return ScannerConfigInfoFactory.create(project, builderID);
+	}
+
+	public static IScannerConfigBuilderInfo createScannerConfigBuildInfo(
+			Map args, String builderID) {
+		return ScannerConfigInfoFactory.create(args, builderID);
+	}
+	
+	public static IPath getWorkingDirectory() {
+		return MakeCorePlugin.getDefault().getStateLocation();
+	}
+
+	private void createSpecs() {
+		IPath path = getWorkingDirectory();
+		try {
+			createSpecsFile(path, CPP_SPECS_FILE);
+			createSpecsFile(path, C_SPECS_FILE);
+		} catch (CoreException e) {
+			log(e);
+		}
+	}
+
+	private void createSpecsFile(IPath path, String fileName) throws CoreException {
+		IPath specs = path.append(fileName);
+		File specsFile = specs.toFile();
+		if (!specsFile.exists()) {
+			try {
+				FileOutputStream file = new FileOutputStream(specsFile);
+				file.write('\n');
+				file.close();
+			} catch (IOException e) {
+				throw new CoreException(new Status(IStatus.ERROR,
+						MakeCorePlugin.getDefault().getDescriptor().getUniqueIdentifier(),
+						-1, "Error writing specs file", e));
+			}
+		}
+	}
+
+	/**
+	 * @param toolset - id specifying compiler toolset i.e. GCC
+	 * @return builder - new instance of a 'specs' builder
+	 */
+	public ISpecsBuilder loadSpecsBuilder(String id) {
+		ISpecsBuilder[] empty = new ISpecsBuilder[0];
+		try {
+			IExtensionPoint extension = getDescriptor().getExtensionPoint(SPECS_BUILDER_SIMPLE_ID);
+			if (extension != null) {
+				IExtension[] extensions = extension.getExtensions();
+				for (int i = 0; i < extensions.length; i++) {
+					String tool = extensions[i].getUniqueIdentifier();
+					if (tool != null && tool.equals(id)) {
+						IConfigurationElement[] configElements = extensions[i]. getConfigurationElements();
+						for (int j = 0; j < configElements.length; j++) {
+							IConfigurationElement[] runElement = configElements[j].getChildren("run"); //$NON-NLS-1$
+							if (runElement.length > 0) { 
+								ISpecsBuilder builder = (ISpecsBuilder) runElement[0].createExecutableExtension("class");
+								return builder;
+							}
+						}
+					}
+				}
+			}
+		} catch (CoreException e) {
+			log(e);
+		}
+		return null;
 	}
 
 }
Index: src/org/eclipse/cdt/make/core/PluginResources.properties
===================================================================
retrieving revision 1.4
diff -u -r1.4 PluginResources.properties
--- src/org/eclipse/cdt/make/core/PluginResources.properties	24 Sep 2003 14:20:21 -0000	1.4
+++ src/org/eclipse/cdt/make/core/PluginResources.properties	18 Feb 2004 21:46:42 -0000
@@ -11,3 +11,16 @@
 MakeTargetProvider.add_temporary_target=Cannot add temporart Target to manager.
 MakeTargetProvider.target_exists=Target exists
 MakeTargetProvider.failed_initializing_targets=Failed initializing build targets
+
+ScannerConfigBuilder.Invoking_Builder=Scanner Configuration update ... 
+
+SpecsBuilder.Build_Error=Error launching builder ({0})
+SpecsBuilder.Reading_Specs=Reading specs ... 
+SpecsBuilder.Parsing_Output=Parsing output... 
+SpecsBuidler.Creating_Markers=Generating markers...
+
+ScannerInfoCollector.Processing=Processing discovered scanner configuration ... 
+ScannerInfoCollector.Updating=Updating Scanner Configuration for project 
+
Index: schema/SpecsBuilder.exsd
===================================================================
RCS file: schema/SpecsBuilder.exsd
diff -N schema/SpecsBuilder.exsd
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ schema/SpecsBuilder.exsd	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,137 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.vmir.cdt.scannerconfig">
+<annotation>
+      <appInfo>
+         <meta.schema plugin="org.vmir.cdt.scannerconfig" id="SpecsBuilders" name="C/C++ Compiler Specs Builder"/>
+      </appInfo>
+      <documentation>
+         This extension point is used to plug in particular compiler specs builder.
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <complexType>
+         <sequence>
+            <element ref="specsbuilder" minOccurs="1" maxOccurs="unbounded"/>
+         </sequence>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="specsbuilder">
+      <complexType>
+         <sequence>
+            <element ref="run"/>
+         </sequence>
+      </complexType>
+   </element>
+
+   <element name="run">
+      <complexType>
+         <sequence>
+            <element ref="parameter" minOccurs="0" maxOccurs="unbounded"/>
+         </sequence>
+         <attribute name="class" type="string" use="required">
+            <annotation>
+               <documentation>
+                  A fully qualified name of the Java class that implements &lt;samp&gt;org.eclipse.cdt.make.core.scannerconfig.ISpecsBuilder&lt;/samp&gt; interface.
+               </documentation>
+               <appInfo>
+                  <meta.attribute kind="java" basedOn="org.vmir.cdt.scannerconfig.core.ISpecsBuilder"/>
+               </appInfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="parameter">
+      <annotation>
+         <documentation>
+            Parameters passed to the specs builder.
+         </documentation>
+      </annotation>
+      <complexType>
+         <attribute name="name" type="string" use="required">
+            <annotation>
+               <documentation>
+                  Name of a parameter.
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="value" type="string" use="required">
+            <annotation>
+               <documentation>
+                  Value fo a parameter
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="since"/>
+      </appInfo>
+      <documentation>
+         [Enter the first release in which this extension point appears.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="examples"/>
+      </appInfo>
+      <documentation>
+         [Enter extension point usage example here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="apiInfo"/>
+      </appInfo>
+      <documentation>
+         Plug-ins that want to extend this extension point must implement &lt;samp&gt;org.vmir.cdt.scannerconfig.core.ISpecsBuilder&lt;/samp&gt; interface or extend &lt;samp&gt;org.vmir.cdt.scannerconfig.core.ASpecsBuilder&lt;/samp&gt; abstract base class.
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="implementation"/>
+      </appInfo>
+      <documentation>
+         org.vmir.cdt.scannerconfig plugin provides default implementation of the GNU C/C++ compiler specs builder.
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="copyright"/>
+      </appInfo>
+      <documentation>
+         
+      </documentation>
+   </annotation>
+
+</schema>
Index: src/org/eclipse/cdt/make/core/scannerconfig/IScannerConfigBuilderInfo.java
===================================================================
RCS file: src/org/eclipse/cdt/make/core/scannerconfig/IScannerConfigBuilderInfo.java
diff -N src/org/eclipse/cdt/make/core/scannerconfig/IScannerConfigBuilderInfo.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/make/core/scannerconfig/IScannerConfigBuilderInfo.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,34 @@
+/**********************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors: 
+ * IBM - Initial API and implementation
+ **********************************************************************/
+
+package org.eclipse.cdt.make.core.scannerconfig;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Settings for ScannerConfigBuilder
+ * 
+ * @author vhirsl
+ */
+public interface IScannerConfigBuilderInfo {
+	boolean isAutoDiscoveryEnabled();
+	void setAutoDiscoveryEnabled(boolean enabled) throws CoreException;
+
+	boolean isDefaultSpecsCmd();
+	void setUseDefaultSpecsCmd(boolean on) throws CoreException;
+
+	IPath getSpecsCommand();
+	void setSpecsCommand(IPath command) throws CoreException;
+
+	String getSpecsArguments();
+	void setSpecsArguments(String args) throws CoreException;
+}
Index: src/org/eclipse/cdt/make/core/scannerconfig/ISpecsBuilder.java
===================================================================
RCS file: src/org/eclipse/cdt/make/core/scannerconfig/ISpecsBuilder.java
diff -N src/org/eclipse/cdt/make/core/scannerconfig/ISpecsBuilder.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/make/core/scannerconfig/ISpecsBuilder.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,40 @@
+/**********************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors: 
+ * IBM - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.cdt.make.core.scannerconfig;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Interface for C/++ specs builders
+ * 
+ * @author vhirsl
+ */
+public interface ISpecsBuilder {
+	/**
+	 * Initializes specs builder
+	 * 
+	 * @param workingDirectory - where the compiler will be invoked
+	 * @param current project - current project being built
+	 * @return boolean - successful initialization
+	 */
+	public boolean initialize(IPath workingDirectory, IScannerConfigBuilderInfo buildInfo, IProject currentProject);
+	/**
+	 * Invokes a C/C++ compiler with target specific options to generate
+	 * compiler specs.
+	 * 
+	 * @param monitor
+	 * @param buildInfo - settings for ScannerConfigBuilder
+	 * @param targetSpecificOptions - array of options affecting compiler specs
+	 */
+	public boolean invokeCompiler(IProgressMonitor monitor, String[] targetSpecificOptions);
+}
Index: src/org/eclipse/cdt/make/core/scannerconfig/ScannerConfigBuilder.java
===================================================================
RCS file: src/org/eclipse/cdt/make/core/scannerconfig/ScannerConfigBuilder.java
diff -N src/org/eclipse/cdt/make/core/scannerconfig/ScannerConfigBuilder.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/make/core/scannerconfig/ScannerConfigBuilder.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,44 @@
+/**********************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors: 
+ * IBM - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.cdt.make.core.scannerconfig;
+
+import org.eclipse.cdt.core.resources.ACBuilder;
+import org.eclipse.cdt.make.core.MakeCorePlugin;
+import org.eclipse.core.resources.IProject;
+import java.util.Map;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+/**
+ * Runs after standard make builder.
+ * Consolidates discovered scanner configuration and updates project's scanner configuration.
+ * 
+ * @see IncrementalProjectBuilder
+ */
+public class ScannerConfigBuilder extends ACBuilder {
+	public final static String BUILDER_ID = MakeCorePlugin.getUniqueIdentifier() + ".ScannerConfigBuilder"; //$NON-NLS-1$
+
+	public ScannerConfigBuilder() {
+		super();
+	}
+
+	/**
+	 * @see IncrementalProjectBuilder#build
+	 */
+	protected IProject [] build(int kind, Map args, IProgressMonitor monitor) throws CoreException {
+		monitor.beginTask("", 100); //$NON-NLS-1$
+		// TODO: correct the monitor's text
+		monitor.subTask(MakeCorePlugin.getResourceString("ScannerConfigBuilder.Invoking_Builder") + getProject().getName());
+		ScannerInfoCollector.getInstance().updateScannerConfiguration(getProject(), new SubProgressMonitor(monitor, 100));
+		return getProject().getReferencedProjects();
+	}
+}
Index: src/org/eclipse/cdt/make/core/scannerconfig/ScannerConfigNature.java
===================================================================
RCS file: src/org/eclipse/cdt/make/core/scannerconfig/ScannerConfigNature.java
diff -N src/org/eclipse/cdt/make/core/scannerconfig/ScannerConfigNature.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/make/core/scannerconfig/ScannerConfigNature.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,131 @@
+/**********************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors: 
+ * IBM - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.cdt.make.core.scannerconfig;
+
+import org.eclipse.cdt.make.core.MakeCorePlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.resources.ICommand;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.IProjectNature;
+
+/**
+ * @see IProjectNature
+ */
+public class ScannerConfigNature implements IProjectNature {
+	
+	public final static String NATURE_ID = MakeCorePlugin.getUniqueIdentifier() + ".ScannerConfigNature"; //$NON-NLS-1$
+	private IProject fProject;
+
+	/**
+	 *
+	 */
+	public ScannerConfigNature() {
+	}
+
+	/**
+	 * @see IProjectNature#configure
+	 */
+	public void configure() throws CoreException {
+		IProjectDescription description = getProject().getDescription();
+		ICommand[] commands = description.getBuildSpec();
+		for (int i = 0; i < commands.length; ++i) {
+			if (commands[i].getBuilderName().equals(ScannerConfigBuilder.BUILDER_ID)) {
+				return;
+			}
+		}
+		ICommand command = description.newCommand();
+		command.setBuilderName(ScannerConfigBuilder.BUILDER_ID);
+		ICommand[] newCommands = new ICommand[commands.length + 1];
+		System.arraycopy(commands, 0, newCommands, 0, commands.length);
+		newCommands[commands.length] = command;
+		description.setBuildSpec(newCommands);
+		getProject().setDescription(description, null);
+	}
+
+	/**
+	 * @see IProjectNature#deconfigure
+	 */
+	public void deconfigure() throws CoreException {
+		IProjectDescription description = getProject().getDescription();
+		ICommand[] commands = description.getBuildSpec();
+		for (int i = 0; i < commands.length; ++i) {
+			if (commands[i].getBuilderName().equals(ScannerConfigBuilder.BUILDER_ID)) {
+				ICommand[] newCommands = new ICommand[commands.length - 1];
+				System.arraycopy(commands, 0, newCommands, 0, i);
+				System.arraycopy(commands, i + 1, newCommands, i, commands.length - i - 1);
+				description.setBuildSpec(newCommands);
+				break;
+			}
+		}
+		getProject().setDescription(description, null);
+	}
+
+	/**
+	 * @see IProjectNature#getProject
+	 */
+	public IProject getProject()  {
+		return fProject;
+	}
+
+	/**
+	 * @see IProjectNature#setProject
+	 */
+	public void setProject(IProject project)  {
+		fProject = project;
+	}
+	
+	static public void addScannerConfigNature(IProject project) throws CoreException {
+		if (project.hasNature(NATURE_ID))
+			return;
+		
+		IProjectDescription description = project.getDescription();
+		String[] ids = description.getNatureIds();
+		String[] newIds = new String[ids.length + 1];
+		System.arraycopy(ids, 0, newIds, 0, ids.length);
+		newIds[ids.length] = NATURE_ID;
+		description.setNatureIds(newIds);
+		project.setDescription(description, null);
+	}
+	
+	static public void removeScannerConfigNature(IProject project) throws CoreException {
+		IProjectDescription description = project.getDescription();
+		String[] ids = description.getNatureIds();
+		for (int i = 0; i < ids.length; ++i) {
+			if (ids[i].equals(NATURE_ID)) {
+				String[] newIds = new String[ids.length - 1];
+				System.arraycopy(ids, 0, newIds, 0, i);
+				System.arraycopy(ids, i + 1, newIds, i, ids.length - i - 1);
+				description.setNatureIds(newIds);
+				project.setDescription(description, null);
+			}
+		}
+	}
+
+	/**
+	 * Returns build command as stored in .project file
+	 * 
+	 * @param project
+	 * @param builderID
+	 * @return ICommand
+	 * @throws CoreException
+	 */
+	public static ICommand getBuildSpec(IProject project, String builderID) throws CoreException {
+		IProjectDescription description = project.getDescription();
+		ICommand[] commands = description.getBuildSpec();
+		for (int i = 0; i < commands.length; ++i) {
+			if (commands[i].getBuilderName().equals(builderID)) {
+				return commands[i];
+			}
+		}
+		return null;
+	}
+}
Index: src/org/eclipse/cdt/make/core/scannerconfig/ScannerInfoCollector.java
===================================================================
RCS file: src/org/eclipse/cdt/make/core/scannerconfig/ScannerInfoCollector.java
diff -N src/org/eclipse/cdt/make/core/scannerconfig/ScannerInfoCollector.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/make/core/scannerconfig/ScannerInfoCollector.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,327 @@
+/**********************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors: 
+ * IBM - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.cdt.make.core.scannerconfig;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.cdt.core.CCProjectNature;
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.CProjectNature;
+import org.eclipse.cdt.core.parser.IScannerInfo;
+import org.eclipse.cdt.core.parser.IScannerInfoProvider;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.cdt.make.core.MakeScannerInfo;
+import org.eclipse.cdt.make.core.MakeProjectNature;
+
+import org.eclipse.cdt.make.core.MakeCorePlugin;
+import org.eclipse.cdt.make.core.scannerconfig.util.CygpathTranslator;
+import org.eclipse.cdt.make.core.scannerconfig.util.ScannerConfigUtil;
+
+
+/**
+ * Singleton object that collects scanner config updates from ScannerInfoParser
+ * and updates scanner config when the project's build is done.
+ *
+ * @author vhirsl
+ */
+public class ScannerInfoCollector { 
+
+	// Singleton
+	private static ScannerInfoCollector instance = new ScannerInfoCollector();
+	private Map discoveredIncludes; 
+	private Map discoveredSymbols;
+	private Map discoveredTSO;	// target specific options
+	// cumulative values
+	private Map sumDiscoveredIncludes; 
+	private Map sumDiscoveredSymbols;
+	private Map sumDiscoveredTSO;	// target specific options
+	
+	private IProject currentProject;	// project being built
+	
+	private ScannerInfoCollector() {
+		discoveredIncludes = new HashMap();
+		discoveredSymbols = new HashMap();
+		discoveredTSO = new HashMap();
+		
+		sumDiscoveredIncludes = new HashMap();
+		sumDiscoveredSymbols = new HashMap();
+		sumDiscoveredTSO = new HashMap();
+	}
+	
+	public static ScannerInfoCollector getInstance() {
+		return instance;
+	}
+
+	/**
+	 * Published method to receive per file contributions to ScannerInfo
+	 * 
+	 * @param project
+	 * @param includes
+	 * @param symbols
+	 * @param targetSpecificOptions
+	 */
+	public synchronized void contributeToScannerConfig(IProject project, List includes, List symbols, List targetSpecificOptions) {
+		try {
+			if (project.hasNature(MakeProjectNature.NATURE_ID) && // limits to StandardMake projects
+					(project.hasNature(CProjectNature.C_NATURE_ID) ||
+					 project.hasNature(CCProjectNature.CC_NATURE_ID))) { 
+
+				String projectName = project.getName();
+				contribute(projectName, discoveredIncludes, includes);
+				contribute(projectName, discoveredSymbols, symbols);
+				contribute(projectName, discoveredTSO, targetSpecificOptions);
+			}
+		} 
+		catch (CoreException e) {
+			e.printStackTrace();
+		}
+	}
+	
+	/**
+	 * Published method to receive compiler specified contributions to ScannerInfo
+	 * 
+	 * @param includes
+	 * @param symbols
+	 */
+	public void contributeToScannerConfig(List includes, List symbols) {
+		contributeToScannerConfig(currentProject, includes, symbols, null);
+	}
+
+	/**
+	 * @param project
+	 * @param discovered symbols | includes | targetSpecificOptions
+	 * @param delta symbols | includes | targetSpecificOptions
+	 * @return true if there is a change in discovered symbols | includes | targetSpecificOptions
+	 */
+	private boolean contribute(String projectName, Map discovered, List delta) {
+		if (delta == null || delta.isEmpty())
+			return false;
+		List projectDiscovered = (List) discovered.get(projectName);
+		if (projectDiscovered == null) {
+			projectDiscovered = new ArrayList(delta);
+			discovered.put(projectName, projectDiscovered);
+			return true;
+		}
+		boolean added = false;
+		for (Iterator i = delta.iterator(); i.hasNext(); ) {
+			String item = (String) i.next();
+			if (!projectDiscovered.contains(item)) {
+				added |= projectDiscovered.add(item);
+			}
+		}
+		return added;
+	}
+
+	/**
+	 * @param project
+	 * @param monitor
+	 */
+	private void updateScannerConfig(IProject project, IProgressMonitor monitor) {
+		IScannerInfoProvider provider = CCorePlugin.getDefault().getScannerInfoProvider(project);
+		monitor.beginTask(MakeCorePlugin.getResourceString("ScannerInfoCollector.Processing"), 100);
+		if (provider != null) {
+			IScannerInfo scanInfo = provider.getScannerInformation(project);
+			if (scanInfo != null) {
+				if (scanInfo instanceof MakeScannerInfo) {
+					MakeScannerInfo makeScanInfo = (MakeScannerInfo)scanInfo;
+					String projectName = project.getName();
+					
+					monitor.subTask(MakeCorePlugin.getResourceString("ScannerInfoCollector.Processing"));
+					if (scannerConfigNeedsUpdate(makeScanInfo, projectName)) {
+						monitor.worked(50);
+						monitor.subTask(MakeCorePlugin.getResourceString("ScannerInfoCollector.Updating") + projectName);
+						
+						try {
+							// update scanner configuration
+							makeScanInfo.update();
+							monitor.worked(50);
+						} catch (CoreException e) {
+							// TODO : VMIR create a marker?
+							MakeCorePlugin.log(e);
+						}
+					}
+				}
+			}
+		}
+		monitor.done();
+	}
+
+	/**
+	 * Compare discovered include paths and symbol definitions with the ones from scanInfo.
+	 * @param scanInfo
+	 * @param projectName
+	 * @return
+	 */
+	private boolean scannerConfigNeedsUpdate(MakeScannerInfo makeScanInfo, String projectName) {
+		// TODO : VMIR to implement other variants
+		List includes = (List) discoveredIncludes.get(projectName);
+		Set symbols = new HashSet((List) discoveredSymbols.get(projectName));
+		if (includes == null && symbols == null)
+			return false;
+		
+		// Step 1. Add discovered scanner config to the existing discovered scanner config 
+		// add the includes from the latest discovery
+		boolean addedIncludes = false;
+		List sumIncludes = (List) sumDiscoveredIncludes.get(projectName);
+		if (sumIncludes == null) {
+			sumIncludes = new ArrayList(includes);
+			sumDiscoveredIncludes.put(projectName, sumIncludes);
+			addedIncludes = true;
+		}
+		else {
+			for (Iterator i = includes.iterator(); i.hasNext(); ) {
+				String include = (String) i.next();
+				if (!sumIncludes.contains(include)) {
+					addedIncludes |= sumIncludes.add(include);
+				}
+			}
+		}
+		// try to translate cygpaths to absolute paths
+		List finalSumIncludes = translateIncludePaths(sumIncludes);
+		
+		// add the symbols from the latest discovery
+		boolean addedSymbols = false;
+		Map sumSymbols = (Map) sumDiscoveredSymbols.get(projectName);
+		if (sumSymbols == null) {
+			sumSymbols = new HashMap();
+			sumDiscoveredSymbols.put(projectName, sumSymbols);
+		}
+		addedSymbols = ScannerConfigUtil.scAddSymbolsSet2SymbolEntryMap(sumSymbols, symbols, false);
+		
+		// Step 2. Get project's scanner config
+		String[] persistedIncludes = makeScanInfo.getIncludePaths();
+		Map persistedSymbols = makeScanInfo.getDefinedSymbols();
+		
+		// TODO VMIR this is likely to change when new UI is introduced
+		// Step 3. Merge scanner config from steps 1 and 2
+		List candidateIncludes = new ArrayList(Arrays.asList(persistedIncludes));
+		for (Iterator i = finalSumIncludes.iterator(); i.hasNext(); ) {
+			String include = (String) i.next();
+			if (!candidateIncludes.contains(include)) {
+				addedIncludes |= candidateIncludes.add(include);
+			}
+		}
+		Map candidateSymbols = new HashMap(sumSymbols);
+		Set persistedSymbolsSet = ScannerConfigUtil.scSymbolsMap2Set(persistedSymbols);
+		addedSymbols |= ScannerConfigUtil.scAddSymbolsSet2SymbolEntryMap(candidateSymbols, persistedSymbolsSet, true);
+		
+		// Step 4. Set resulting scanner config
+		makeScanInfo.setIncludePaths((String[])candidateIncludes.toArray(new String[candidateIncludes.size()]));
+		makeScanInfo.setPreprocessorSymbols((String[])ScannerConfigUtil.
+			scSymbolsSymbolEntryMap2Set(candidateSymbols).toArray(new String[candidateSymbols.size()]));
+		
+		// invalidate discovered include paths and symbol definitions
+		discoveredIncludes.put(projectName, null);
+		discoveredSymbols.put(projectName, null);
+		
+		return (addedIncludes | addedSymbols);
+	}
+
+	/**
+	 * @param sumIncludes
+	 * @return
+	 */
+	private List translateIncludePaths(List sumIncludes) {
+		List translatedIncludePaths = new ArrayList();
+		for (Iterator i = sumIncludes.iterator(); i.hasNext(); ) {
+			String includePath = (String) i.next();
+			IPath realPath = new Path(includePath);
+			if (!realPath.toFile().exists()) {
+				String translatedPath = new CygpathTranslator(currentProject, includePath).run();
+				if (!translatedPath.equals(includePath)) {
+					// Check if the translated path exists
+					IPath transPath = new Path(translatedPath);
+					if (transPath.toFile().exists()) {
+						translatedIncludePaths.add(translatedPath);
+					}
+					else {
+						// TODO VMIR create problem marker
+					}
+				}
+			}
+		}
+		return translatedIncludePaths;
+	}
+
+	private void getCompilerScannerInfo(final IProject project, 
+										final List tso, 
+										final IProgressMonitor monitor) {
+		// Call specs builder to get compiler's scanner info
+		final ISpecsBuilder specsBuilder = MakeCorePlugin.getDefault().
+										   loadSpecsBuilder(MakeCorePlugin.GCC_SPECS_BUILDER_ID);
+		if (specsBuilder != null) {
+			// get IScannerConfigBuilderInfo
+			IScannerConfigBuilderInfo info;
+			try {
+				info = MakeCorePlugin.createScannerConfigBuildInfo(
+						project, ScannerConfigBuilder.BUILDER_ID);
+			}
+			catch (CoreException e) {
+				MakeCorePlugin.log(e);
+				info = MakeCorePlugin.createScannerConfigBuildInfo(
+						MakeCorePlugin.getDefault().getPluginPreferences(), 
+						ScannerConfigBuilder.BUILDER_ID, false);
+			}
+			final IScannerConfigBuilderInfo buildInfo = info;
+			
+			ISafeRunnable runnable = new ISafeRunnable() {
+				public void run() {
+					if (specsBuilder.initialize(MakeCorePlugin.getWorkingDirectory(), buildInfo, project)) {
+						if (tso == null) {
+							specsBuilder.invokeCompiler(monitor, new String[0]);
+						}
+						else {
+							specsBuilder.invokeCompiler(monitor, (String[])tso.toArray(new String[tso.size()]));
+						}
+					}
+				}
+	
+				public void handleException(Throwable exception) {
+					MakeCorePlugin.log(exception);
+				}
+			};
+			Platform.run(runnable);
+		}
+	}
+
+	/**
+	 * @param project
+	 * @param monitor
+	 */
+	public synchronized void updateScannerConfiguration(IProject project, IProgressMonitor monitor) {
+		currentProject = project;
+		String projectName = project.getName();
+		// check TSO for the project
+		monitor.beginTask("", 100); //$NON-NLS-1$
+		getCompilerScannerInfo(project, (List) discoveredTSO.get(projectName), new SubProgressMonitor(monitor, 60));
+		updateScannerConfig(project, new SubProgressMonitor(monitor, 40));
+
+		// delete discovered scanner config
+		discoveredIncludes.put(projectName, null);
+		discoveredSymbols.put(projectName, null);
+		discoveredTSO.put(projectName, null);
+	}
+
+}
Index: src/org/eclipse/cdt/make/core/scannerconfig/gnu/GCCCompilerSpecsParser.java
===================================================================
RCS file: src/org/eclipse/cdt/make/core/scannerconfig/gnu/GCCCompilerSpecsParser.java
diff -N src/org/eclipse/cdt/make/core/scannerconfig/gnu/GCCCompilerSpecsParser.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/make/core/scannerconfig/gnu/GCCCompilerSpecsParser.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,90 @@
+/**********************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors: 
+ * IBM - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.cdt.make.core.scannerconfig.gnu;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.eclipse.cdt.core.ErrorParserManager;
+import org.eclipse.cdt.core.IErrorParser;
+
+import org.eclipse.cdt.make.core.scannerconfig.ScannerInfoCollector;
+
+/**
+ * Parses output of gcc -c -v specs.c or
+ *                  g++ -c -v specs.cpp
+ * command
+ * 
+ * @author vhirsl
+ */
+public class GCCCompilerSpecsParser implements IErrorParser {
+	private final int STATE_BEGIN = 0;
+	private final int STATE_SPECS_STARTED = 1;
+	private final int STATE_INCLUDES_STARTED = 2;
+	
+	private int state = STATE_BEGIN;
+	private List symbols = new ArrayList();
+	private List includes = new ArrayList();
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.core.IErrorParser#processLine(java.lang.String, org.eclipse.cdt.core.ErrorParserManager)
+	 */
+	public boolean processLine(String line, ErrorParserManager eoParser) {
+		boolean rc = false;
+		// Known patterns:
+		// (a) gcc|g++ ... -Dxxx -Iyyy ...
+		switch (state) {
+			case STATE_BEGIN:
+				if (line.startsWith("Reading specs from")) {	//$NON-NLS-1$
+					state = STATE_SPECS_STARTED;
+				}
+				return rc;
+			case STATE_SPECS_STARTED: 
+				if (line.indexOf("-D") != -1) {	//$NON-NLS-1$
+					// line contains -Ds, extract them
+					StringTokenizer scanner = new StringTokenizer(line);
+					if (scanner.countTokens() <= 1)
+						return rc;
+					for (String token = scanner.nextToken(); scanner.hasMoreTokens(); token = scanner.nextToken()) {
+						if (token.startsWith("-D")) {	//$NON-NLS-1$
+							String symbol = token.substring(2);
+							if (!symbols.contains(symbol))
+								symbols.add(symbol);
+						}
+					}
+				}
+				// now get all the includes
+				if (line.startsWith("#include") && line.endsWith("search starts here:")) { //$NON-NLS-1$ //$NON-NLS-2$
+					state = STATE_INCLUDES_STARTED;
+				}
+				return rc;
+			case STATE_INCLUDES_STARTED:
+				if (line.startsWith("#include") && line.endsWith("search starts here:")) { //$NON-NLS-1$ //$NON-NLS-2$
+					state = STATE_INCLUDES_STARTED;
+				}
+				else if (line.startsWith("End of search list.")) {	//$NON-NLS-1$
+					state = STATE_BEGIN;
+					break;
+				}
+				else {
+					if (!includes.contains(line))
+						includes.add(line);
+				}
+				return rc;
+			}
+			
+		ScannerInfoCollector.getInstance().contributeToScannerConfig(includes, symbols);
+			
+		return rc;
+	}
+
+}
Index: src/org/eclipse/cdt/make/core/scannerconfig/gnu/GCCScannerInfoParser.java
===================================================================
RCS file: src/org/eclipse/cdt/make/core/scannerconfig/gnu/GCCScannerInfoParser.java
diff -N src/org/eclipse/cdt/make/core/scannerconfig/gnu/GCCScannerInfoParser.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/make/core/scannerconfig/gnu/GCCScannerInfoParser.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,123 @@
+/**********************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors: 
+ * IBM - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.cdt.make.core.scannerconfig.gnu;
+
+import java.util.StringTokenizer;
+
+import org.eclipse.cdt.core.ErrorParserManager;
+import org.eclipse.cdt.core.IErrorParser;
+import org.eclipse.cdt.core.IMarkerGenerator;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.cdt.make.core.scannerconfig.ScannerInfoCollector;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Parses gcc and g++ output for -I and -D parameters.
+ * 
+ * @author vhirsl
+ */
+public class GCCScannerInfoParser implements IErrorParser {
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.core.IErrorParser#processLine(java.lang.String, org.eclipse.cdt.core.ErrorParserManager)
+	 */
+	public boolean processLine(String line, ErrorParserManager eoParser) {
+		boolean rc = false;
+		// Known patterns:
+		// (a) gcc|g++ ... -Dxxx -Iyyy ...
+		StringTokenizer scanner = new StringTokenizer(line);
+		if (scanner.countTokens() <= 1)
+			return false;
+		String token = scanner.nextToken();
+		if (token.equalsIgnoreCase("gcc") || token.equalsIgnoreCase("g++")) {//$NON-NLS-1$ //$NON-NLS-2$
+			// Recognized gcc or g++ compiler invocation
+			List includes = new ArrayList();
+			List symbols = new ArrayList();
+			List targetSpecificOptions = new ArrayList();
+
+			rc = true;
+			String fileName = null;
+			String desc = "Found";
+			while (scanner.hasMoreTokens()) {
+				token = scanner.nextToken();
+				if (token.startsWith("-D")) {//$NON-NLS-1$
+					String symbol = token.substring(2);
+					if (!symbols.contains(symbol))
+						symbols.add(symbol);
+				}
+				else if (token.startsWith("-I")) {//$NON-NLS-1$
+					String iPath = token.substring(2);
+					if (!includes.contains(iPath))
+						includes.add(iPath);
+				}
+				else if (token.equals("-mwin32") ||		//$NON-NLS-1$
+						 token.equals("-mno-win32") ||	//$NON-NLS-1$
+						 token.equals("-mno-cygwin") ||	//$NON-NLS-1$
+						 token.equals("-ansi") ||		//$NON-NLS-1$
+						 token.equals("-nostdinc")) {	//$NON-NLS-1$
+					if (!targetSpecificOptions.contains(token))
+						targetSpecificOptions.add(token);
+				}
+				else {
+					String possibleFileName = token.toLowerCase();
+					if (possibleFileName.endsWith(".c") || 			//$NON-NLS-1$
+							possibleFileName.endsWith(".cpp") ||	//$NON-NLS-1$
+							possibleFileName.endsWith(".cc") ||		//$NON-NLS-1$
+							possibleFileName.endsWith(".cxx")) {	//$NON-NLS-1$
+						fileName = token;
+					}
+				}
+			}
+			
+			IFile file = null;
+			if (fileName != null) {
+				file = eoParser.findFilePath(fileName);
+	
+				if (file == null) {
+					// Parse the entire project.
+					file = eoParser.findFileName(fileName);
+					if (file != null) {
+						// If there is a conflict set the error on the project.
+						if (eoParser.isConflictingName(fileName)) {
+							desc = "*" + desc;
+							file = null;
+						}
+					}
+				}
+				
+				// Contribute discovered includes and symbols to the ScannerInfoCollector
+				if (file != null) {
+					IProject project = file.getProject();
+					ScannerInfoCollector.getInstance().
+						contributeToScannerConfig(project, includes, symbols, targetSpecificOptions);
+				}
+			}
+			
+			// TODO : VMIR remove when debugging is done
+			int severity = IMarkerGenerator.SEVERITY_INFO;
+			
+			for (Iterator i = includes.iterator(); i.hasNext(); ) {
+				String iPath = (String)i.next();
+				eoParser.generateMarker(file, -1, "Found an include path: "+iPath, severity, iPath);
+			}
+			for (Iterator i = symbols.iterator(); i.hasNext(); ) {
+				String symbol = (String)i.next();
+				eoParser.generateMarker(file, -1, "Found a symbol definition: "+symbol, severity, symbol);
+			}
+			
+		}
+		return false;
+	}
+}
Index: src/org/eclipse/cdt/make/core/scannerconfig/gnu/GCCSpecsBuilder.java
===================================================================
RCS file: src/org/eclipse/cdt/make/core/scannerconfig/gnu/GCCSpecsBuilder.java
diff -N src/org/eclipse/cdt/make/core/scannerconfig/gnu/GCCSpecsBuilder.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/make/core/scannerconfig/gnu/GCCSpecsBuilder.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,271 @@
+/**********************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors: 
+ * IBM - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.cdt.make.core.scannerconfig.gnu;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import org.eclipse.cdt.core.CCProjectNature;
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.CProjectNature;
+import org.eclipse.cdt.core.CommandLauncher;
+import org.eclipse.cdt.core.ErrorParserManager;
+import org.eclipse.cdt.core.IMarkerGenerator;
+import org.eclipse.cdt.core.model.ICModelMarker;
+import org.eclipse.cdt.core.resources.IConsole;
+import org.eclipse.cdt.make.core.MakeCorePlugin;
+import org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo;
+import org.eclipse.cdt.make.core.scannerconfig.ISpecsBuilder;
+import org.eclipse.cdt.make.internal.core.StreamMonitor;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+/**
+ * New type
+ * 
+ * @author vhirsl
+ */
+public class GCCSpecsBuilder implements ISpecsBuilder, IMarkerGenerator {
+	
+	private static final String BUILD_ERROR = "SpecsBuilder.Build_Error"; //$NON-NLS-1$
+	private static final String SPECS_ERROR_PARSER = MakeCorePlugin.getUniqueIdentifier() + ".GCCSpecsParser"; //$NON-NLS-1$
+	private static final String SPECS_BUILDER_CONSOLE_ID = MakeCorePlugin.getUniqueIdentifier() + ".SpecsBuilderConsole";	//$NON-NLS-1$
+	
+	private IPath workingDirectory;
+	private IProject currentProject;
+	private IPath fCompileCommand;
+	private String fCompileArguments = null;
+	private String targetFile;
+	private IScannerConfigBuilderInfo fBuildInfo;
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.make.core.scannerconfig.ISpecsBuilder#initialize(org.eclipse.core.runtime.IPath, org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo, org.eclipse.core.resources.IProject)
+	 */
+	public boolean initialize(IPath workingDirectory, IScannerConfigBuilderInfo buildInfo, IProject currentProject) {
+		boolean rc = false;
+		this.workingDirectory = workingDirectory;
+		this.currentProject = currentProject;
+		this.fBuildInfo = buildInfo;
+		try {
+			fCompileCommand = fBuildInfo.getSpecsCommand();
+			if (fCompileCommand != null) {
+				fCompileArguments = fBuildInfo.getSpecsArguments();
+				if (currentProject.hasNature(CCProjectNature.CC_NATURE_ID)) {
+					targetFile = MakeCorePlugin.CPP_SPECS_FILE;
+				}
+				else if (currentProject.hasNature(CProjectNature.C_NATURE_ID)) {
+					targetFile = MakeCorePlugin.C_SPECS_FILE;
+				}
+				rc = true;
+			}
+		} catch (CoreException e) {
+			fCompileCommand = null;
+			CCorePlugin.log(e);
+		}
+		return rc;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.make.core.scannerconfig.ISpecsBuilder#invokeCompiler(org.eclipse.core.runtime.IProgressMonitor, java.lang.String[])
+	 */
+	public boolean invokeCompiler(IProgressMonitor monitor, String[] targetSpecificOptions) {
+		if (monitor == null) {
+			monitor = new NullProgressMonitor();
+		}
+		monitor.beginTask(MakeCorePlugin.getResourceString("SpecsBuilder.Reading_Specs"), 100); //$NON-NLS-1$
+		
+		try {
+			if (fCompileCommand != null) {
+				IConsole console = CCorePlugin.getDefault().getConsole("SPECS_BUILDER_CONSOLE_ID");
+				console.start(currentProject);
+				OutputStream cos = console.getOutputStream();
+
+				// Before launching give visual cues via the monitor
+				monitor.subTask(MakeCorePlugin.getResourceString("SpecsBuilder.Reading_Specs")); //$NON-NLS-1$
+				
+				String errMsg = null;
+				CommandLauncher launcher = new CommandLauncher();
+				// Print the command for visual interaction.
+				launcher.showCommand(true);
+
+				// add file and TSO
+				String[] compileArguments = prepareArguments(targetSpecificOptions);
+
+				String ca = coligate(compileArguments);
+
+				monitor.subTask(MakeCorePlugin.getResourceString("SpecsBuilder.Invoking_Command")
+						+ fCompileCommand.toString() + ca); //$NON-NLS-1$
+				cos = new StreamMonitor(new SubProgressMonitor(monitor, 70), cos, 100);
+				ErrorParserManager epm = new ErrorParserManager(currentProject, this, new String[] {SPECS_ERROR_PARSER});
+				epm.setOutputStream(cos);
+				OutputStream stdout = epm.getOutputStream();
+				OutputStream stderr = epm.getOutputStream();
+				Process p = launcher.execute(fCompileCommand, compileArguments, setEnvironment(launcher), workingDirectory);
+				if (p != null) {
+					try {
+						// Close the input of the Process explicitely.
+						// We will never write to it.
+						p.getOutputStream().close();
+					} catch (IOException e) {
+					}
+					if (launcher.waitAndRead(stdout, stderr, new SubProgressMonitor(monitor, 0))
+							!= CommandLauncher.OK)
+						errMsg = launcher.getErrorMessage();
+					monitor.subTask(MakeCorePlugin.getResourceString("SpecsBuilder.Parsing_Output")); //$NON-NLS-1$
+				}
+				else {
+					errMsg = launcher.getErrorMessage();
+				}
+
+				if (errMsg != null) {
+					String errorDesc = MakeCorePlugin.getFormattedString(BUILD_ERROR, 
+							fCompileCommand.toString() + ca);
+					epm.generateMarker(currentProject, -1, errorDesc, IMarkerGenerator.SEVERITY_ERROR_BUILD, null);
+				}
+
+				stdout.close();
+				stderr.close();
+
+				monitor.subTask(MakeCorePlugin.getResourceString("SpecsBuidler.Creating_Markers")); //$NON-NLS-1$
+				epm.reportProblems();
+				cos.close();
+			}
+		} catch (Exception e) {
+			CCorePlugin.log(e);
+		} finally {
+			monitor.done();
+		}
+		return true;
+	}
+
+	/**
+	 * @param tso
+	 * @return
+	 */
+	private String[] prepareArguments(String[] tso) {
+		String[] rv = null;
+		// commandArguments may have multiple arguments; tokenizing
+		int nTokens = 0;
+		if (fCompileArguments != null && fCompileArguments.length() > 0) {
+			StringTokenizer tokenizer = new StringTokenizer(fCompileArguments, " ");//$NON-NLS-1$
+			nTokens = tokenizer.countTokens();
+			if (nTokens > 0) {
+				rv = new String[nTokens + 1 + tso.length];
+				for (int i = 0; tokenizer.hasMoreTokens(); ++i) {
+					rv[i] = tokenizer.nextToken();
+				}
+			}
+		}
+		if (rv == null) {
+			rv = new String[1 + tso.length];
+		}
+		rv[nTokens] = targetFile;
+		for (int i = 0; i < tso.length; ++i) {
+			rv[nTokens + 1 + i] = tso[i];
+		}
+		return rv;
+	}
+
+	/**
+	 * @param array
+	 * @return
+	 */
+	private String coligate(String[] array) {
+		StringBuffer sb = new StringBuffer(128);
+		for (int i = 0; i < array.length; ++i) {
+			sb.append(' ');
+			sb.append(array[i]);
+		}
+		String ca = sb.toString();
+		return ca;
+	}
+
+	/**
+	 * @param launcher
+	 * @return
+	 */
+	private String[] setEnvironment(CommandLauncher launcher) {
+		// Set the environmennt, some scripts may need the CWD var to be set.
+		Properties props = launcher.getEnvironment();
+		props.put("CWD", workingDirectory.toOSString()); //$NON-NLS-1$
+		props.put("PWD", workingDirectory.toOSString()); //$NON-NLS-1$
+		String[] env = null;
+		ArrayList envList = new ArrayList();
+		Enumeration names = props.propertyNames();
+		if (names != null) {
+			while (names.hasMoreElements()) {
+				String key = (String) names.nextElement();
+				envList.add(key + "=" + props.getProperty(key)); //$NON-NLS-1$
+			}
+			env = (String[]) envList.toArray(new String[envList.size()]);
+		}
+		return env;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.core.IMarkerGenerator#addMarker(org.eclipse.core.resources.IResource, int, java.lang.String, int, java.lang.String)
+	 */
+	public void addMarker(IResource file, int lineNumber, String errorDesc, int severity, String errorVar) {
+		try {
+			IMarker[] cur = file.findMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_ONE);
+			/*
+			 * Try to find matching markers and don't put in duplicates
+			 */
+			if ((cur != null) && (cur.length > 0)) {
+				for (int i = 0; i < cur.length; i++) {
+					int line = ((Integer) cur[i].getAttribute(IMarker.LOCATION)).intValue();
+					int sev = ((Integer) cur[i].getAttribute(IMarker.SEVERITY)).intValue();
+					String mesg = (String) cur[i].getAttribute(IMarker.MESSAGE);
+					if (line == lineNumber && sev == mapMarkerSeverity(severity) && mesg.equals(errorDesc)) {
+						return;
+					}
+				}
+			}
+
+			IMarker marker = file.createMarker(ICModelMarker.C_MODEL_PROBLEM_MARKER);
+			marker.setAttribute(IMarker.LOCATION, lineNumber);
+			marker.setAttribute(IMarker.MESSAGE, errorDesc);
+			marker.setAttribute(IMarker.SEVERITY, mapMarkerSeverity(severity));
+			marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
+			marker.setAttribute(IMarker.CHAR_START, -1);
+			marker.setAttribute(IMarker.CHAR_END, -1);
+			if (errorVar != null) {
+				marker.setAttribute(ICModelMarker.C_MODEL_MARKER_VARIABLE, errorVar);
+			}
+		}
+		catch (CoreException e) {
+			CCorePlugin.log(e.getStatus());
+		}
+	}
+
+	int mapMarkerSeverity(int severity) {
+		switch (severity) {
+			case SEVERITY_ERROR_BUILD :
+			case SEVERITY_ERROR_RESOURCE :
+				return IMarker.SEVERITY_ERROR;
+			case SEVERITY_INFO :
+				return IMarker.SEVERITY_INFO;
+			case SEVERITY_WARNING :
+				return IMarker.SEVERITY_WARNING;
+		}
+		return IMarker.SEVERITY_ERROR;
+	}
+}
Index: src/org/eclipse/cdt/make/core/scannerconfig/util/CygpathTranslator.java
===================================================================
RCS file: src/org/eclipse/cdt/make/core/scannerconfig/util/CygpathTranslator.java
diff -N src/org/eclipse/cdt/make/core/scannerconfig/util/CygpathTranslator.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/make/core/scannerconfig/util/CygpathTranslator.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,111 @@
+/**********************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors: 
+ * IBM - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.cdt.make.core.scannerconfig.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Properties;
+
+import org.eclipse.cdt.core.CommandLauncher;
+import org.eclipse.cdt.make.core.MakeCorePlugin;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * TODO Provide description
+ * 
+ * @author vhirsl
+ */
+public class CygpathTranslator {
+	IProject project;
+	private String orgPath;
+	private String transPath;
+
+	public CygpathTranslator(IProject project, String path) {
+		this.project = project;
+		orgPath = path;
+	}
+	
+	public String run() {
+		ISafeRunnable runnable = new ISafeRunnable() {
+			public void run() throws Exception {
+				transPath = platformRun();
+			}
+
+			public void handleException(Throwable exception) {
+				transPath = orgPath;
+				MakeCorePlugin.log(exception);
+			}
+		};
+		Platform.run(runnable);
+		return transPath;
+	}
+
+	/**
+	 * @return
+	 */
+	private String platformRun() {
+		CommandLauncher launcher = new CommandLauncher();
+		launcher.showCommand(false);
+
+		OutputStream output = new ByteArrayOutputStream();
+
+		Process p = launcher.execute(
+			new Path("cygpath"),			//$NON-NLS-1$
+			new String[] {"-m", orgPath},	//$NON-NLS-1$
+			new String[0],//setEnvironment(launcher, "c:/"),//$NON-NLS-1$
+			new Path("."));				//$NON-NLS-1$
+		if (p != null) {
+			try {
+				// Close the input of the Process explicitely.
+				// We will never write to it.
+				p.getOutputStream().close();
+			}
+			catch (IOException e) {
+			}
+			if (launcher.waitAndRead(output, output) != CommandLauncher.OK) {
+				String errMsg = launcher.getErrorMessage();
+			}
+			else
+				return output.toString().trim();
+		}
+		return orgPath;
+	}
+
+	/**
+	 * @param launcher
+	 * @return
+	 */
+	private String[] setEnvironment(CommandLauncher launcher, String dir) {
+		// Set the environmennt, some scripts may need the CWD var to be set.
+		IPath workingDirectory = new Path(dir);
+		Properties props = launcher.getEnvironment();
+		props.put("CWD", workingDirectory.toOSString()); //$NON-NLS-1$
+		props.put("PWD", workingDirectory.toOSString()); //$NON-NLS-1$
+		String[] env = null;
+		ArrayList envList = new ArrayList();
+		Enumeration names = props.propertyNames();
+		if (names != null) {
+			while (names.hasMoreElements()) {
+				String key = (String) names.nextElement();
+				envList.add(key + "=" + props.getProperty(key)); //$NON-NLS-1$
+			}
+			env = (String[]) envList.toArray(new String[envList.size()]);
+		}
+		return env;
+	}
+}
Index: src/org/eclipse/cdt/make/core/scannerconfig/util/ScannerConfigUtil.java
===================================================================
RCS file: src/org/eclipse/cdt/make/core/scannerconfig/util/ScannerConfigUtil.java
diff -N src/org/eclipse/cdt/make/core/scannerconfig/util/ScannerConfigUtil.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/make/core/scannerconfig/util/ScannerConfigUtil.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,96 @@
+/**********************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors: 
+ * IBM - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.cdt.make.core.scannerconfig.util;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Utility class that handles some Scanner Config specifig collection conversions
+ * 
+ * @author vhirsl
+ */
+public final class ScannerConfigUtil {
+	
+	/**
+	 * Converts a map of symbols to a set
+	 * 
+	 * @param symbolsMap
+	 * @return
+	 */
+	public static Set scSymbolsMap2Set(Map symbolsMap) {
+		Set retSymbols = new HashSet();
+		Set keys = symbolsMap.keySet();
+		for (Iterator i = keys.iterator(); i.hasNext(); ) {
+			String symbol;
+			String key = (String) i.next();
+			String value = (String) symbolsMap.get(key);
+			if (value == null || value.length() == 0) {
+				symbol = key;
+			}
+			else {
+				symbol = key + "=" + value;	//$NON-NLS-1
+			}
+			retSymbols.add(symbol);
+		}
+		return retSymbols;
+	}
+
+	/**
+	 * Adds all new discovered symbols/values to the existing ones.
+	 *  
+	 * @param sumSymbols - a map of [String, Set] where Set is a SymbolEntry
+	 * @param symbols
+	 * @return boolean
+	 */
+	public static boolean scAddSymbolsSet2SymbolEntryMap(Map sumSymbols, Set symbols, boolean preferred) {
+		boolean rc = false;
+		for (Iterator i = symbols.iterator(); i.hasNext(); ) {
+			String symbol = (String) i.next();
+			String key;
+			String value = null;
+			int index = symbol.indexOf("="); //$NON-NLS-1$
+			if (index != -1) {
+				key = symbol.substring(0, index).trim();
+				value = symbol.substring(index + 1).trim();
+			} else {
+				key = symbol.trim();
+			}
+			SymbolEntry sEntry = (SymbolEntry) sumSymbols.get(key);
+			if (sEntry == null) {
+				sEntry = new SymbolEntry(key, value, true);
+				rc = true;
+			}
+			else {
+				rc |= sEntry.add(value, preferred);
+			}
+			sumSymbols.put(key, sEntry);
+		}
+		return rc;
+	}
+
+	/**
+	 * Gets all discovered symbols with preferred values
+	 * @param sumSymbols
+	 * @return
+	 */
+	public static Set scSymbolsSymbolEntryMap2Set(Map sumSymbols) {
+		Set symbols = (Set) sumSymbols.entrySet();
+		Set rv = new HashSet(symbols.size());
+		for (Iterator i = symbols.iterator(); i.hasNext(); ) {
+			SymbolEntry sEntry = (SymbolEntry) ((Map.Entry) i.next()).getValue();
+			rv.add(sEntry.getPreferedRaw());
+		}
+		return rv;
+	}
+}
Index: src/org/eclipse/cdt/make/core/scannerconfig/util/SymbolEntry.java
===================================================================
RCS file: src/org/eclipse/cdt/make/core/scannerconfig/util/SymbolEntry.java
diff -N src/org/eclipse/cdt/make/core/scannerconfig/util/SymbolEntry.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/make/core/scannerconfig/util/SymbolEntry.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,127 @@
+/**********************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors: 
+ * IBM - Initial API and implementation
+ **********************************************************************/
+
+package org.eclipse.cdt.make.core.scannerconfig.util;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+
+/**
+ * Represents a symbol definition with possible multiple values
+ * example:
+ * 		LOG_LEVEL
+ * 		LOG_LEVEL = 2
+ * 		LOG_LEVEL = LOG_BASE + 1
+ * @author vhirsl
+ */
+public class SymbolEntry {
+	private static final String UNSPECIFIED_VALUE = "1";	//$NON-NLS-1$
+	private String name;
+	private Set values;
+	private String preferredValue;	// the first added value unless otherwise specified
+	
+	public SymbolEntry(String name) {
+		this.name = name;
+	}
+	public SymbolEntry(String name, String value) {
+		this(name);
+		if (values == null) {
+			values = new HashSet();
+		}
+		values.add(value);
+	}
+	public SymbolEntry(String name, String value, boolean preferred) {
+		this(name, value);
+		if (preferred) {
+			preferredValue = value;
+		}
+	}
+
+	public boolean add(String value) {
+		if (values == null) {
+			values = new HashSet();
+		}
+		if (preferredValue == null) {
+			preferredValue = value;
+		}
+		return values.add(value);
+	}
+	public boolean add(String value, boolean preferred) {
+		boolean rc = add(value);
+		if (preferred) {
+			preferredValue = value;
+		}
+		return rc;
+	}
+	public boolean addAll(SymbolEntry se) {
+		return values.addAll(se.values);
+	}
+	
+	public void removeAll() {
+		values = null;
+		preferredValue = null;
+	}
+	
+	public String getPrefered() {
+		return name+ "=" + (preferredValue == null ? UNSPECIFIED_VALUE : preferredValue);//$NON-NLS-1$
+	}
+	public String getPreferedRaw() {
+		return name + (preferredValue == null ? "" : "=" + preferredValue);//$NON-NLS-1$ //$NON-NLS-2$
+	}
+	
+	public Set getAllButPreferred() {
+		if (values == null)
+			return null;
+		Set rv = new HashSet(values.size());
+		for (Iterator i = values.iterator(); i.hasNext(); ) {
+			String val = (String) i.next();
+			if (val.equals(preferredValue))
+				continue;
+			rv.add(name + "=" + (val == null ? UNSPECIFIED_VALUE : val));//$NON-NLS-1$
+		}
+		return rv;
+	}
+	public Set getAllButPreferredRaw() {
+		if (values == null)
+			return null;
+		Set rv = new HashSet(values.size());
+		for (Iterator i = values.iterator(); i.hasNext(); ) {
+			String val = (String) i.next();
+			if (val.equals(preferredValue))
+				continue;
+			rv.add(name + (val == null ? "" : "=" + val));//$NON-NLS-1$ //$NON-NLS-2$
+		}
+		return rv;
+	}
+	public Set getAll() {
+		if (values == null)
+			return null;
+		Set rv = new HashSet(values.size());
+		for (Iterator i = values.iterator(); i.hasNext(); ) {
+			String val = (String) i.next();
+			rv.add(name + "=" + (val == null ? UNSPECIFIED_VALUE : val));//$NON-NLS-1$
+		}
+		return rv;
+	}
+	public Set getAllRaw() {
+		if (values == null)
+			return null;
+		Set rv = new HashSet(values.size());
+		for (Iterator i = values.iterator(); i.hasNext(); ) {
+			String val = (String) i.next();
+			rv.add(name + (val == null ? "" : "=" + val));//$NON-NLS-1$ //$NON-NLS-2$
+		}
+		return rv;
+	}
+	
+}
Index: src/org/eclipse/cdt/make/internal/core/scannerconfig/ScannerConfigInfoFactory.java
===================================================================
RCS file: src/org/eclipse/cdt/make/internal/core/scannerconfig/ScannerConfigInfoFactory.java
diff -N src/org/eclipse/cdt/make/internal/core/scannerconfig/ScannerConfigInfoFactory.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/make/internal/core/scannerconfig/ScannerConfigInfoFactory.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,259 @@
+/**********************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors: 
+ * IBM - Initial API and implementation
+ **********************************************************************/
+
+package org.eclipse.cdt.make.internal.core.scannerconfig;
+
+import java.util.Map;
+
+import org.eclipse.core.resources.ICommand;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.cdt.make.core.MakeCorePlugin;
+import org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo;
+import org.eclipse.cdt.make.core.scannerconfig.ScannerConfigNature;
+
+/**
+ * Creates a ScannerConfigBuilderInfo variant
+ * @author vhirsl
+ */
+public class ScannerConfigInfoFactory {
+	private static final String PREFIX = MakeCorePlugin.getUniqueIdentifier();
+
+	static final String BUILD_SCANNER_CONFIG_ENABLED = PREFIX + ".ScannerConfigDiscoveryEnabled"; //$NON-NLS-1$
+	static final String USE_DEFAULT_SPECS_CMD = PREFIX + ".useDefaultSpecsCmd"; //$NON-NLS-1$
+	static final String SPECS_COMMAND = PREFIX + ".specsCommand"; //$NON-NLS-1$
+	static final String SPECS_ARGUMENTS = PREFIX + ".specsArguments"; //$NON-NLS-1$
+	
+	/**
+	 *
+	 * @author vhirsl
+	 */
+	private abstract static class Store implements IScannerConfigBuilderInfo {
+		/* (non-Javadoc)
+		 * @see org.vmir.cdt.scannerconfig.make.core.IScannerConfigBuilderInfo#isAutoDiscoveryEnabled()
+		 */
+		public boolean isAutoDiscoveryEnabled() {
+			return getBoolean(BUILD_SCANNER_CONFIG_ENABLED);
+		}
+
+		/* (non-Javadoc)
+		 * @see org.vmir.cdt.scannerconfig.make.core.IScannerConfigBuilderInfo#setAutoDiscoveryEnabled(boolean)
+		 */
+		public void setAutoDiscoveryEnabled(boolean enabled) throws CoreException {
+			putString(BUILD_SCANNER_CONFIG_ENABLED, Boolean.toString(enabled));
+		}
+
+		/* (non-Javadoc)
+		 * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo#isDefaultSpecsCmd()
+		 */
+		public boolean isDefaultSpecsCmd() {
+			if (getString(USE_DEFAULT_SPECS_CMD) == null ||
+				getString(USE_DEFAULT_SPECS_CMD).length() == 0) { // if no property then default to true
+				return true;
+			}
+			return getBoolean(USE_DEFAULT_SPECS_CMD);
+		}
+
+		/* (non-Javadoc)
+		 * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo#setUseDefaultSpecsCmd(boolean)
+		 */
+		public void setUseDefaultSpecsCmd(boolean on) throws CoreException {
+			putString(USE_DEFAULT_SPECS_CMD, Boolean.toString(on));
+		}
+
+		/* (non-Javadoc)
+		 * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo#getSpecsCommand()
+		 */
+		public IPath getSpecsCommand() {
+			if (isDefaultSpecsCmd()) {
+				String command = getSpecsParameter("defaultCommand"); //$NON-NLS-1$
+				if (command == null) {
+					return new Path("gcc"); //$NON-NLS-1$
+				}
+				return new Path(command);
+			}
+			return new Path(getString(SPECS_COMMAND));
+		}
+
+		/* (non-Javadoc)
+		 * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo#setSpecsCommand(org.eclipse.core.runtime.IPath)
+		 */
+		public void setSpecsCommand(IPath command) throws CoreException {
+			putString(SPECS_COMMAND, command.toString());
+		}
+		
+		/* (non-Javadoc)
+		 * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo#getSpecsArguments()
+		 */
+		public String getSpecsArguments() {
+			if (isDefaultSpecsCmd()) {
+				String command = getSpecsParameter("defaultAttributes"); //$NON-NLS-1$
+				if (command == null) {
+					command = "-c -v"; //$NON-NLS-1$
+				}
+				return command;
+			}
+			return getString(SPECS_ARGUMENTS);
+		}
+
+		/* (non-Javadoc)
+		 * @see org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo#setSpecsArguments(java.lang.String)
+		 */
+		public void setSpecsArguments(String args) throws CoreException {
+			putString(SPECS_ARGUMENTS, args);
+		}
+
+		protected boolean getBoolean(String property) {
+			return Boolean.valueOf(getString(property)).booleanValue();
+		}
+		protected abstract String getBuilderID();
+		protected abstract String getString(String property);
+		protected abstract void putString(String name, String value) throws CoreException;
+
+		protected String getSpecsParameter(String name) {
+			IExtension extension =
+				Platform.getPluginRegistry().getExtension(
+						MakeCorePlugin.getUniqueIdentifier(),
+						MakeCorePlugin.SPECS_BUILDER_SIMPLE_ID,
+// TODO VMIR account for possible multiple available specs builders
+						MakeCorePlugin.GCC_SPECS_BUILDER_ID);
+			if (extension == null)
+				return null;
+			IConfigurationElement[] configs = extension.getConfigurationElements();
+			if (configs.length == 0)
+				return null;
+			IConfigurationElement[] runElement = configs[0].getChildren("run"); //$NON-NLS-1$
+			IConfigurationElement[] paramElement = runElement[0].getChildren("parameter"); //$NON-NLS-1$
+			for (int i = 0; i < paramElement.length; i++) {
+				if (paramElement[i].getAttribute("name").equals(name)) { //$NON-NLS-1$
+					return paramElement[i].getAttribute("value"); //$NON-NLS-1$
+				}
+			}
+			return null;
+		}
+	}
+	
+	/**
+	 *
+	 * @author vhirsl
+	 */
+	private static class Preference extends Store {
+		private Preferences prefs;
+		private String builderID;
+		private boolean useDefaults;
+
+		Preference(Preferences prefs, String builderID, boolean useDefaults) {
+			this.prefs = prefs;
+			this.builderID = builderID;
+			this.useDefaults = useDefaults;
+		}
+
+		protected void putString(String name, String value) {
+			if (useDefaults) {
+				prefs.setDefault(name, value);
+			} else {
+				prefs.setValue(name, value);
+			}
+		}
+
+		protected String getString(String property) {
+			if (useDefaults) {
+				return prefs.getDefaultString(property);
+			}
+			return prefs.getString(property);
+		}
+
+		protected String getBuilderID() {
+			return builderID;
+		}
+	}
+	
+	private static class BuildProperty extends Store {
+		private IProject project;
+		private String builderID;
+		private Map args;
+
+		BuildProperty(IProject project, String builderID) throws CoreException {
+			this.project = project;
+			this.builderID = builderID;
+			ICommand builder = ScannerConfigNature.getBuildSpec(project, builderID);
+			if (builder == null) {
+				throw new CoreException(new Status(IStatus.ERROR,
+						MakeCorePlugin.getUniqueIdentifier(), -1,
+						MakeCorePlugin.getResourceString("ScannerConfigInfoFactory.Missing_Builder")//$NON-NLS-1$
+							+ builderID, null)); 
+			}
+			args = builder.getArguments();
+		}
+
+		protected void putString(String name, String value) throws CoreException {
+			String curValue = (String) args.get(name);
+			if (curValue != null && curValue.equals(value)) {
+				return;
+			}
+			ICommand builder = ScannerConfigNature.getBuildSpec(project, builderID);
+			args.put(name, value);
+			builder.setArguments(args);
+			project.setDescription(project.getDescription(), null);
+		}
+
+		protected String getString(String name) {
+			String value = (String) args.get(name);
+			return value == null ? "" : value; //$NON-NLS-1$
+		}
+
+		protected String getBuilderID() {
+			return builderID;
+		}
+	}
+
+	private static class BuildArguments extends Store {
+		private Map args;
+		private String builderID;
+
+		BuildArguments(Map args, String builderID) {
+			this.args = args;
+			this.builderID = builderID;
+		}
+
+		protected void putString(String name, String value) {
+			args.put(name, value);
+		}
+
+		protected String getString(String name) {
+			return (String) args.get(name);
+		}
+
+		protected String getBuilderID() {
+			return builderID;
+		}
+	}
+
+	public static IScannerConfigBuilderInfo create(Preferences prefs, String builderID, boolean useDefaults) {
+		return new ScannerConfigInfoFactory.Preference(prefs, builderID, useDefaults);
+	}
+
+	public static IScannerConfigBuilderInfo create(IProject project, String builderID) throws CoreException {
+		return new ScannerConfigInfoFactory.BuildProperty(project, builderID);
+	}
+
+	public static IScannerConfigBuilderInfo create(Map args, String builderID) {
+		return new ScannerConfigInfoFactory.BuildArguments(args, builderID);
+	}
+}
Index: plugin.properties
===================================================================
retrieving revision 1.7
diff -u -r1.7 plugin.properties
--- plugin.properties	17 Oct 2003 02:34:10 -0000	1.7
+++ plugin.properties	18 Feb 2004 21:47:23 -0000
@@ -46,3 +46,5 @@
  
 MakefileEditor.name=Makefile Editor
 
+PropertyScannerConfig.name=Project Scanner Configuration Discovery
+PreferenceScannerConfig.name=Scanner Configuration Discovery
Index: plugin.xml
===================================================================
retrieving revision 1.26
diff -u -r1.26 plugin.xml
--- plugin.xml	2 Feb 2004 20:04:46 -0000	1.26
+++ plugin.xml	18 Feb 2004 21:47:24 -0000
@@ -399,5 +399,28 @@
          </actionSet>
       </perspectiveExtension>
    </extension>
+   <extension
+         point="org.eclipse.ui.propertyPages">
+      <page
+            adaptable="true"
+            objectClass="org.eclipse.core.resources.IProject"
+            name="%PropertyScannerConfig.name"
+            class="org.eclipse.cdt.make.internal.ui.properties.ScannerConfigPropertyPage"
+            id="org.eclipse.cdt.make.ui.properties.ScannerConfigPropertyPage">
+         <filter
+               name="nature"
+               value="org.eclipse.cdt.make.core.makeNature">
+         </filter>
+      </page>
+   </extension>
+   <extension
+         point="org.eclipse.ui.preferencePages">
+      <page
+            name="%PreferenceScannerConfig.name"
+            category="org.eclipse.cdt.ui.preferences.CPluginPreferencePage"
+            class="org.eclipse.cdt.make.internal.ui.preferences.ScannerConfigPreferencePage"
+            id="org.eclipse.cdt.make.ui.preferences.ScannerConfigPreferencePage">
+      </page>
+   </extension>
 
 </plugin>
Index: src/org/eclipse/cdt/make/internal/ui/MakeResources.properties
===================================================================
retrieving revision 1.9
diff -u -r1.9 MakeResources.properties
--- src/org/eclipse/cdt/make/internal/ui/MakeResources.properties	13 Jan 2004 18:54:39 -0000	1.9
+++ src/org/eclipse/cdt/make/internal/ui/MakeResources.properties	18 Feb 2004 21:47:26 -0000
@@ -102,3 +102,11 @@
 LexicalSortingAction.tooltip.on=Do Not Sort
 LexicalSortingAction.tooltip.off=Sort
 
+# --- ScannerConfigPage ---
+ScannerConfigPage.label=Scanner Config
+ScannerConfigPage.desc=Scanner configuration discovery settings
+ScannerConfigPage.activate=Automate scanner configuration discovery
+
+ScannerConfigPage.specsCmd.group_label=Generate specs command
+ScannerConfigPage.specsCmd.use_default=Use default
+ScannerConfigPage.specsCmd.label=Generate specs command:
Index: src/org/eclipse/cdt/make/ui/dialogs/SettingsBlock.java
===================================================================
retrieving revision 1.4
diff -u -r1.4 SettingsBlock.java
--- src/org/eclipse/cdt/make/ui/dialogs/SettingsBlock.java	13 Jan 2004 18:54:39 -0000	1.4
+++ src/org/eclipse/cdt/make/ui/dialogs/SettingsBlock.java	18 Feb 2004 21:47:26 -0000
@@ -91,6 +91,7 @@
 		if (fBuildInfo.isStopOnError()) {
 			stopOnErrorButton.setSelection(true);
 		}
+		stopOnErrorButton.setEnabled(fBuildInfo.isDefaultBuildCmd());
 	}
 
 	protected void createBuildCmdControls(Composite parent) {
@@ -142,8 +143,6 @@
 		}
 		if (fBuildInfo.isDefaultBuildCmd()) {
 			buildCommand.setEnabled(false);
-		} else {
-			stopOnErrorButton.setEnabled(false);
 		}
 		defButton.setSelection(fBuildInfo.isDefaultBuildCmd());
 	}
Index: src/org/eclipse/cdt/make/ui/wizards/MakeProjectWizardOptionPage.java
===================================================================
retrieving revision 1.7
diff -u -r1.7 MakeProjectWizardOptionPage.java
--- src/org/eclipse/cdt/make/ui/wizards/MakeProjectWizardOptionPage.java	14 Oct 2003 20:59:08 -0000	1.7
+++ src/org/eclipse/cdt/make/ui/wizards/MakeProjectWizardOptionPage.java	18 Feb 2004 21:47:26 -0000
@@ -5,8 +5,9 @@
  * All Rights Reserved.
  */
 
+import org.eclipse.cdt.make.core.MakeCorePlugin;
 import org.eclipse.cdt.make.internal.ui.MakeProjectOptionBlock;
-import org.eclipse.cdt.make.internal.ui.MakeUIPlugin;
+import org.eclipse.cdt.make.ui.dialogs.ScannerConfigPage;
 import org.eclipse.cdt.ui.dialogs.ICOptionContainer;
 import org.eclipse.cdt.ui.dialogs.ReferenceBlock;
 import org.eclipse.cdt.ui.dialogs.TabFolderOptionBlock;
@@ -40,6 +41,7 @@
 		protected void addTabs() {
 			addTab(new ReferenceBlock());
 			super.addTabs();
+			addTab(new ScannerConfigPage());
 		}
 	}
 
@@ -61,7 +63,7 @@
 	 * @see org.eclipse.cdt.ui.dialogs.ICOptionContainer#getPreference()
 	 */
 	public Preferences getPreferences() {
-		return MakeUIPlugin.getDefault().getPluginPreferences();
+		return MakeCorePlugin.getDefault().getPluginPreferences();
 	}
 
 }
Index: src/org/eclipse/cdt/make/internal/ui/preferences/ScannerConfigPreferencePage.java
===================================================================
RCS file: src/org/eclipse/cdt/make/internal/ui/preferences/ScannerConfigPreferencePage.java
diff -N src/org/eclipse/cdt/make/internal/ui/preferences/ScannerConfigPreferencePage.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/make/internal/ui/preferences/ScannerConfigPreferencePage.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,91 @@
+/**********************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors: 
+ * IBM - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.cdt.make.internal.ui.preferences;
+
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.cdt.ui.dialogs.ICOptionContainer;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.cdt.make.core.MakeCorePlugin;
+import org.eclipse.cdt.make.ui.dialogs.ScannerConfigPage;
+
+/**
+ * TODO: Provide description for "ScannerConfigPreferencePage".
+ * @see PreferencePage
+ */
+public class ScannerConfigPreferencePage extends PreferencePage implements IWorkbenchPreferencePage, ICOptionContainer {
+
+	private ScannerConfigPage fScannerConfigPage;
+	
+	public ScannerConfigPreferencePage() {
+		super();
+	}
+
+	/**
+	 * @see PreferencePage#init
+	 */
+	public void init(IWorkbench workbench)  {
+	}
+
+	/**
+	 * @see PreferencePage#createContents
+	 */
+	protected Control createContents(Composite parent)  {
+		fScannerConfigPage = new ScannerConfigPage(true);	// add title
+		// must set container before call to createControl
+		fScannerConfigPage.setContainer(this);
+		
+		fScannerConfigPage.createControl(parent);
+		return fScannerConfigPage.getControl();
+	}
+
+	protected void performDefaults() {
+		fScannerConfigPage.performDefaults();
+		super.performDefaults();
+	}
+	
+	public boolean performOk() {
+		try {
+			fScannerConfigPage.performApply(null);
+			MakeCorePlugin.getDefault().savePluginPreferences();
+			return true;
+		} 
+		catch (CoreException e) {
+			return false;
+		}
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.ui.dialogs.ICOptionContainer#updateContainer()
+	 */
+	public void updateContainer() {
+		setErrorMessage(fScannerConfigPage.getErrorMessage());
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.ui.dialogs.ICOptionContainer#getProject()
+	 */
+	public IProject getProject() {
+		return null;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.ui.dialogs.ICOptionContainer#getPreferences()
+	 */
+	public Preferences getPreferences() {
+		return MakeCorePlugin.getDefault().getPluginPreferences();
+	}
+}
Index: src/org/eclipse/cdt/make/internal/ui/properties/ScannerConfigPropertyPage.java
===================================================================
RCS file: src/org/eclipse/cdt/make/internal/ui/properties/ScannerConfigPropertyPage.java
diff -N src/org/eclipse/cdt/make/internal/ui/properties/ScannerConfigPropertyPage.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/make/internal/ui/properties/ScannerConfigPropertyPage.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,79 @@
+/**********************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors: 
+ * IBM - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.cdt.make.internal.ui.properties;
+
+import org.eclipse.cdt.ui.dialogs.ICOptionContainer;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.dialogs.PropertyPage;
+import org.eclipse.cdt.make.core.MakeCorePlugin;
+import org.eclipse.cdt.make.ui.dialogs.ScannerConfigPage;
+
+public class ScannerConfigPropertyPage extends PropertyPage implements ICOptionContainer {
+
+	private ScannerConfigPage fScannerConfigPage;
+
+	public ScannerConfigPropertyPage() {
+		super();
+	}
+
+	/**
+	 * @see PreferencePage#createContents(Composite)
+	 */
+	protected Control createContents(Composite parent) {
+		fScannerConfigPage = new ScannerConfigPage(true);	// add title
+		// must set container before call to createControl
+		fScannerConfigPage.setContainer(this);
+		
+		fScannerConfigPage.createControl(parent);
+		return fScannerConfigPage.getControl();
+	}
+
+	protected void performDefaults() {
+		fScannerConfigPage.performDefaults();
+		super.performDefaults();
+	}
+	
+	public boolean performOk() {
+		try {
+			fScannerConfigPage.performApply(null);
+			return true;
+		}
+		catch (CoreException e) {
+			return false;
+		}
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.ui.dialogs.ICOptionContainer#updateContainer()
+	 */
+	public void updateContainer() {
+		setErrorMessage(fScannerConfigPage.getErrorMessage());
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.ui.dialogs.ICOptionContainer#getProject()
+	 */
+	public IProject getProject() {
+		return (IProject) getElement();
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.ui.dialogs.ICOptionContainer#getPreferences()
+	 */
+	public Preferences getPreferences() {
+		return MakeCorePlugin.getDefault().getPluginPreferences();
+	}
+
+}
Index: src/org/eclipse/cdt/make/ui/dialogs/ScannerConfigPage.java
===================================================================
RCS file: src/org/eclipse/cdt/make/ui/dialogs/ScannerConfigPage.java
diff -N src/org/eclipse/cdt/make/ui/dialogs/ScannerConfigPage.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/make/ui/dialogs/ScannerConfigPage.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,277 @@
+/**********************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors: 
+ * IBM - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.cdt.make.ui.dialogs;
+
+import org.eclipse.cdt.ui.dialogs.AbstractCOptionPage;
+import org.eclipse.cdt.ui.dialogs.ICOptionContainer;
+import org.eclipse.cdt.utils.ui.controls.ControlFactory;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.cdt.make.core.MakeCorePlugin;
+import org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo;
+import org.eclipse.cdt.make.core.scannerconfig.ScannerConfigBuilder;
+import org.eclipse.cdt.make.core.scannerconfig.ScannerConfigNature;
+import org.eclipse.cdt.make.internal.ui.MakeUIPlugin;
+
+/**
+ *
+ * @author vhirsl
+ */
+public class ScannerConfigPage extends AbstractCOptionPage {
+	private static final String PREFIX = "ScannerConfigPage";	//$NON-NLS-1$
+	private static final String LABEL = PREFIX + ".label";	//$NON-NLS-1$
+	private static final String DESC = PREFIX + ".desc";	//$NON-NLS-1$
+	private static final String ACTIVATE_AUTO_DISCOVERY = PREFIX + ".activate"; //$NON-NLS-1$
+	private static final String SPECS_CMD_GROUP = PREFIX + ".specsCmd.group_label"; //$NON-NLS-1$
+	private static final String SPECS_CMD_USE_DEFAULT = PREFIX + ".specsCmd.use_default"; //$NON-NLS-1$
+	private static final String SPECS_CMD_LABEL = PREFIX + ".specsCmd.label"; //$NON-NLS-1$
+
+	
+	private boolean addTitle = false;
+
+	private Button autoDiscovery;
+
+	Button defButton;
+	Text specsCommand;
+	
+	IScannerConfigBuilderInfo fBuildInfo;
+	
+	/**
+	 * Default constructor
+	 */
+	public ScannerConfigPage() {
+		super(MakeUIPlugin.getResourceString(LABEL));
+		setDescription(MakeUIPlugin.getResourceString(DESC));
+	}
+
+	/**
+	 * @param addTitle
+	 */
+	public ScannerConfigPage(boolean addTitle) {
+		this();
+		this.addTitle = addTitle;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.ui.dialogs.ICOptionPage#setContainer(org.eclipse.cdt.ui.dialogs.ICOptionContainer)
+	 */
+	public void setContainer(ICOptionContainer container) {
+		super.setContainer(container);
+		IProject project = container.getProject();
+		if (project != null) {
+			try {
+				fBuildInfo = MakeCorePlugin.createScannerConfigBuildInfo(project, ScannerConfigBuilder.BUILDER_ID);
+			}
+			catch (CoreException e) {
+				fBuildInfo = MakeCorePlugin.createScannerConfigBuildInfo(container.getPreferences(), ScannerConfigBuilder.BUILDER_ID, true);
+			}
+		}
+		else {
+			fBuildInfo = MakeCorePlugin.createScannerConfigBuildInfo(container.getPreferences(), ScannerConfigBuilder.BUILDER_ID, false);
+		}
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt..dialogs.ICOptionPage#performApply(org.eclipse.core.runtime.IProgressMonitor)
+	 */
+	public void performApply(IProgressMonitor monitor) throws CoreException {
+		// install/deinstall the scanner configuration builder
+		IProject project = getContainer().getProject();
+		IScannerConfigBuilderInfo buildInfo;
+		if (project != null) {
+			if (autoDiscovery.getSelection()) {
+				ScannerConfigNature.addScannerConfigNature(project);
+				buildInfo = MakeCorePlugin.createScannerConfigBuildInfo(project, ScannerConfigBuilder.BUILDER_ID);
+				buildInfo.setAutoDiscoveryEnabled(autoDiscovery.getSelection());
+			}
+			else {
+				ScannerConfigNature.removeScannerConfigNature(project);
+				return;
+			}
+		}
+		else {
+			buildInfo = MakeCorePlugin.createScannerConfigBuildInfo(getContainer().getPreferences(), ScannerConfigBuilder.BUILDER_ID, false);
+			buildInfo.setAutoDiscoveryEnabled(autoDiscovery.getSelection());
+		}
+		buildInfo.setUseDefaultSpecsCmd(useDefaultSpecsCmd());
+		if (!useDefaultSpecsCmd()) {
+			String specsLine = getSpecsCommandLine();
+			int start = 0;
+			int end = -1;
+			if (specsLine.startsWith("\"")) { //$NON-NLS-1$
+				start = 1;
+				end = specsLine.indexOf('"', 1);
+			}
+			else {
+				end = specsLine.indexOf(' ');
+			}
+			IPath path;
+			if (end == -1) {
+				path = new Path(specsLine);
+			} else {
+				path = new Path(specsLine.substring(start, end));
+			}
+			buildInfo.setSpecsCommand(path);
+			String args = ""; //$NON-NLS-1$
+			if (end != -1) {
+				args = specsLine.substring(end + 1);
+			}
+			buildInfo.setSpecsArguments(args);
+		}
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.cdt.ui.dialogs.ICOptionPage#performDefaults()
+	 */
+	public void performDefaults() {
+		IScannerConfigBuilderInfo buildInfo;
+		// Populate with the default value
+		if (getContainer().getProject() != null) {
+			// get the preferences
+			buildInfo = MakeCorePlugin.createScannerConfigBuildInfo(getContainer().getPreferences(),
+					ScannerConfigBuilder.BUILDER_ID, false);
+		}
+		else {
+			// get the defaults
+			buildInfo = MakeCorePlugin.createScannerConfigBuildInfo(getContainer().getPreferences(),
+					ScannerConfigBuilder.BUILDER_ID, true);
+		}
+		autoDiscovery.setSelection(buildInfo.isAutoDiscoveryEnabled());
+		IPath sCommand = fBuildInfo.getSpecsCommand();
+		if (sCommand != null) {
+			StringBuffer cmd = new StringBuffer(sCommand.toOSString());
+			String args = buildInfo.getSpecsArguments();
+			if (args != null && !args.equals("")) { //$NON-NLS-1$
+				cmd.append(' ');
+				cmd.append(args);
+			}
+			specsCommand.setText(cmd.toString());
+		}
+		if (buildInfo.isDefaultSpecsCmd()) {
+			specsCommand.setEnabled(false);
+		} else {
+			specsCommand.setEnabled(true);
+		}
+		defButton.setSelection(buildInfo.isDefaultSpecsCmd());
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
+	 */
+	public void createControl(Composite parent) {
+		Composite composite = ControlFactory.createComposite(parent, 1);
+		setControl(composite);
+
+		if (addTitle) {
+			addTitle(composite);
+		}
+		addSCDiscoveryState(composite);
+//		addSeparator(composite);
+		createSpecsCmdControls(composite);
+	}
+
+	private void addTitle(Composite composite) {
+		//Label for dialog title
+		Label pathLabel = ControlFactory.createLabel(composite, MakeUIPlugin.getResourceString(DESC));
+	}
+	
+	private void addSCDiscoveryState(Composite parent) {
+		//Checkbox for enabling the discovery
+		ControlFactory.insertSpace(parent, 1, 10);
+		autoDiscovery = ControlFactory.createCheckBox(parent, MakeUIPlugin.getResourceString(ACTIVATE_AUTO_DISCOVERY));
+		autoDiscovery.setSelection(fBuildInfo.isAutoDiscoveryEnabled());
+	}
+
+	private void addSeparator(Composite parent) {
+		Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
+		GridData gridData = new GridData();
+		gridData.horizontalAlignment = GridData.FILL;
+		gridData.grabExcessHorizontalSpace = true;
+		separator.setLayoutData(gridData);
+	}
+
+	private void createSpecsCmdControls(Composite parent) {
+		Group group = ControlFactory.createGroup(parent, MakeUIPlugin.getResourceString(SPECS_CMD_GROUP), 1);
+		defButton = ControlFactory.createCheckBox(group, MakeUIPlugin.getResourceString(SPECS_CMD_USE_DEFAULT));
+		defButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(SelectionEvent e) {
+				if (useDefaultSpecsCmd() == true) {
+					specsCommand.setEnabled(false);
+				} else {
+					specsCommand.setEnabled(true);
+				}
+				getContainer().updateContainer();
+			}
+		});
+		((GridData) (defButton.getLayoutData())).horizontalAlignment = GridData.FILL_HORIZONTAL;
+		((GridData) (defButton.getLayoutData())).horizontalSpan = 2;
+		Label label = ControlFactory.createLabel(group, MakeUIPlugin.getResourceString(SPECS_CMD_LABEL));
+		((GridData) (label.getLayoutData())).horizontalAlignment = GridData.BEGINNING;
+		((GridData) (label.getLayoutData())).grabExcessHorizontalSpace = false;
+		specsCommand = ControlFactory.createTextField(group, SWT.SINGLE | SWT.BORDER);
+		((GridData) (specsCommand.getLayoutData())).horizontalAlignment = GridData.FILL;
+		((GridData) (specsCommand.getLayoutData())).grabExcessHorizontalSpace = true;
+		specsCommand.addListener(SWT.Modify, new Listener() {
+			public void handleEvent(Event e) {
+				getContainer().updateContainer();
+			}
+		});
+		IPath sCommand = fBuildInfo.getSpecsCommand();
+		if (sCommand != null) {
+			StringBuffer cmd = new StringBuffer(sCommand.toOSString());
+			String args = fBuildInfo.getSpecsArguments();
+			if (args != null && !args.equals("")) { //$NON-NLS-1$
+				cmd.append(' ');
+				cmd.append(args);
+			}
+			specsCommand.setText(cmd.toString());
+		}
+		if (fBuildInfo.isDefaultSpecsCmd()) {
+			specsCommand.setEnabled(false);
+		}
+		defButton.setSelection(fBuildInfo.isDefaultSpecsCmd());
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jface.dialogs.IDialogPage#getErrorMessage()
+	 */
+	public String getErrorMessage() {
+		if (!useDefaultSpecsCmd()) {
+			String cmd = getSpecsCommandLine();
+			if (cmd == null || cmd.length() == 0) {
+				return "Must enter a 'specs' command";	//$NON-NLS-1$
+			}
+		}
+		return null;
+	}
+
+	private boolean useDefaultSpecsCmd() {
+		return defButton.getSelection();
+	}
+
+	private String getSpecsCommandLine() {
+		return specsCommand.getText().trim();
+	}
+}

Back to the top