michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_BinaryPath_h michael@0: #define mozilla_BinaryPath_h michael@0: michael@0: #include "nsXPCOMPrivate.h" // for MAXPATHLEN michael@0: #ifdef XP_WIN michael@0: #include michael@0: #elif defined(XP_MACOSX) michael@0: #include michael@0: #elif defined(XP_UNIX) michael@0: #include michael@0: #include michael@0: #endif michael@0: michael@0: namespace mozilla { michael@0: michael@0: class BinaryPath { michael@0: public: michael@0: #ifdef XP_WIN michael@0: static nsresult Get(const char *argv0, char aResult[MAXPATHLEN]) michael@0: { michael@0: wchar_t wide_path[MAXPATHLEN]; michael@0: nsresult rv = GetW(argv0, wide_path); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: WideCharToMultiByte(CP_UTF8, 0, wide_path, -1, michael@0: aResult, MAXPATHLEN, nullptr, nullptr); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: static nsresult GetW(const char *argv0, wchar_t aResult[MAXPATHLEN]) michael@0: { michael@0: if (::GetModuleFileNameW(0, aResult, MAXPATHLEN)) michael@0: return NS_OK; michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: #elif defined(XP_MACOSX) michael@0: static nsresult Get(const char *argv0, char aResult[MAXPATHLEN]) michael@0: { michael@0: // Works even if we're not bundled. michael@0: CFBundleRef appBundle = CFBundleGetMainBundle(); michael@0: if (!appBundle) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle); michael@0: if (!executableURL) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsresult rv; michael@0: if (CFURLGetFileSystemRepresentation(executableURL, false, (UInt8 *)aResult, MAXPATHLEN)) michael@0: rv = NS_OK; michael@0: else michael@0: rv = NS_ERROR_FAILURE; michael@0: CFRelease(executableURL); michael@0: return rv; michael@0: } michael@0: michael@0: #elif defined(ANDROID) michael@0: static nsresult Get(const char *argv0, char aResult[MAXPATHLEN]) michael@0: { michael@0: // On Android, we use the GRE_HOME variable that is set by the Java michael@0: // bootstrap code. michael@0: const char *greHome = getenv("GRE_HOME"); michael@0: #if defined(MOZ_WIDGET_GONK) michael@0: if (!greHome) michael@0: greHome = "/system/b2g"; michael@0: #endif michael@0: michael@0: if (!greHome) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: snprintf(aResult, MAXPATHLEN, "%s/%s", greHome, "dummy"); michael@0: aResult[MAXPATHLEN-1] = '\0'; michael@0: return NS_OK; michael@0: } michael@0: michael@0: #elif defined(XP_UNIX) michael@0: static nsresult Get(const char *argv0, char aResult[MAXPATHLEN]) michael@0: { michael@0: struct stat fileStat; michael@0: // on unix, there is no official way to get the path of the current binary. michael@0: // instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to michael@0: // multiple applications, we will try a series of techniques: michael@0: // michael@0: // 1) use realpath() on argv[0], which works unless we're loaded from the michael@0: // PATH. Only do so if argv[0] looks like a path (contains a /). michael@0: // 2) manually walk through the PATH and look for ourself michael@0: // 3) give up michael@0: if (strchr(argv0, '/') && realpath(argv0, aResult) && michael@0: stat(aResult, &fileStat) == 0) michael@0: return NS_OK; michael@0: michael@0: const char *path = getenv("PATH"); michael@0: if (!path) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: char *pathdup = strdup(path); michael@0: if (!pathdup) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: bool found = false; michael@0: char *token = strtok(pathdup, ":"); michael@0: while (token) { michael@0: char tmpPath[MAXPATHLEN]; michael@0: sprintf(tmpPath, "%s/%s", token, argv0); michael@0: if (realpath(tmpPath, aResult) && stat(aResult, &fileStat) == 0) { michael@0: found = true; michael@0: break; michael@0: } michael@0: token = strtok(nullptr, ":"); michael@0: } michael@0: free(pathdup); michael@0: if (found) michael@0: return NS_OK; michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: #else michael@0: #error Oops, you need platform-specific code here michael@0: #endif michael@0: michael@0: public: michael@0: static nsresult GetFile(const char *argv0, nsIFile* *aResult) michael@0: { michael@0: nsCOMPtr lf; michael@0: #ifdef XP_WIN michael@0: wchar_t exePath[MAXPATHLEN]; michael@0: nsresult rv = GetW(argv0, exePath); michael@0: #else michael@0: char exePath[MAXPATHLEN]; michael@0: nsresult rv = Get(argv0, exePath); michael@0: #endif michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: #ifdef XP_WIN michael@0: rv = NS_NewLocalFile(nsDependentString(exePath), true, michael@0: getter_AddRefs(lf)); michael@0: #else michael@0: rv = NS_NewNativeLocalFile(nsDependentCString(exePath), true, michael@0: getter_AddRefs(lf)); michael@0: #endif michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: NS_ADDREF(*aResult = lf); michael@0: return NS_OK; michael@0: } michael@0: }; michael@0: michael@0: } michael@0: michael@0: #endif /* mozilla_BinaryPath_h */