| /******************************************************************************* |
| * Copyright (c) 2004, 2011 QNX Software Systems 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: |
| * QNX Software Systems - initial API and implementation |
| * Markus Schorn (Wind River Systems) |
| * Ed Swartz (Nokia) |
| * Sergey Prigogin (Google) |
| * James Blackburn (Broadcom Corp.) |
| *******************************************************************************/ |
| package org.eclipse.cdt.utils; |
| |
| import java.io.File; |
| import java.io.IOException; |
| |
| import org.eclipse.cdt.core.CCorePlugin; |
| import org.eclipse.cdt.core.parser.IScannerInfo; |
| import org.eclipse.cdt.core.parser.IScannerInfoProvider; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IWorkspace; |
| import org.eclipse.core.resources.IWorkspaceRoot; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Platform; |
| |
| /** |
| * @noextend This class is not intended to be subclassed by clients. |
| * @noinstantiate This class is not intended to be instantiated by clients. |
| */ |
| public class PathUtil { |
| /** Detect whether we're running on Windows (as IPath does) */ |
| private static final boolean WINDOWS = java.io.File.separatorChar == '\\'; |
| |
| public static boolean isWindowsFileSystem() { |
| return WINDOWS; |
| } |
| |
| public static IWorkspaceRoot getWorkspaceRoot() { |
| IWorkspace workspace = ResourcesPlugin.getWorkspace(); |
| if (workspace != null) { |
| return workspace.getRoot(); |
| } |
| return null; |
| } |
| |
| /** |
| * Return the canonical path (or the passed in path, if one couldn't be found). |
| * @param fullPath |
| * @return canonicalized IPath or passed in fullPath. |
| */ |
| public static IPath getCanonicalPath(IPath fullPath) { |
| if (!fullPath.isAbsolute()) |
| return fullPath; |
| |
| File file = fullPath.toFile(); |
| try { |
| String canonPath = file.getCanonicalPath(); |
| IPath canonicalPath = new Path(canonPath); |
| if (fullPath.getDevice() == null) |
| canonicalPath = canonicalPath.setDevice(null); |
| return canonicalPath; |
| } catch (IOException ex) { |
| } |
| return fullPath; |
| } |
| |
| /** |
| * On Windows returns the {@link java.io.File#getCanonicalPath()} for a given absolute path. |
| * On other platforms, and for relative paths returns the the original path. |
| * |
| * @param fullPath |
| * @return canonicalized IPath or passed in fullPath. |
| * @since 5.3 |
| */ |
| public static IPath getCanonicalPathWindows(IPath fullPath) { |
| if (!WINDOWS) |
| return fullPath; |
| return getCanonicalPath(fullPath); |
| } |
| |
| public static IPath getWorkspaceRelativePath(IPath fullPath) { |
| IWorkspaceRoot workspaceRoot = getWorkspaceRoot(); |
| if (workspaceRoot != null) { |
| IPath workspaceLocation = workspaceRoot.getLocation(); |
| if (workspaceLocation != null && isPrefix(workspaceLocation, fullPath)) { |
| int segments = matchingFirstSegments(fullPath, workspaceLocation); |
| IPath relPath = fullPath.setDevice(null).removeFirstSegments(segments); |
| return new Path("").addTrailingSeparator().append(relPath); //$NON-NLS-1$ |
| } |
| } |
| return fullPath; |
| } |
| |
| public static IPath getProjectRelativePath(IPath fullPath, IProject project) { |
| IPath projectPath = project.getFullPath(); |
| if (isPrefix(projectPath, fullPath)) { |
| return fullPath.removeFirstSegments(projectPath.segmentCount()); |
| } |
| projectPath = project.getLocation(); |
| if (isPrefix(projectPath, fullPath)) { |
| return fullPath.removeFirstSegments(projectPath.segmentCount()); |
| } |
| return getWorkspaceRelativePath(fullPath); |
| } |
| |
| public static IPath getWorkspaceRelativePath(String fullPath) { |
| return getWorkspaceRelativePath(new Path(fullPath)); |
| } |
| |
| public static IPath getRawLocation(IPath wsRelativePath) { |
| IWorkspaceRoot workspaceRoot = getWorkspaceRoot(); |
| if (workspaceRoot != null && wsRelativePath != null) { |
| IPath workspaceLocation = workspaceRoot.getLocation(); |
| if (workspaceLocation != null && !isPrefix(workspaceLocation, wsRelativePath)) { |
| return workspaceLocation.append(wsRelativePath); |
| } |
| } |
| return wsRelativePath; |
| } |
| |
| public static IPath makeRelativePath(IPath path, IPath relativeTo) { |
| int segments = matchingFirstSegments(relativeTo, path); |
| if (segments > 0) { |
| IPath prefix = relativeTo.removeFirstSegments(segments); |
| IPath suffix = path.removeFirstSegments(segments); |
| IPath relativePath = new Path(""); //$NON-NLS-1$ |
| for (int i = 0; i < prefix.segmentCount(); ++i) { |
| relativePath = relativePath.append(".." + IPath.SEPARATOR); //$NON-NLS-1$ |
| } |
| return relativePath.append(suffix); |
| } |
| return null; |
| } |
| |
| public static IPath makeRelativePathToProjectIncludes(IPath fullPath, IProject project) { |
| IScannerInfoProvider provider = CCorePlugin.getDefault().getScannerInfoProvider(project); |
| if (provider != null) { |
| IScannerInfo info = provider.getScannerInformation(project); |
| if (info != null) { |
| return makeRelativePathToIncludes(fullPath, info.getIncludePaths()); |
| } |
| } |
| return null; |
| } |
| |
| public static IPath makeRelativePathToIncludes(IPath fullPath, String[] includePaths) { |
| IPath relativePath = null; |
| int mostSegments = 0; |
| for (int i = 0; i < includePaths.length; ++i) { |
| IPath includePath = new Path(includePaths[i]); |
| if (isPrefix(includePath, fullPath)) { |
| int segments = includePath.segmentCount(); |
| if (segments > mostSegments) { |
| relativePath = fullPath.removeFirstSegments(segments).setDevice(null); |
| mostSegments = segments; |
| } |
| } |
| } |
| return relativePath; |
| } |
| |
| public static IProject getEnclosingProject(IPath fullPath) { |
| IWorkspaceRoot root = getWorkspaceRoot(); |
| if (root != null) { |
| IPath path = getWorkspaceRelativePath(fullPath); |
| while (path.segmentCount() > 0) { |
| IResource res = root.findMember(path); |
| if (res != null) |
| return res.getProject(); |
| |
| path = path.removeLastSegments(1); |
| } |
| } |
| return null; |
| } |
| |
| public static IPath getValidEnclosingFolder(IPath fullPath) { |
| IWorkspaceRoot root = getWorkspaceRoot(); |
| if (root != null) { |
| IPath path = getWorkspaceRelativePath(fullPath); |
| while (path.segmentCount() > 0) { |
| IResource res = root.findMember(path); |
| if (res != null && res.exists() && (res.getType() == IResource.PROJECT || res.getType() == IResource.FOLDER)) |
| return path; |
| |
| path = path.removeLastSegments(1); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Checks whether path1 is the same as path2. |
| * <p> |
| * Similar to IPath.equals(Object obj), but takes case sensitivity of the file system |
| * into account. |
| * |
| * @return {@code true} if path1 is the same as path2, and {@code false} otherwise |
| * |
| * @since 5.1 |
| * @deprecated Use {@link #equalPath(IPath, IPath)} instead. |
| */ |
| @Deprecated |
| public boolean equal(IPath path1, IPath path2) { |
| // Check leading separators |
| if (path1.isAbsolute() != path2.isAbsolute() || path1.isUNC() != path2.isUNC()) { |
| return false; |
| } |
| int i = path1.segmentCount(); |
| // Check segment count |
| if (i != path2.segmentCount()) |
| return false; |
| // Check segments in reverse order - later segments more likely to differ |
| while (--i >= 0) { |
| if (!path1.segment(i).equals(path2.segment(i))) |
| return false; |
| } |
| // Check device last (least likely to differ) |
| if (path1.getDevice() == null) { |
| return path2.getDevice() == null; |
| } else { |
| return path1.getDevice().equalsIgnoreCase(path2.getDevice()); |
| } |
| } |
| |
| /** |
| * Checks whether path1 is the same as path2. |
| * <p> |
| * Similar to IPath.equals(Object obj), but takes case sensitivity of the file system |
| * into account. |
| * |
| * @return {@code true} if path1 is the same as path2, and {@code false} otherwise |
| * @since 5.3 |
| */ |
| public static boolean equalPath(IPath path1, IPath path2) { |
| // Check leading separators |
| if (path1.isAbsolute() != path2.isAbsolute() || path1.isUNC() != path2.isUNC()) { |
| return false; |
| } |
| int i = path1.segmentCount(); |
| // Check segment count |
| if (i != path2.segmentCount()) |
| return false; |
| // Check segments in reverse order - later segments more likely to differ |
| boolean caseSensitive = !isWindowsFileSystem(); |
| while (--i >= 0) { |
| if (!(caseSensitive ? |
| path1.segment(i).equals(path2.segment(i)) : |
| path1.segment(i).equalsIgnoreCase(path2.segment(i)))) { |
| return false; |
| } |
| } |
| // Check device last (least likely to differ) |
| if (path1.getDevice() == null) { |
| return path2.getDevice() == null; |
| } else { |
| return path1.getDevice().equalsIgnoreCase(path2.getDevice()); |
| } |
| } |
| |
| /** |
| * Checks whether path1 is a prefix of path2. To be a prefix, path1's segments |
| * must appear in path1 in the same order, and their device ids must match. |
| * <p> |
| * An empty path is a prefix of all paths with the same device; a root path is a prefix of |
| * all absolute paths with the same device. |
| * <p> |
| * Similar to IPath.isPrefixOf(IPath anotherPath), but takes case sensitivity of the file system |
| * into account. |
| * |
| * @return {@code true} if path1 is a prefix of path2, and {@code false} otherwise |
| * @since 5.1 |
| */ |
| public static boolean isPrefix(IPath path1, IPath path2) { |
| if (path1.getDevice() == null) { |
| if (path2.getDevice() != null) { |
| return false; |
| } |
| } else { |
| if (!path1.getDevice().equalsIgnoreCase(path2.getDevice())) { |
| return false; |
| } |
| } |
| if (path1.isEmpty() || (path1.isRoot() && path2.isAbsolute())) { |
| return true; |
| } |
| int len1 = path1.segmentCount(); |
| if (len1 > path2.segmentCount()) { |
| return false; |
| } |
| boolean caseSensitive = !isWindowsFileSystem(); |
| for (int i = 0; i < len1; i++) { |
| if (!(caseSensitive ? |
| path1.segment(i).equals(path2.segment(i)) : |
| path1.segment(i).equalsIgnoreCase(path2.segment(i)))) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Returns the number of segments which match in path1 and path2 |
| * (device ids are ignored), comparing in increasing segment number order. |
| * <p> |
| * Similar to IPath.matchingFirstSegments(IPath anotherPath), but takes case sensitivity |
| * of the file system into account. |
| * |
| * @return the number of matching segments |
| * @since 5.1 |
| */ |
| public static int matchingFirstSegments(IPath path1, IPath path2) { |
| Assert.isNotNull(path1); |
| Assert.isNotNull(path2); |
| int len1 = path1.segmentCount(); |
| int len2 = path2.segmentCount(); |
| int max = Math.min(len1, len2); |
| int count = 0; |
| boolean caseSensitive = !isWindowsFileSystem(); |
| for (int i = 0; i < max; i++) { |
| if (!(caseSensitive ? |
| path1.segment(i).equals(path2.segment(i)) : |
| path1.segment(i).equalsIgnoreCase(path2.segment(i)))) { |
| return count; |
| } |
| count++; |
| } |
| return count; |
| } |
| |
| /** |
| * Finds location of the program inspecting each path in the path list. |
| * |
| * @param prog - program to find. For Windows, extensions "com" and "exe" |
| * can be omitted. |
| * @param pathsStr - the list of paths to inspect separated by path separator |
| * defined in the platform (i.e. ":" in Unix and ";" in Windows). |
| * In case pathStr is {@code null} environment variable ${PATH} is inspected. |
| * @return - absolute location of the file on the file system |
| * or {@code null} if not found. |
| * @since 5.3 |
| */ |
| public static IPath findProgramLocation(String prog, String pathsStr) { |
| if (prog == null || prog.trim().isEmpty()) |
| return null; |
| |
| if (pathsStr == null) |
| pathsStr = System.getenv("PATH"); //$NON-NLS-1$ |
| |
| if (pathsStr.trim().isEmpty()) |
| return null; |
| |
| String locationStr = null; |
| String[] dirs = pathsStr.split(File.pathSeparator); |
| |
| // Try to find "prog.exe" or "prog.com" on Windows |
| if (Platform.getOS().equals(Platform.OS_WIN32)) { |
| for (String dir : dirs) { |
| IPath dirLocation = new Path(dir); |
| File file = null; |
| |
| file = dirLocation.append(prog + ".exe").toFile(); //$NON-NLS-1$ |
| if (file.isFile() && file.canRead()) { |
| locationStr = file.getAbsolutePath(); |
| break; |
| } |
| file = dirLocation.append(prog + ".com").toFile(); //$NON-NLS-1$ |
| if (file.isFile() && file.canRead()) { |
| locationStr = file.getAbsolutePath(); |
| break; |
| } |
| } |
| } |
| |
| // Check "prog" on Unix and Windows too (if was not found) - could be cygwin or something |
| // do it in separate loop due to performance and correctness of Windows regular case |
| if (locationStr == null) { |
| for (String dir : dirs) { |
| IPath dirLocation = new Path(dir); |
| File file = null; |
| |
| file = dirLocation.append(prog).toFile(); |
| if (file.isFile() && file.canRead()) { |
| locationStr = file.getAbsolutePath(); |
| break; |
| } |
| } |
| } |
| |
| if (locationStr != null) |
| return new Path(locationStr); |
| |
| return null; |
| } |
| |
| /** |
| * Finds location of the program inspecting each path in the path list |
| * defined by environment variable ${PATH}. |
| * |
| * @param prog - program to find. For Windows, extensions "com" and "exe" |
| * can be omitted. |
| * @return - absolute location of the file on the file system |
| * or {@code null} if not found. |
| * @since 5.3 |
| */ |
| public static IPath findProgramLocation(String prog) { |
| return findProgramLocation(prog, null); |
| } |
| } |