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: #include "nsXULAppAPI.h" michael@0: #include "nsXPCOMGlue.h" michael@0: #include michael@0: #include michael@0: #ifdef XP_WIN michael@0: #include michael@0: #define snprintf _snprintf michael@0: #define strcasecmp _stricmp michael@0: #endif michael@0: michael@0: #include "nsAppRunner.h" michael@0: #include "nsIFile.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsMemory.h" michael@0: #include "nsCRTGlue.h" michael@0: #include "nsStringAPI.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: #include "plstr.h" michael@0: #include "prprf.h" michael@0: #include "prenv.h" michael@0: #include "nsINIParser.h" michael@0: michael@0: #ifdef XP_WIN michael@0: #include "nsWindowsWMain.cpp" michael@0: #endif michael@0: michael@0: #include "BinaryPath.h" michael@0: michael@0: #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL michael@0: michael@0: using namespace mozilla; michael@0: michael@0: /** michael@0: * Output a string to the user. This method is really only meant to be used to michael@0: * output last-ditch error messages designed for developers NOT END USERS. michael@0: * michael@0: * @param isError michael@0: * Pass true to indicate severe errors. michael@0: * @param fmt michael@0: * printf-style format string followed by arguments. michael@0: */ michael@0: static void Output(bool isError, const char *fmt, ... ) michael@0: { michael@0: va_list ap; michael@0: va_start(ap, fmt); michael@0: michael@0: #if (defined(XP_WIN) && !MOZ_WINCONSOLE) michael@0: char16_t msg[2048]; michael@0: _vsnwprintf(msg, sizeof(msg)/sizeof(msg[0]), NS_ConvertUTF8toUTF16(fmt).get(), ap); michael@0: michael@0: UINT flags = MB_OK; michael@0: if (isError) michael@0: flags |= MB_ICONERROR; michael@0: else michael@0: flags |= MB_ICONINFORMATION; michael@0: michael@0: MessageBoxW(nullptr, msg, L"XULRunner", flags); michael@0: #else michael@0: vfprintf(stderr, fmt, ap); michael@0: #endif michael@0: michael@0: va_end(ap); michael@0: } michael@0: michael@0: /** michael@0: * Return true if |arg| matches the given argument name. michael@0: */ michael@0: static bool IsArg(const char* arg, const char* s) michael@0: { michael@0: if (*arg == '-') michael@0: { michael@0: if (*++arg == '-') michael@0: ++arg; michael@0: return !strcasecmp(arg, s); michael@0: } michael@0: michael@0: #if defined(XP_WIN) michael@0: if (*arg == '/') michael@0: return !strcasecmp(++arg, s); michael@0: #endif michael@0: michael@0: return false; michael@0: } michael@0: michael@0: static nsresult michael@0: GetGREVersion(const char *argv0, michael@0: nsACString *aMilestone, michael@0: nsACString *aVersion) michael@0: { michael@0: if (aMilestone) michael@0: aMilestone->Assign(""); michael@0: if (aVersion) michael@0: aVersion->Assign(""); michael@0: michael@0: nsCOMPtr iniFile; michael@0: nsresult rv = BinaryPath::GetFile(argv0, getter_AddRefs(iniFile)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: iniFile->SetNativeLeafName(NS_LITERAL_CSTRING("platform.ini")); michael@0: michael@0: nsINIParser parser; michael@0: rv = parser.Init(iniFile); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: if (aMilestone) { michael@0: rv = parser.GetString("Build", "Milestone", *aMilestone); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: } michael@0: if (aVersion) { michael@0: rv = parser.GetString("Build", "BuildID", *aVersion); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: /** michael@0: * A helper class which calls NS_LogInit/NS_LogTerm in its scope. michael@0: */ michael@0: class ScopedLogging michael@0: { michael@0: public: michael@0: ScopedLogging() { NS_LogInit(); } michael@0: ~ScopedLogging() { NS_LogTerm(); } michael@0: }; michael@0: michael@0: static void Usage(const char *argv0) michael@0: { michael@0: nsAutoCString milestone; michael@0: GetGREVersion(argv0, &milestone, nullptr); michael@0: michael@0: // display additional information (XXX make localizable?) michael@0: Output(false, michael@0: "Mozilla XULRunner %s\n\n" michael@0: "Usage: " XULRUNNER_PROGNAME " [OPTIONS]\n" michael@0: " " XULRUNNER_PROGNAME " APP-FILE [APP-OPTIONS...]\n" michael@0: "\n" michael@0: "OPTIONS\n" michael@0: " --app specify APP-FILE (optional)\n" michael@0: " -h, --help show this message\n" michael@0: " -v, --version show version\n" michael@0: " --gre-version print the GRE version string on stdout\n" michael@0: "\n" michael@0: "APP-FILE\n" michael@0: " Application initialization file.\n" michael@0: "\n" michael@0: "APP-OPTIONS\n" michael@0: " Application specific options.\n", michael@0: milestone.get()); michael@0: } michael@0: michael@0: XRE_GetFileFromPathType XRE_GetFileFromPath; michael@0: XRE_CreateAppDataType XRE_CreateAppData; michael@0: XRE_FreeAppDataType XRE_FreeAppData; michael@0: XRE_mainType XRE_main; michael@0: michael@0: static const nsDynamicFunctionLoad kXULFuncs[] = { michael@0: { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath }, michael@0: { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData }, michael@0: { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData }, michael@0: { "XRE_main", (NSFuncPtr*) &XRE_main }, michael@0: { nullptr, nullptr } michael@0: }; michael@0: michael@0: class AutoAppData michael@0: { michael@0: public: michael@0: AutoAppData(nsIFile* aINIFile) : mAppData(nullptr) { michael@0: nsresult rv = XRE_CreateAppData(aINIFile, &mAppData); michael@0: if (NS_FAILED(rv)) michael@0: mAppData = nullptr; michael@0: } michael@0: ~AutoAppData() { michael@0: if (mAppData) michael@0: XRE_FreeAppData(mAppData); michael@0: } michael@0: michael@0: operator nsXREAppData*() const { return mAppData; } michael@0: nsXREAppData* operator -> () const { return mAppData; } michael@0: michael@0: private: michael@0: nsXREAppData* mAppData; michael@0: }; michael@0: michael@0: int main(int argc, char* argv[]) michael@0: { michael@0: char exePath[MAXPATHLEN]; michael@0: nsresult rv = mozilla::BinaryPath::Get(argv[0], exePath); michael@0: if (NS_FAILED(rv)) { michael@0: Output(true, "Couldn't calculate the application directory.\n"); michael@0: return 255; michael@0: } michael@0: michael@0: char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]); michael@0: if (!lastSlash || (size_t(lastSlash - exePath) > MAXPATHLEN - sizeof(XPCOM_DLL) - 1)) michael@0: return 255; michael@0: michael@0: strcpy(++lastSlash, XPCOM_DLL); michael@0: michael@0: rv = XPCOMGlueStartup(exePath); michael@0: if (NS_FAILED(rv)) { michael@0: Output(true, "Couldn't load XPCOM.\n"); michael@0: return 255; michael@0: } michael@0: michael@0: ScopedLogging log; michael@0: michael@0: if (argc > 1 && (IsArg(argv[1], "h") || michael@0: IsArg(argv[1], "help") || michael@0: IsArg(argv[1], "?"))) michael@0: { michael@0: Usage(argv[0]); michael@0: return 0; michael@0: } michael@0: michael@0: if (argc == 2 && (IsArg(argv[1], "v") || IsArg(argv[1], "version"))) michael@0: { michael@0: nsAutoCString milestone; michael@0: nsAutoCString version; michael@0: GetGREVersion(argv[0], &milestone, &version); michael@0: Output(false, "Mozilla XULRunner %s - %s\n", michael@0: milestone.get(), version.get()); michael@0: return 0; michael@0: } michael@0: michael@0: rv = XPCOMGlueLoadXULFunctions(kXULFuncs); michael@0: if (NS_FAILED(rv)) { michael@0: Output(true, "Couldn't load XRE functions.\n"); michael@0: return 255; michael@0: } michael@0: michael@0: if (argc > 1) { michael@0: nsAutoCString milestone; michael@0: rv = GetGREVersion(argv[0], &milestone, nullptr); michael@0: if (NS_FAILED(rv)) michael@0: return 2; michael@0: michael@0: if (IsArg(argv[1], "gre-version")) { michael@0: if (argc != 2) { michael@0: Usage(argv[0]); michael@0: return 1; michael@0: } michael@0: michael@0: printf("%s\n", milestone.get()); michael@0: return 0; michael@0: } michael@0: michael@0: if (IsArg(argv[1], "install-app")) { michael@0: Output(true, "--install-app support has been removed. Use 'python install-app.py' instead.\n"); michael@0: return 1; michael@0: } michael@0: } michael@0: michael@0: const char *appDataFile = getenv("XUL_APP_FILE"); michael@0: michael@0: if (!(appDataFile && *appDataFile)) { michael@0: if (argc < 2) { michael@0: Usage(argv[0]); michael@0: return 1; michael@0: } michael@0: michael@0: if (IsArg(argv[1], "app")) { michael@0: if (argc == 2) { michael@0: Usage(argv[0]); michael@0: return 1; michael@0: } michael@0: argv[1] = argv[0]; michael@0: ++argv; michael@0: --argc; michael@0: } michael@0: michael@0: appDataFile = argv[1]; michael@0: argv[1] = argv[0]; michael@0: ++argv; michael@0: --argc; michael@0: michael@0: static char kAppEnv[MAXPATHLEN]; michael@0: snprintf(kAppEnv, MAXPATHLEN, "XUL_APP_FILE=%s", appDataFile); michael@0: putenv(kAppEnv); michael@0: } michael@0: michael@0: nsCOMPtr appDataLF; michael@0: rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appDataLF)); michael@0: if (NS_FAILED(rv)) { michael@0: Output(true, "Error: unrecognized application.ini path.\n"); michael@0: return 2; michael@0: } michael@0: michael@0: AutoAppData appData(appDataLF); michael@0: if (!appData) { michael@0: Output(true, "Error: couldn't parse application.ini.\n"); michael@0: return 2; michael@0: } michael@0: michael@0: return XRE_main(argc, argv, appData, 0); michael@0: }