/******************************************************************************* * Copyright (c) 2007, 2009 Intel 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: * Intel Corporation - Initial API and implementation * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.managedbuilder.internal.dataprovider; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.eclipse.cdt.core.cdtvariables.CdtVariableException; import org.eclipse.cdt.core.settings.model.CMacroEntry; import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; import org.eclipse.cdt.core.settings.model.ICLanguageSettingPathEntry; import org.eclipse.cdt.core.settings.model.ICLibraryFileEntry; import org.eclipse.cdt.core.settings.model.ICSettingEntry; import org.eclipse.cdt.core.settings.model.util.AbstractEntryStorage; import org.eclipse.cdt.core.settings.model.util.CDataUtil; import org.eclipse.cdt.core.settings.model.util.SettingsSet; import org.eclipse.cdt.core.settings.model.util.SettingsSet.EntryInfo; import org.eclipse.cdt.core.settings.model.util.SettingsSet.SettingLevel; import org.eclipse.cdt.managedbuilder.core.BuildException; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.IEnvVarBuildPath; import org.eclipse.cdt.managedbuilder.core.IOption; import org.eclipse.cdt.managedbuilder.core.IOptionPathConverter; import org.eclipse.cdt.managedbuilder.core.IResourceInfo; import org.eclipse.cdt.managedbuilder.core.IReverseOptionPathConverter; import org.eclipse.cdt.managedbuilder.core.ITool; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; import org.eclipse.cdt.managedbuilder.core.OptionStringValue; import org.eclipse.cdt.managedbuilder.envvar.IEnvironmentVariableProvider; import org.eclipse.cdt.managedbuilder.internal.core.Option; import org.eclipse.cdt.managedbuilder.internal.macros.DefaultMacroContextInfo; import org.eclipse.cdt.managedbuilder.internal.macros.OptionContextData; import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; import org.eclipse.cdt.utils.cdtvariables.CdtVariableResolver; import org.eclipse.cdt.utils.cdtvariables.SupplierBasedCdtVariableSubstitutor; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; /** * BuildEntryStorage has a handle back to the BuildLanguageData * to allow checking on which language entries are actually defined. */ public class BuildEntryStorage extends AbstractEntryStorage { private static final int USER_ENTRIES_LEVEL = 0; private static final int ENV_ENTRIES_LEVEL = 1; private static final int DISCOVERY_ENTRIES_LEVEL = 2; private BuildLanguageData fLangData; private String fBuildDirName; private static class UserEntryInfo { private ICLanguageSettingEntry fEntry; private OptionStringValue fOriginalValue; private OptionStringValue fBsResolvedValue; private List<UserEntryInfo> fSequense; UserEntryInfo(ICLanguageSettingEntry entry, OptionStringValue originalValue, OptionStringValue bsResolvedValue, List<UserEntryInfo> sequense) { fEntry = entry; fOriginalValue = originalValue; fBsResolvedValue = bsResolvedValue; fSequense = sequense; if (sequense != null) sequense.add(this); } } private static class EmptyEntryInfo { private OptionStringValue fOriginalValue; private int fPosition; EmptyEntryInfo(OptionStringValue value, int position) { fOriginalValue = value; fPosition = position; } } public BuildEntryStorage(int kind, BuildLanguageData lData) { super(kind); fLangData = lData; } @Override protected SettingsSet createEmptySettings() { SettingsSet settings = new SettingsSet(3); SettingLevel levels[] = settings.getLevels(); boolean override = isDiscoveredEntriesOverridable(); int readOnlyFlag = override ? 0 : ICSettingEntry.READONLY; levels[USER_ENTRIES_LEVEL].setFlagsToClear(ICSettingEntry.READONLY | ICSettingEntry.BUILTIN); levels[USER_ENTRIES_LEVEL].setFlagsToSet(0); levels[USER_ENTRIES_LEVEL].setReadOnly(false); levels[USER_ENTRIES_LEVEL].setOverrideSupported(override); levels[ENV_ENTRIES_LEVEL].setFlagsToClear(ICSettingEntry.BUILTIN); levels[ENV_ENTRIES_LEVEL].setFlagsToSet(readOnlyFlag | ICSettingEntry.RESOLVED); levels[ENV_ENTRIES_LEVEL].setReadOnly(true); levels[ENV_ENTRIES_LEVEL].setOverrideSupported(false); levels[DISCOVERY_ENTRIES_LEVEL].setFlagsToClear(0); levels[DISCOVERY_ENTRIES_LEVEL].setFlagsToSet(readOnlyFlag | ICSettingEntry.BUILTIN | ICSettingEntry.RESOLVED); levels[DISCOVERY_ENTRIES_LEVEL].setReadOnly(true); levels[DISCOVERY_ENTRIES_LEVEL].setOverrideSupported(false); return settings; } private boolean isDiscoveredEntriesOverridable() { return fLangData.getUndefOptionsForKind(getKind()).length != 0; } private String getBuildDitName() { if (fBuildDirName == null) { fBuildDirName = fLangData.getConfiguration().getName(); } return fBuildDirName; } @Override protected void obtainEntriesFromLevel(int levelNum, SettingLevel level) { switch (levelNum) { case USER_ENTRIES_LEVEL: if (level == null) { restoreDefaults(); } else { EntryInfo infos[] = level.getInfos(); UserEntryInfo[] userInfos = new UserEntryInfo[infos.length]; for (int i = 0; i < infos.length; i++) { UserEntryInfo uei = (UserEntryInfo)infos[i].getCustomInfo(); if (uei == null) uei = new UserEntryInfo(infos[i].getEntry(), null, null, null); userInfos[i] = uei; } @SuppressWarnings("unchecked") List<EmptyEntryInfo> context = (List<EmptyEntryInfo>)level.getContext(); setUserEntries(userInfos, context); setUserUndefinedStringSet(level.containsOverrideInfo() ? level.getOverrideSet() : null); } break; } } private void restoreDefaults() { ITool tool = fLangData.getTool(); for (IOption option : fLangData.getOptionsForKind(getKind())) { if (option.getParent() == tool) { tool.removeOption(option); } } for (IOption option : fLangData.getUndefOptionsForKind(getKind())) { if (option.getParent() == tool) { tool.removeOption(option); } } } @Override protected void putEntriesToLevel(int levelNum, SettingLevel level) { switch (levelNum) { case USER_ENTRIES_LEVEL: List<EmptyEntryInfo> emptyEntryInfos = new ArrayList<EmptyEntryInfo>(); for (UserEntryInfo userEntry : getUserEntries(level.getFlags(0), true, emptyEntryInfos)) { level.addEntry(userEntry.fEntry, userEntry); } level.addOverrideNameSet(getUserUndefinedStringSet()); if (emptyEntryInfos.size() != 0) level.setContext(emptyEntryInfos); break; case ENV_ENTRIES_LEVEL: ICLanguageSettingEntry[] envEntries = getEnvEntries(level.getFlags(0)); level.addEntries(envEntries); break; case DISCOVERY_ENTRIES_LEVEL: ICLanguageSettingEntry[] discoveredEntries = getDiscoveredEntries(level.getFlags(0)); level.addEntries(discoveredEntries); break; } } /** * @return scanner discovered entries (level 2) */ private ICLanguageSettingEntry[] getDiscoveredEntries(int flags) { ICLanguageSettingEntry[] entries = ProfileInfoProvider.getInstance().getEntryValues(fLangData, getKind(), flags); if (entries == null || entries.length == 0) { UserEntryInfo[] infos = getUserEntries(flags, false, null); if (infos.length != 0) { entries = new ICLanguageSettingEntry[infos.length]; for (int i = 0; i < entries.length; i++) { entries[i] = infos[i].fEntry; } } } return entries; } private SupplierBasedCdtVariableSubstitutor createSubstitutor(IOption option, boolean bsVarsOnly) { OptionContextData ocd = new OptionContextData(option, fLangData.getTool()); DefaultMacroContextInfo ci = new DefaultMacroContextInfo(IBuildMacroProvider.CONTEXT_OPTION, ocd); return bsVarsOnly ? new BuildSystemSpecificVariableSubstitutor(ci) : new SupplierBasedCdtVariableSubstitutor(ci, "", " "); //$NON-NLS-1$ //$NON-NLS-2$ } /** * Return user entries (level 0) * * The UserEntryInfo[] is an array of all user entries from all the options * applicable to the language setting entry kind. * @param emptyValuesInfos list to which unresolved entries are added * @return UserEntryInfo[] (never null) */ private UserEntryInfo[] getUserEntries(int flags, boolean usr, List<EmptyEntryInfo> emptyValuesInfos) { IOption options[] = fLangData.getOptionsForKind(getKind()); if (options.length > 0) { List<UserEntryInfo> entryList = new ArrayList<UserEntryInfo>(); for (IOption opt : options) { Option option = (Option)opt; @SuppressWarnings("unchecked") List<OptionStringValue> list = usr ? (List<OptionStringValue>)option.getExactValue() : (List<OptionStringValue>)option.getExactBuiltinsList(); if (list != null) { SupplierBasedCdtVariableSubstitutor subst = createSubstitutor(option, false); SupplierBasedCdtVariableSubstitutor bSVarsSubst = createSubstitutor(option, true); for (int j = 0; j < list.size(); j++) { OptionStringValue ve = list.get(j); OptionStringValue[] rVes = resolve(ve, option, bSVarsSubst); if (rVes.length == 0) { // If not resolved, add EmptyEntryInfo based off the value entry if (emptyValuesInfos != null) { emptyValuesInfos.add(new EmptyEntryInfo(ve, j)); } } else { // If resolved, add each resolved entry as a separate UserEntryInfo boolean isMultiple = rVes.length > 1; List<UserEntryInfo> sequense = isMultiple ? new ArrayList<UserEntryInfo>(rVes.length) : null; for (OptionStringValue rVe : rVes) { ICLanguageSettingEntry entry = createUserEntry(option, rVe, flags, subst); entryList.add(new UserEntryInfo(entry, ve, rVe, sequense)); } } } } } return entryList.toArray(new UserEntryInfo[entryList.size()]); } return new UserEntryInfo[0]; } // private static OptionStringValue stripQuotes(OptionStringValue ov) { // String value = ov.getValue(); // value = stripQuotes(value, true); // if (value != null) { // value = value.substring(1, value.length() - 1); // ov = substituteValue(ov, value); // } // return ov; // } private static String stripQuotes(String value, boolean nullIfNone) { if (value.indexOf('"') == 0 && value.lastIndexOf('"') == value.length() - 1 && value.length() != 1) { return value.substring(1, value.length() - 1); } return nullIfNone ? null : value; } private static OptionStringValue substituteValue(OptionStringValue ov, String value) { return new OptionStringValue(value, ov.isBuiltIn(), ov.getSourceAttachmentPath(), ov.getSourceAttachmentRootPath(), ov.getSourceAttachmentPrefixMapping()); } private HashSet<String> getUserUndefinedStringSet() { HashSet<String> set = null; for (IOption option : fLangData.getUndefOptionsForKind(getKind())) { @SuppressWarnings("unchecked") List<String> list = (List<String>)option.getValue(); if (list.size() != 0) { if (set == null) set = new HashSet<String>(); set.addAll(list); } } return set; } /** * Makes non-absolute paths relative to the build directory */ private PathInfo fromBuildToProj(PathInfo info) { if (info.isAbsolute()) return info; Path path = new Path(info.getUnresolvedPath()); String projPath; if (path.segmentCount() != 0 && "..".equals(path.segment(0))) { //$NON-NLS-1$ projPath = path.removeFirstSegments(1).toString(); } else { StringBuffer buf = new StringBuffer(); buf.append(getBuildDitName()).append('/').append(info.getUnresolvedPath()); projPath = buf.toString(); } return new PathInfo(projPath, info.isWorkspacePath(), info.getSubstitutor()); } private PathInfo fromProjToBuild(PathInfo info) { if (info.isAbsolute()) return info; Path path = new Path(info.getUnresolvedPath()); String projPath; if (path.segmentCount() != 0 && getBuildDitName().equals(path.segment(0))) { projPath = path.removeFirstSegments(1).toString(); } else { StringBuffer buf = new StringBuffer(); buf.append("../").append(info.getUnresolvedPath()); //$NON-NLS-1$ projPath = buf.toString(); } return new PathInfo(projPath, info.isWorkspacePath(), info.getSubstitutor()); } // private String[] resolve(String v, IOption option, IPath[] buildLocation) { // } private String[] resolve(String v, IOption option, SupplierBasedCdtVariableSubstitutor sub) { try { return CdtVariableResolver.resolveToStringList(v, sub); } catch (CdtVariableException e) { ManagedBuilderCorePlugin.log(e); } return new String[0]; } private OptionStringValue[] resolve(OptionStringValue ov, IOption option, SupplierBasedCdtVariableSubstitutor sub) { String value = ov.getValue(); value = stripQuotes(value, false); String[] rValues = resolve(value, option, sub); OptionStringValue[] result = new OptionStringValue[rValues.length]; for (int i = 0; i < result.length; i++) { result[i] = substituteValue(ov, stripQuotes(rValues[i], false)); } return result; } /** * @return env entries (level 1) */ private ICLanguageSettingEntry[] getEnvEntries(int flags) { String paths[] = null; int kind = getKind(); switch (kind) { case ICSettingEntry.INCLUDE_PATH: { IEnvironmentVariableProvider provider = ManagedBuildManager.getEnvironmentVariableProvider(); paths = provider.getBuildPaths(fLangData.getConfiguration(), IEnvVarBuildPath.BUILDPATH_INCLUDE); } break; case ICSettingEntry.LIBRARY_PATH: { IEnvironmentVariableProvider provider = ManagedBuildManager.getEnvironmentVariableProvider(); paths = provider.getBuildPaths(fLangData.getConfiguration(), IEnvVarBuildPath.BUILDPATH_LIBRARY); } break; } if (paths != null && paths.length != 0) { ICLanguageSettingEntry entries[] = new ICLanguageSettingEntry[paths.length]; for (int i = 0; i < paths.length; i++) { entries[i] = (ICLanguageSettingEntry)CDataUtil.createEntry(kind, paths[i].toString(), null, null, flags); } return entries; } return new ICLanguageSettingEntry[0]; } /** * Create an ICLanguageSettingEntry based on the passed in Option */ private ICLanguageSettingEntry createUserEntry(Option option, OptionStringValue optionValue, int flags, SupplierBasedCdtVariableSubstitutor subst) { final int kind = getKind(); if (kind == ICSettingEntry.MACRO) { String nv[] = macroNameValueFromValue(optionValue.getValue()); return new CMacroEntry(nv[0], nv[1], flags); } IPath srcPath = null, srcRootPath = null, srcPrefixMapping = null; IOptionPathConverter optionPathConverter = fLangData.getTool().getOptionPathConverter(); // Create a PathInfo entry representing the optionValue PathInfo pInfo = optionPathValueToEntry(optionValue.getValue(), subst); if (pInfo.isWorkspacePath()) { flags |= ICSettingEntry.VALUE_WORKSPACE_PATH; } else if (optionPathConverter != null) { IPath path = optionPathConverter.convertToPlatformLocation(pInfo.getUnresolvedPath(), option, fLangData.getTool()); if (path != null) { pInfo = new PathInfo(path.toString(), false, subst); } } // make non absolute paths relative to the build directory if (getOptionType(option) != IOption.LIBRARIES) { pInfo = fromBuildToProj(pInfo); } else { // The IOption.LIBRARIES type is morphed to => ICSettingEntyr#LIBRARY_FILE // It *isn't* a workspace path! flags &= ~ICSettingEntry.VALUE_WORKSPACE_PATH; pInfo = new PathInfo(optionValue.getValue(), false, subst); } // Library files are special, they potentially know about their source Prefix & Root // The build system has two different types for storing Library Files: IOption.LIBRARIES // && IOption.LIBRARY_FILES. We map both of these to a CLibraryFileEntry, and mark the // difference with a flag isRawEntry Type. if (kind == ICSettingEntry.LIBRARY_FILE) { // Handle source types String tmp = optionValue.getSourceAttachmentPath(); if (tmp != null) srcPath = new Path(tmp); tmp = optionValue.getSourceAttachmentRootPath(); if (tmp != null) srcRootPath = new Path(tmp); tmp = optionValue.getSourceAttachmentPrefixMapping(); if (tmp != null) srcPrefixMapping = new Path(tmp); } return (ICLanguageSettingEntry)CDataUtil.createEntry(kind, pInfo.getUnresolvedPath(), null, null, flags, srcPath, srcRootPath, srcPrefixMapping); } private OptionStringValue createOptionValue(IOption option, UserEntryInfo info, SupplierBasedCdtVariableSubstitutor subst) { if (info.fOriginalValue != null) return info.fOriginalValue; return entryValueToOption(option, info.fEntry, subst); } private OptionStringValue entryValueToOption(IOption option, ICLanguageSettingEntry entry, SupplierBasedCdtVariableSubstitutor subst) { String optionValue = entryValueToOptionStringValue(option, entry, subst); if (entry.getKind() == ICSettingEntry.LIBRARY_FILE) { ICLibraryFileEntry libFile = (ICLibraryFileEntry)entry; return new OptionStringValue(optionValue, false, pathToString(libFile.getSourceAttachmentPath()), pathToString(libFile.getSourceAttachmentRootPath()), pathToString(libFile.getSourceAttachmentPrefixMapping())); } return new OptionStringValue(optionValue); } private static String pathToString(IPath path) { return path != null ? path.toString() : null; } private String entryValueToOptionStringValue(IOption option, ICLanguageSettingEntry entry, SupplierBasedCdtVariableSubstitutor subst) { String result; boolean checkQuote = true; if (entry.getKind() == ICSettingEntry.MACRO && entry.getValue().length() > 0) { result = new StringBuffer(entry.getName()).append('=').append(entry.getValue()).toString(); } else if (entry instanceof ICLanguageSettingPathEntry) { IOptionPathConverter converter = fLangData.getTool().getOptionPathConverter(); if (converter instanceof IReverseOptionPathConverter) { result = ((IReverseOptionPathConverter)converter).convertToOptionValue(entry, option, fLangData.getTool()); checkQuote = false; } else { ICLanguageSettingPathEntry pathEntry = (ICLanguageSettingPathEntry)entry; result = doConvertToOptionValue(option, pathEntry, subst); } } else { result = entry.getName(); } if (checkQuote) { result = doubleQuotePath(result, false); } return result; } private String doConvertToOptionValue(IOption option, ICLanguageSettingPathEntry pathEntry, SupplierBasedCdtVariableSubstitutor subst) { boolean isWsp = pathEntry.isValueWorkspacePath(); PathInfo pInfo = new PathInfo(pathEntry.getName(), isWsp, subst); String result; if (isWsp) { if (!pInfo.isAbsolute()) { IConfiguration cfg = fLangData.getConfiguration(); IResource rc = cfg.getOwner(); if (rc != null) { IProject proj = rc.getProject(); String path = pInfo.getUnresolvedPath(); IPath p = proj.getFullPath().append(path); result = p.toString(); } else { result = pathEntry.getName(); } } else { result = pathEntry.getName(); } result = ManagedBuildManager.fullPathToLocation(result); } else { // Persisting to the LIBRARIES option type doens't require path translation // as this is just the name of a library, not the path to it... if (getOptionType(option) != IOption.LIBRARIES) pInfo = fromProjToBuild(pInfo); result = pInfo.getUnresolvedPath(); } return result; } /** * @return the option type for the option */ private static int getOptionType(IOption option) { try { return option.getValueType(); } catch (BuildException e) { ManagedBuilderCorePlugin.log(e); } return IOption.STRING; } private static String doubleQuotePath(String pathName, boolean nullIfNone) { /* Trim */ pathName = pathName.trim(); /* Check if path is already double-quoted */ boolean bStartsWithQuote = pathName.indexOf('"') == 0; boolean bEndsWithQuote = pathName.lastIndexOf('"') == pathName.length() - 1; boolean quoted = false; /* Check for spaces, backslashes or macros */ int i = pathName.indexOf(' ') + pathName.indexOf('\\') + pathName.indexOf("${"); //$NON-NLS-1$ /* If indexOf didn't fail all three times, double-quote path */ if (i != -3) { if (!bStartsWithQuote) { pathName = "\"" + pathName; //$NON-NLS-1$ quoted = true; } if (!bEndsWithQuote) { pathName = pathName + "\""; //$NON-NLS-1$ quoted = true; } } if (quoted) return pathName; return nullIfNone ? null : pathName; } public static String[] macroNameValueFromValue(String value) { String nv[] = new String[2]; int index = value.indexOf('='); if (index > 0) { nv[0] = value.substring(0, index); nv[1] = value.substring(index + 1); } else { nv[0] = value; nv[1] = ""; //$NON-NLS-1$ } return nv; } // private static Object[] optionPathValueToEntry(String value) { // String wspPath = ManagedBuildManager.locationToFullPath(value); // if (wspPath != null) // return new Object[] { wspPath, Boolean.valueOf(true) }; // return new Object[] { value, Boolean.valueOf(false) }; // } private static PathInfo optionPathValueToEntry(String str, SupplierBasedCdtVariableSubstitutor subst) { String unresolvedStr = ManagedBuildManager.locationToFullPath(str); boolean isWorkspacePath = false; if (unresolvedStr == null) { unresolvedStr = str; } else { // A path starting from "${workspace_loc}" is always a filesystem path. if (!unresolvedStr.startsWith("${workspace_loc}")) { //$NON-NLS-1$ isWorkspacePath = true; } } return new PathInfo(unresolvedStr, isWorkspacePath, subst); } private void setUserEntries(UserEntryInfo[] entries, List<EmptyEntryInfo> emptyEntryInfos) { int kind = getKind(); IOption options[] = fLangData.getOptionsForKind(kind); // We don't expect more than one option to manage a particular entry kind, though it // is theoretically possible... Add a trace for Toolchain developers if (options.length > 1) ManagedBuilderCorePlugin.error("Unexpected error: Warning more than one options found for kind " + getKind()); //$NON-NLS-1$ if (options.length != 0) { IOption option = options[0]; OptionStringValue[] optValue; if (entries.length != 0) { entries = combineSequenses(entries); entries = addEmptyEntries(entries, emptyEntryInfos); optValue = new OptionStringValue[entries.length]; SupplierBasedCdtVariableSubstitutor subst = createSubstitutor(option, false); for (int i = 0; i < entries.length; i++) { optValue[i] = createOptionValue(option, entries[i], subst); } } else { optValue = Option.EMPTY_LV_ARRAY; } ITool tool = fLangData.getTool(); IResourceInfo rcInfo = tool.getParentResourceInfo(); IOption newOption = ManagedBuildManager.setOption(rcInfo, tool, option, optValue); for (IOption opt : fLangData.getOptionsForKind(kind)) { if (opt != newOption) ManagedBuildManager.setOption(rcInfo, tool, opt, new String[0]); } } } private UserEntryInfo[] addEmptyEntries(UserEntryInfo infos[], List<EmptyEntryInfo> emptyEntryInfos) { if (emptyEntryInfos == null || emptyEntryInfos.size() == 0) return infos; LinkedList<UserEntryInfo> list = new LinkedList<UserEntryInfo>(); list.addAll(Arrays.asList(infos)); for (int i = 0; i < emptyEntryInfos.size(); i++) { EmptyEntryInfo ei = emptyEntryInfos.get(i); int index = ei.fPosition; if (index > list.size()) index = list.size(); list.add(index, new UserEntryInfo(null, ei.fOriginalValue, ei.fOriginalValue, null)); } return list.toArray(new UserEntryInfo[list.size()]); } /** * This method iterates over the passed in UserEntryInfo[]. The point of it is * to collapse entries which are contained in a given UserEntry's sequence into a single * UserEntryInfo. * * FIXME: As far as I can see info.fSequense only ever has a single entry in it... * see UserEntryInfo constructor => this method doesn't accomplish anything useful */ private UserEntryInfo[] combineSequenses(UserEntryInfo infos[]) { if (infos.length == 0) return infos; List<UserEntryInfo> list = new ArrayList<UserEntryInfo>(infos.length); for (int i = 0; i < infos.length; i++) { UserEntryInfo info = infos[i]; if (info.fSequense != null) { boolean match = true; int seqSize = info.fSequense.size(); if (seqSize > infos.length - i) { match = false; } else { for (int k = 0; k < seqSize; k++) { if (info.fSequense.get(k) != infos[i + k]) { match = false; break; } } } if (match) { i = i + seqSize - 1; } else { infos[i] = createDesequencedEntry(info); for (int k = i + 1; k < infos.length; k++) { if (infos[k].fSequense == info.fSequense) infos[k] = createDesequencedEntry(infos[k]); } info = infos[i]; } } list.add(info); } return list.toArray(new UserEntryInfo[list.size()]); } private static UserEntryInfo createDesequencedEntry(UserEntryInfo info) { OptionStringValue resolvedValue = info.fBsResolvedValue; if (resolvedValue != null) { String v = doubleQuotePath(resolvedValue.getValue(), true); if (v != null) resolvedValue = substituteValue(resolvedValue, v); } return new UserEntryInfo(info.fEntry, resolvedValue, resolvedValue, null); } private void setUserUndefinedStringSet(Set<String> set) { int kind = getKind(); IOption[] options = fLangData.getUndefOptionsForKind(kind); if (options.length != 0) { if (set != null && set.size() == 0) set = null; String[] optValue = set != null ? (String[])set.toArray(new String[set.size()]) : new String[0]; IOption option = options[0]; ITool tool = fLangData.getTool(); IResourceInfo rcInfo = tool.getParentResourceInfo(); IOption newOption = ManagedBuildManager.setOption(rcInfo, tool, option, optValue); options = fLangData.getUndefOptionsForKind(kind); for (IOption opt : options) { if (opt != newOption) ManagedBuildManager.setOption(rcInfo, tool, option, new String[0]); } } } void optionsChanged() { } }