# HG changeset patch # User dadubrow # Date 1265052693 21600 # Node ID a163687f3d89ca6bdfa72e17a434b27458350733 # Parent 1ef0dbc67108d9d034c05c830694f771a42a7af7 backport hostside pnp diff -r 1ef0dbc67108 -r a163687f3d89 core/com.nokia.cpp.utils.core/src/com/nokia/cpp/internal/api/utils/core/HostOS.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/com.nokia.cpp.utils.core/src/com/nokia/cpp/internal/api/utils/core/HostOS.java Mon Feb 01 13:31:33 2010 -0600 @@ -0,0 +1,81 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + +package com.nokia.cpp.internal.api.utils.core; + +import java.io.File; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + + +/** + * Utilities used for portability between hosts. + *

+ * NOTE: please keep this in sync with the org.eclipse.cdt.debug.edc version of this class! + */ +public class HostOS { + /** Is the host Windows? */ + public static boolean IS_WIN32 = File.separatorChar == '\\'; + /** Is the host some Unix variant? */ + public static boolean IS_UNIX = File.separatorChar == '/'; + /** Executable file extension */ + public static final String EXE_EXT = IS_WIN32 ? ".exe" : ""; + + /** + * Ensure that the executable name mentioned is canonical for the machine. + * This only affects Windows, currently, ensuring that an ".exe" is attached. + * @param executablePath + * @return updated path + */ + public static String canonicalizeExecutableName(String executable) { + if (IS_WIN32) { + IPath executablePath = new Path(executable); + String ext = executablePath.getFileExtension(); + if (ext == null) { + executable += EXE_EXT; + } + } + return executable; + } + + /** + * Scan the PATH variable and see if the given binary is visible on + * the PATH that will be used at runtime (with the default environment and overrides). + * @param pathValue the expected Path + * @param program + * @return IPath if program is on PATH, else null + */ + public static IPath findProgramOnPath(String program, String pathValue) { + + // be sure proper path/extension are present + program = HostOS.canonicalizeExecutableName(program); + + IPath path = null; + + IPath[] pathEntries = PathUtils.getPathEntries(pathValue); + for (IPath pathEntry : pathEntries) { + IPath testPath = pathEntry.append(program); + if (testPath.toFile().exists()) { + path = testPath; + break; + } + } + + return path; + } +} diff -r 1ef0dbc67108 -r a163687f3d89 core/com.nokia.cpp.utils.core/src/com/nokia/cpp/internal/api/utils/core/PathUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/com.nokia.cpp.utils.core/src/com/nokia/cpp/internal/api/utils/core/PathUtils.java Mon Feb 01 13:31:33 2010 -0600 @@ -0,0 +1,272 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + +package com.nokia.cpp.internal.api.utils.core; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +/** + * These utilities handle some common portability issues when dealing with + * (absolute) paths which may be in a format intended for another operating system. + * It also handles shortcomings in the org.eclipse.core.runtime.Path + * implementation, which is not able to construct a meaningful path from + * a Win32 path outside of Windows. + *

+ * NOTE: please keep this in sync with the org.eclipse.cdt.debug.edc version of this class! + */ +public class PathUtils { + + /** + * Convert a variable constructed blindly for a Win32 environment into + * Unix-like syntax. This is typically used for PATH or lists + * of paths where ';' is the entry separator and '\' is the + * path component separator. + *

+ * NOTE: we assume that the entries in the + * path list are already legal Unix paths, but just with the + * wrong slash. + * @param env + * @return converted string + */ + public static String convertPathListToUnix(String env) { + if (env == null) return null; + env = env.replaceAll(";", ":"); // entry separators + env = env.replaceAll("\\\\", "/"); // path separators + return env; + } + + /** + * Convert a path constructed blindly for a Win32 environment into + * Unix-like syntax.

+ * NOTE: we assume that the path is already a legal Unix path, + * but just with the wrong slash. + * @param file + * @return converted string + */ + public static String convertPathToUnix(String file) { + if (file == null) return null; + // handle Windows slashes and canonicalize + file = file.replaceAll("\\\\", "/"); + return file; + } + + /** + * Convert a path which may be in Windows or Unix format to Windows format. + * NOTE: we assume that the path is already a legal path, + * but just with the wrong slash. + * @param file + * @return converted string + */ + public static String convertPathToWindows(String file) { + if (file == null) return null; + file = file.replaceAll("/", "\\\\"); + return file; + } + + /** + * Convert a path which may be in Windows or Unix format to Windows format. + * NOTE: we assume that the path is already a legal path, + * but just with the wrong slash. + * @param file + * @return converted string + */ + public static String convertPathToWindows(IPath path) { + return convertPathToWindows(path.toPortableString()); + } + + /** + * Convert a path which may be in the opposite slash format to the local slash format. + * NOTE: we assume that the path is already a legal path, + * but just with the wrong slash. + * @param file + * @return converted string + */ + public static String convertPathToNative(String path) { + if (path == null) return null; + if (HostOS.IS_UNIX) + return path.replaceAll("\\\\", "/"); + else + return path.replaceAll("/", "\\\\"); + } + + /** + * Create an IPath from a string which may be a Win32 path.

+ *

+ * ("new Path(...)" won't work in Unix when using a Win32 path: the backslash + * separator and the device notation are completely munged.) + * @param path + * @return converted string + */ + public static IPath createPath(String path) { + if (path == null) return null; + if (path.contains("\\")) { + // handle Windows slashes and canonicalize + path = path.replaceAll("\\\\", "/"); + } + + // also check for device or UNC + int idx = path.indexOf(":"); + if (idx > 0) { + String device = path.substring(0, idx + 1); + path = path.substring(idx + 1); + return new Path(path).setDevice(device); + } + else { + // Cygwin or UNC path + if (path.startsWith("//")) { + String network; + idx = path.indexOf("/", 2); + if (idx > 0) { + network = path.substring(0, idx); + path = path.substring(idx); + } else { + network = path; + path = ""; + } + return new Path(network, path).makeUNC(true); + } + } + + // fallthrough + return new Path(path); + } + + /** + * Get the PATH entries from the given path environment value or the + * system environment. + * @param pathValue the expected PATH/Path value, or null for the system value + * @return array of IPath, never null + */ + public static IPath[] getPathEntries(String pathValue) { + String pathVar = null; + if (pathValue != null) { + pathVar = pathValue; + } else { + if (HostOS.IS_WIN32) { + // canonical name, plus fallback below + pathVar = System.getenv("Path"); //$NON-NLS-1$ + } + if (pathVar == null) { + pathVar = System.getenv("PATH"); //$NON-NLS-1$ + } + } + + if (pathVar == null) + pathVar = ""; + + String pathSeparator = System.getProperty("path.separator"); + String[] pathEntries = pathVar.split(pathSeparator); + IPath[] paths = new IPath[pathEntries.length]; + for (int i = 0; i < pathEntries.length; i++) { + paths[i] = new Path(pathEntries[i]); + } + return paths; + } + + /** + * If the filesystem is case sensitive, locate the file on the filesystem + * on the given path, by ignoring case sensitivity differences. + * This is needed on case-preserving but not case-insensitive filesystems. + * @param path + * @return path pointing to existing file (possibly with different case in components) or + * original path if there is no match + */ + public static IPath findExistingPathIfCaseSensitive(IPath path) { + // case is insensitive already + if (HostOS.IS_WIN32) + return path; + + if (path == null || !path.isAbsolute()) + return path; + + File pathFile = path.toFile(); + if (pathFile.exists()) { + try { + return new Path(pathFile.getCanonicalPath()); + } catch (IOException e) { + // should not happen + return path; + } + } + + + // start with the assumption that the path is mostly correct except for the + // last N segments. + IPath goodPath = Path.ROOT; + if (path.getDevice() != null) + goodPath = goodPath.setDevice(path.getDevice()); + + // if bad drive or no root (?!), just skip + if (!goodPath.toFile().exists()) + return path; + + for (int seg = path.segmentCount(); seg > 0; seg--) { + final IPath prefix = path.uptoSegment(seg - 1); + + if (prefix.toFile().exists()) { + goodPath = prefix; + break; + } + } + + StringBuilder builder = new StringBuilder(); + + builder.append(goodPath.addTrailingSeparator().toOSString()); + + boolean failedLookup = false; + + for (int seg = goodPath.segmentCount(); seg < path.segmentCount(); seg++) { + final String segment = path.segment(seg); + + final String[] matches = { segment }; + + if (!failedLookup) { + File dir = new File(builder.toString()); + if (!new File(dir, matches[0]).exists()) { + // component has wrong case; find the first one matching case-insensitively + String[] names = dir.list(new FilenameFilter() { + + public boolean accept(File dir, String name) { + if (name.equalsIgnoreCase(segment)) { + matches[0] = name; + return true; + } + return false; + } + }); + + if (names.length == 0) { + // no matches! the rest of the path won't match either + failedLookup = true; + } + } + } + builder.append(matches[0]); + builder.append('/'); + } + + if (!path.hasTrailingSeparator() && builder.length() > 0 && builder.charAt(builder.length() - 1) == '/') { + builder.setLength(builder.length() - 1); + } + return new Path(builder.toString()); + } +}