/******************************************************************************* * Copyright (c) 2004, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM - Initial API and implementation * Markus Schorn (Wind River Systems) * Gerhard Schaber (Wind River Systems) *******************************************************************************/ package org.eclipse.cdt.make.internal.core.scannerconfig.util; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.eclipse.cdt.internal.core.SafeStringInterner; import org.eclipse.cdt.internal.core.resources.ResourceLookup; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; /** * Class that represents a compiler command and related scanner configuration * * @author vhirsl */ public class CCommandDSC { protected final static String SINGLE_SPACE = " "; //$NON-NLS-1$ protected final static String CMD_DESCRIPTION_ELEM = "commandDescription"; //$NON-NLS-1$ protected final static String CMD_SI_ELEM = "commandScannerInfo"; //$NON-NLS-1$ protected final static String OPTION_ELEM = "option"; //$NON-NLS-1$ protected final static String SI_ITEM_ELEM = "siItem"; //$NON-NLS-1$ protected final static String KEY_ATTR = "key"; //$NON-NLS-1$ protected final static String VALUE_ATTR = "value"; //$NON-NLS-1$ protected final static String QUOTE_INCLUDE_ATTR = "quote"; //$NON-NLS-1$ protected final static String KIND_ATTR = "kind"; //$NON-NLS-1$ protected int commandId; protected List<KVStringPair> compilerCommand; // members are KVStringPair objects protected boolean discovered; protected boolean cppFileType; // C or C++ file type protected IProject project; protected List<String> symbols; protected List<String> includes; protected List<String> quoteIncludes; public CCommandDSC(boolean cppFileType) { this(cppFileType, null); } public CCommandDSC(boolean cppFileType, IProject project) { compilerCommand = new ArrayList<KVStringPair>(); discovered = false; this.cppFileType = cppFileType; symbols = new ArrayList<String>(); includes = new ArrayList<String>(); quoteIncludes = new ArrayList<String>(); this.project = project; } public boolean appliesToCPPFileType() { return cppFileType; } public void addSCOption(KVStringPair option) { if (project != null && (option.getKey().equals(SCDOptionsEnum.INCLUDE_FILE.toString()) || option.getKey().equals(SCDOptionsEnum.INCLUDE.toString()) || option.getKey().equals(SCDOptionsEnum.ISYSTEM.toString()) || option.getKey().equals(SCDOptionsEnum.IMACROS_FILE.toString()) || option.getKey().equals(SCDOptionsEnum.IQUOTE.toString()))) { String value = option.getValue(); value = CygpathTranslator.translateIncludePaths(project, Collections.singletonList(value)).get(0); value = SafeStringInterner.safeIntern(makeRelative(project, new Path(value)).toOSString()); option = new KVStringPair(option.getKey(), value); } compilerCommand.add(option); } public Integer getCommandIdAsInteger() { return new Integer(getCommandId()); } /** * @return Returns the commandId. */ public int getCommandId() { return commandId; } /** * @param commandId The commandId to set. */ public void setCommandId(int commandId) { this.commandId = commandId; } @Override public String toString() { String commandAsString = new String(); for (Iterator<KVStringPair> i = compilerCommand.iterator(); i.hasNext(); ) { KVStringPair optionPair = i.next(); String value = optionPair.getValue(); commandAsString += optionPair.getKey() + SINGLE_SPACE + value + SINGLE_SPACE; } return commandAsString.trim(); } public int getId() { return commandId; } /** * Returns a command where -imacros and -include options have been removed * @param quoteIncludePaths whether or not paths for includes must be put inside double quotes. * @return the command line to run the scanner discovery. */ public String getSCDRunnableCommand(boolean quoteIncludePaths, boolean quoteDefines) { String commandAsString = new String(); for (Iterator<KVStringPair> i = compilerCommand.iterator(); i.hasNext(); ) { KVStringPair optionPair = i.next(); if (optionPair.getKey().equals(SCDOptionsEnum.COMMAND.toString())) { commandAsString += optionPair.getValue() + SINGLE_SPACE; } else { // skip -include and -imacros options if (optionPair.getKey().equals(SCDOptionsEnum.IMACROS_FILE.toString()) || optionPair.getKey().equals(SCDOptionsEnum.INCLUDE_FILE.toString())) continue; String value = optionPair.getValue(); if (optionPair.getKey().equals(SCDOptionsEnum.INCLUDE.toString()) || optionPair.getKey().equals(SCDOptionsEnum.ISYSTEM.toString()) || optionPair.getKey().equals(SCDOptionsEnum.IQUOTE.toString())) { value = makeAbsolute(project, value); if (quoteIncludePaths) { value= "\"" + value + "\""; //$NON-NLS-1$ //$NON-NLS-2$ } } else if (quoteDefines && optionPair.getKey().equals(SCDOptionsEnum.DEFINE.toString())) { if (value.indexOf('\'') == -1) { value= "'" + value + "'"; //$NON-NLS-1$//$NON-NLS-2$ } else { value= value.replaceAll("\"", "\\\\\""); //$NON-NLS-1$//$NON-NLS-2$ value= "\"" + value + "\""; //$NON-NLS-1$ //$NON-NLS-2$ } } commandAsString += optionPair.getKey() + SINGLE_SPACE + value + SINGLE_SPACE; } } return commandAsString.trim(); } /** * @return the compiler command */ public String getCompilerName() { String compiler = new String(); for (Iterator<KVStringPair> i = compilerCommand.iterator(); i.hasNext(); ) { KVStringPair optionPair = i.next(); if (optionPair.getKey().equals(SCDOptionsEnum.COMMAND.toString())) { compiler = optionPair.getValue(); break; } } return compiler.trim(); } /** * @return list of strings */ public List<String> getImacrosFile() { List<String> imacrosFiles = new ArrayList<String>(); for (Iterator<KVStringPair> i = compilerCommand.iterator(); i.hasNext(); ) { KVStringPair optionPair = i.next(); if (optionPair.getKey().equals(SCDOptionsEnum.IMACROS_FILE.toString())) { imacrosFiles.add(makeAbsolute(project,optionPair.getValue())); } } return imacrosFiles; } /** * @return list of strings */ public List<String> getIncludeFile() { List<String> includeFiles = new ArrayList<String>(); for (Iterator<KVStringPair> i = compilerCommand.iterator(); i.hasNext(); ) { KVStringPair optionPair = i.next(); if (optionPair.getKey().equals(SCDOptionsEnum.INCLUDE_FILE.toString())) { includeFiles.add(makeAbsolute(project,optionPair.getValue())); } } return includeFiles; } // public List getFilesList() { // return files; // } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object arg0) { if (arg0 != null && arg0.getClass().equals(this.getClass())) { CCommandDSC other = (CCommandDSC)arg0; return (compilerCommand.equals(other.compilerCommand) && cppFileType == other.cppFileType); } return false; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return compilerCommand.hashCode(); } /** * @return Returns the includes as strings. */ public List<String> getIncludes() { return makeAbsolute(project, includes); } /** * @param includes The includes to set. */ public void setIncludes(List<String> includes) { this.includes = includes; } /** * @return Returns the quote include paths as strings (for #include "...") */ public List<String> getQuoteIncludes() { return makeAbsolute(project, quoteIncludes); } /** * @param includes - quote include paths (for #include "...") */ public void setQuoteIncludes(List<String> includes) { quoteIncludes = includes; } /** * @return Returns the symbols. */ public List<String> getSymbols() { return symbols; } /** * @param symbols The symbols to set. */ public void setSymbols(List<String> symbols) { this.symbols = symbols; } /** * @return Returns the discovered. */ public boolean isDiscovered() { return discovered; } /** * @param discovered The discovered to set. */ public void setDiscovered(boolean discovered) { this.discovered = discovered; } public void serialize(Element cmdElem) { Document doc = cmdElem.getOwnerDocument(); // serialize the command Element cmdDescElem = doc.createElement(CMD_DESCRIPTION_ELEM); for (Iterator<KVStringPair> i = compilerCommand.iterator(); i.hasNext(); ) { Element optionElem = doc.createElement(OPTION_ELEM); KVStringPair option = i.next(); optionElem.setAttribute(KEY_ATTR, option.getKey()); optionElem.setAttribute(VALUE_ATTR, option.getValue()); cmdDescElem.appendChild(optionElem); } cmdElem.appendChild(cmdDescElem); // serialize includes and symbols Element siElem = doc.createElement(CMD_SI_ELEM); for (Iterator<String> j = quoteIncludes.iterator(); j.hasNext(); ) { Element siItem = doc.createElement(SI_ITEM_ELEM); siItem.setAttribute(KIND_ATTR, "INCLUDE_PATH"); //$NON-NLS-1$ siItem.setAttribute(VALUE_ATTR, j.next()); siItem.setAttribute(QUOTE_INCLUDE_ATTR, "true"); //$NON-NLS-1$ siElem.appendChild(siItem); } for (Iterator<String> j = includes.iterator(); j.hasNext(); ) { Element siItem = doc.createElement(SI_ITEM_ELEM); siItem.setAttribute(KIND_ATTR, "INCLUDE_PATH"); //$NON-NLS-1$ siItem.setAttribute(VALUE_ATTR, j.next()); siElem.appendChild(siItem); } for (Iterator<String> j = symbols.iterator(); j.hasNext(); ) { Element siItem = doc.createElement(SI_ITEM_ELEM); siItem.setAttribute(KIND_ATTR, "SYMBOL_DEFINITION"); //$NON-NLS-1$ siItem.setAttribute(VALUE_ATTR, j.next()); siElem.appendChild(siItem); } cmdElem.appendChild(siElem); } public void deserialize(Element cmdElem) { // read command options NodeList descList = cmdElem.getElementsByTagName(CMD_DESCRIPTION_ELEM); if (descList.getLength() > 0) { Element descElem = (Element) descList.item(0); NodeList optionList = descElem.getElementsByTagName(OPTION_ELEM); for (int i = 0; i < optionList.getLength(); ++i) { Element optionElem = (Element) optionList.item(i); String key = SafeStringInterner.safeIntern(optionElem.getAttribute(KEY_ATTR)); String value = SafeStringInterner.safeIntern(optionElem.getAttribute(VALUE_ATTR)); KVStringPair option = new KVStringPair(key, value); addSCOption(option); } } // read associated scanner info NodeList siList = cmdElem.getElementsByTagName(CMD_SI_ELEM); if (siList.getLength() > 0) { Element siElem = (Element) siList.item(0); NodeList siItemList = siElem.getElementsByTagName(SI_ITEM_ELEM); for (int i = 0; i < siItemList.getLength(); ++i) { Element siItemElem = (Element) siItemList.item(i); String kind = siItemElem.getAttribute(KIND_ATTR); String value = siItemElem.getAttribute(VALUE_ATTR); String quote = siItemElem.getAttribute(QUOTE_INCLUDE_ATTR); if (kind.equals("INCLUDE_PATH")) { //$NON-NLS-1$ if (quote.equals("true")) { //$NON-NLS-1$ quoteIncludes.add(SafeStringInterner.safeIntern(value)); } else { includes.add(value); } } else if (kind.equals("SYMBOL_DEFINITION")) { //$NON-NLS-1$ symbols.add(SafeStringInterner.safeIntern(value)); } } setDiscovered(true); } } public void resolveOptions(IProject project) { if (!isDiscovered()) { // that's wrong for sure, options cannot be resolved fron the optionPairs?? ArrayList<String> symbols = new ArrayList<String>(); ArrayList<String> includes = new ArrayList<String>(); ArrayList<String> quoteincludes = new ArrayList<String>(); for (Iterator<KVStringPair> options = compilerCommand.iterator(); options.hasNext(); ) { KVStringPair optionPair = options.next(); String key = optionPair.getKey(); String value = optionPair.getValue(); if (key.equals(SCDOptionsEnum.INCLUDE.toString()) || key.equals(SCDOptionsEnum.ISYSTEM.toString())) { includes.add(SafeStringInterner.safeIntern(value)); } else if (key.equals(SCDOptionsEnum.IQUOTE.toString())) { quoteincludes.add(SafeStringInterner.safeIntern(value)); } else if (key.equals(SCDOptionsEnum.DEFINE.toString())) { symbols.add(SafeStringInterner.safeIntern(value)); } } setIncludes(includes); setQuoteIncludes(quoteincludes); setSymbols(symbols); } setDiscovered(true); } public static IPath makeRelative(IProject project, IPath path) { IResource resource = findResource(project, path); if (resource != null) { if (resource.getProject() == project) { path = resource.getProjectRelativePath(); } // else { // path = resource.getFullPath(); // } } return path; } protected static IResource findResource(IProject project, IPath path) { IResource resource = project.findMember(path, false); if (resource == null) { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); resource = root.findMember(path, false); if (resource == null) { resource= ResourceLookup.selectFileForLocation(path, project); } } return resource; } public static List<String> makeRelative(IProject project, List<String> paths) { List<String> list = new ArrayList<String>(paths.size()); for (Iterator<String> iter=paths.iterator(); iter.hasNext(); ) { String path = iter.next(); path = makeRelative(project, new Path(path)).toOSString(); list.add(SafeStringInterner.safeIntern(path)); } return list; } public static final String makeAbsolute(IProject project, String path) { IPath ppath = new Path(path); if (project != null && !ppath.isAbsolute()) { IResource res = project.findMember(ppath); if (res == null) { // To calculate path only; this does not create any file res = project.getFile(path); } if (res != null) { ppath = res.getLocation(); if (ppath != null) { path = ppath.toOSString(); } } // path = new File(project.getLocation().toOSString(), path).getAbsolutePath(); } return SafeStringInterner.safeIntern(path); } public static List<String> makeAbsolute(IProject project, List<String> paths) { List<String> list = new ArrayList<String>(paths.size()); for (Iterator<String> iter=paths.iterator(); iter.hasNext(); ) { String path = iter.next(); path = makeAbsolute(project, path); list.add(SafeStringInterner.safeIntern(path)); } return list; } }