/*******************************************************************************
* Copyright (c) 2009, 2016 Wind River Systems, Inc. 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:
* Markus Schorn - initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.parser.scanner;
import java.io.File;
import org.eclipse.cdt.utils.PathUtil;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
/**
* Represents an entry of the include search path
*/
public final class IncludeSearchPathElement {
private static final boolean NON_SLASH_SEPARATOR = File.separatorChar != '/';
public static final String FRAMEWORK_VAR = "__framework__"; //$NON-NLS-1$
public static final String FILE_VAR = "__header__"; //$NON-NLS-1$
private static final String FRAMEWORK_HEADERS = ".framework/Headers"; //$NON-NLS-1$
private final String fPath;
private final boolean fForQuoteIncludesOnly;
private final boolean fIsFrameworkDirectory;
private final boolean fIsNewFrameworkDirectory;
IncludeSearchPathElement(String path, boolean forQuoteIncludesOnly) {
fPath = path;
fForQuoteIncludesOnly = forQuoteIncludesOnly;
if (path.indexOf('_') != -1 && path.indexOf(FRAMEWORK_VAR) != -1 && path.indexOf(FILE_VAR) != -1) {
fIsFrameworkDirectory = true;
fIsNewFrameworkDirectory = false;
} else if (path.endsWith(FRAMEWORK_HEADERS)) {
fIsFrameworkDirectory = false;
fIsNewFrameworkDirectory = true;
} else {
fIsFrameworkDirectory = false;
fIsNewFrameworkDirectory = false;
}
}
public boolean isForQuoteIncludesOnly() {
return fForQuoteIncludesOnly;
}
public String getLocation(String includeDirective) {
if (fIsFrameworkDirectory) {
int firstSep = firstSeparator(includeDirective);
if (firstSep <= 0) {
return null;
}
String framework = includeDirective.substring(0, firstSep);
String file = includeDirective.substring(firstSep + 1);
if (file.length() == 0)
return null;
StringBuilder buf = new StringBuilder(fPath);
replace(buf, FRAMEWORK_VAR, framework);
replace(buf, FILE_VAR, file);
return ScannerUtility.reconcilePath(buf.toString());
} else if (fIsNewFrameworkDirectory) {
int firstSep = firstSeparator(includeDirective);
if (firstSep > 0) {
String framework = includeDirective.substring(0, firstSep);
String file = includeDirective.substring(firstSep + 1);
if (file.length() > 0) {
if (fPath.endsWith(framework + FRAMEWORK_HEADERS)) {
return ScannerUtility.createReconciledPath(fPath, file);
}
}
}
}
return ScannerUtility.createReconciledPath(fPath, includeDirective);
}
/**
* Returns the include directive for the given location satisfying the
* condition {@code getLocation(getIncludeDirective(location) == location}.
* If no such include directive without ".." exists, returns {@code null}.
*/
public String getIncludeDirective(String location) {
IPath dirPath = new Path(fPath);
IPath locationPath = new Path(location);
if (fIsFrameworkDirectory) {
if (dirPath.segmentCount() != locationPath.segmentCount())
return null;
int i = PathUtil.matchingFirstSegments(dirPath, locationPath);
String dirSegment = dirPath.segment(i);
String locationSegment = locationPath.segment(i);
String framework = deduceVariable(FRAMEWORK_VAR, dirSegment, locationSegment);
if (framework == null)
return null;
i++;
dirPath = dirPath.removeFirstSegments(i);
locationPath = locationPath.removeFirstSegments(i);
i = PathUtil.matchingFirstSegments(dirPath, locationPath);
if (i < dirPath.segmentCount() - 1)
return null;
dirSegment = dirPath.segment(i);
locationSegment = locationPath.segment(i);
String file = deduceVariable(FILE_VAR, dirSegment, locationSegment);
if (file == null)
return null;
return framework + '/' + file;
}
if (!PathUtil.isPrefix(dirPath, locationPath))
return null;
return locationPath.removeFirstSegments(dirPath.segmentCount()).setDevice(null).toPortableString();
}
private int firstSeparator(String path) {
int firstSep = path.indexOf('/');
if (NON_SLASH_SEPARATOR) {
firstSep = Math.max(firstSep, path.indexOf(File.separatorChar));
}
return firstSep;
}
private void replace(StringBuilder buf, String find, final String replace) {
int idx = buf.indexOf(find);
if (idx >= 0) {
buf.replace(idx, idx + find.length(), replace);
}
}
private String deduceVariable(String varName, String raw, String substituted) {
int pos = raw.indexOf(varName);
if (pos < 0)
return null;
int suffixLength = raw.length() - pos - varName.length();
if (substituted.length() <= pos + suffixLength)
return null;
for (int i = 0; i < suffixLength; i++) {
if (raw.charAt(raw.length() - i) != substituted.charAt(substituted.length() - i))
return null;
}
return substituted.substring(pos, substituted.length() - suffixLength);
}
/**
* For debugging only.
*/
@Override
public String toString() {
return fPath;
}
}