Merge m-c to b2g-inbound.
[gecko.git] / xulrunner / app / nsXULRunnerApp.cpp
blob20e9d65c1ef86a994b8371ddbcd88e8b468b176c
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "nsXULAppAPI.h"
6 #include "nsXPCOMGlue.h"
7 #include <stdio.h>
8 #include <stdlib.h>
9 #ifdef XP_WIN
10 #include <windows.h>
11 #define snprintf _snprintf
12 #define strcasecmp _stricmp
13 #endif
15 #include "nsAppRunner.h"
16 #include "nsIFile.h"
17 #include "nsIXULAppInstall.h"
18 #include "nsCOMPtr.h"
19 #include "nsMemory.h"
20 #include "nsCRTGlue.h"
21 #include "nsStringAPI.h"
22 #include "nsServiceManagerUtils.h"
23 #include "plstr.h"
24 #include "prprf.h"
25 #include "prenv.h"
26 #include "nsINIParser.h"
28 #ifdef XP_WIN
29 #include "nsWindowsWMain.cpp"
30 #endif
32 #include "BinaryPath.h"
34 #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
36 using namespace mozilla;
38 /**
39 * Output a string to the user. This method is really only meant to be used to
40 * output last-ditch error messages designed for developers NOT END USERS.
42 * @param isError
43 * Pass true to indicate severe errors.
44 * @param fmt
45 * printf-style format string followed by arguments.
47 static void Output(bool isError, const char *fmt, ... )
49 va_list ap;
50 va_start(ap, fmt);
52 #if (defined(XP_WIN) && !MOZ_WINCONSOLE)
53 PRUnichar msg[2048];
54 _vsnwprintf(msg, sizeof(msg)/sizeof(msg[0]), NS_ConvertUTF8toUTF16(fmt).get(), ap);
56 UINT flags = MB_OK;
57 if (isError)
58 flags |= MB_ICONERROR;
59 else
60 flags |= MB_ICONINFORMATION;
62 MessageBoxW(nullptr, msg, L"XULRunner", flags);
63 #else
64 vfprintf(stderr, fmt, ap);
65 #endif
67 va_end(ap);
70 /**
71 * Return true if |arg| matches the given argument name.
73 static bool IsArg(const char* arg, const char* s)
75 if (*arg == '-')
77 if (*++arg == '-')
78 ++arg;
79 return !strcasecmp(arg, s);
82 #if defined(XP_WIN) || defined(XP_OS2)
83 if (*arg == '/')
84 return !strcasecmp(++arg, s);
85 #endif
87 return false;
90 static nsresult
91 GetGREVersion(const char *argv0,
92 nsACString *aMilestone,
93 nsACString *aVersion)
95 if (aMilestone)
96 aMilestone->Assign("<Error>");
97 if (aVersion)
98 aVersion->Assign("<Error>");
100 nsCOMPtr<nsIFile> iniFile;
101 nsresult rv = BinaryPath::GetFile(argv0, getter_AddRefs(iniFile));
102 if (NS_FAILED(rv))
103 return rv;
105 iniFile->SetNativeLeafName(NS_LITERAL_CSTRING("platform.ini"));
107 nsINIParser parser;
108 rv = parser.Init(iniFile);
109 if (NS_FAILED(rv))
110 return rv;
112 if (aMilestone) {
113 rv = parser.GetString("Build", "Milestone", *aMilestone);
114 if (NS_FAILED(rv))
115 return rv;
117 if (aVersion) {
118 rv = parser.GetString("Build", "BuildID", *aVersion);
119 if (NS_FAILED(rv))
120 return rv;
122 return NS_OK;
125 static void Usage(const char *argv0)
127 nsAutoCString milestone;
128 GetGREVersion(argv0, &milestone, nullptr);
130 // display additional information (XXX make localizable?)
131 Output(false,
132 "Mozilla XULRunner %s\n\n"
133 "Usage: " XULRUNNER_PROGNAME " [OPTIONS]\n"
134 " " XULRUNNER_PROGNAME " APP-FILE [APP-OPTIONS...]\n"
135 "\n"
136 "OPTIONS\n"
137 " --app specify APP-FILE (optional)\n"
138 " -h, --help show this message\n"
139 " -v, --version show version\n"
140 " --gre-version print the GRE version string on stdout\n"
141 " --install-app <application> [<destination> [<directoryname>]]\n"
142 " Install a XUL application.\n"
143 "\n"
144 "APP-FILE\n"
145 " Application initialization file.\n"
146 "\n"
147 "APP-OPTIONS\n"
148 " Application specific options.\n",
149 milestone.get());
152 XRE_GetFileFromPathType XRE_GetFileFromPath;
153 XRE_CreateAppDataType XRE_CreateAppData;
154 XRE_FreeAppDataType XRE_FreeAppData;
155 XRE_mainType XRE_main;
157 static const nsDynamicFunctionLoad kXULFuncs[] = {
158 { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
159 { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData },
160 { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData },
161 { "XRE_main", (NSFuncPtr*) &XRE_main },
162 { nullptr, nullptr }
165 static nsresult
166 GetXULRunnerDir(const char *argv0, nsIFile* *aResult)
168 nsresult rv;
170 nsCOMPtr<nsIFile> appFile;
171 rv = BinaryPath::GetFile(argv0, getter_AddRefs(appFile));
172 if (NS_FAILED(rv)) {
173 Output(true, "Could not find XULRunner application path.\n");
174 return rv;
177 rv = appFile->GetParent(aResult);
178 if (NS_FAILED(rv)) {
179 Output(true, "Could not find XULRunner installation dir.\n");
181 return rv;
184 static int
185 InstallXULApp(nsIFile* aXULRunnerDir,
186 const char *aAppLocation,
187 const char *aInstallTo,
188 const char *aLeafName)
190 nsCOMPtr<nsIFile> appLocation;
191 nsCOMPtr<nsIFile> installTo;
192 nsString leafName;
194 nsresult rv = XRE_GetFileFromPath(aAppLocation, getter_AddRefs(appLocation));
195 if (NS_FAILED(rv))
196 return 2;
198 if (aInstallTo) {
199 rv = XRE_GetFileFromPath(aInstallTo, getter_AddRefs(installTo));
200 if (NS_FAILED(rv))
201 return 2;
204 if (aLeafName)
205 NS_CStringToUTF16(nsDependentCString(aLeafName),
206 NS_CSTRING_ENCODING_NATIVE_FILESYSTEM, leafName);
208 rv = NS_InitXPCOM2(nullptr, aXULRunnerDir, nullptr);
209 if (NS_FAILED(rv))
210 return 3;
213 // Scope our COMPtr to avoid holding XPCOM refs beyond xpcom shutdown
214 nsCOMPtr<nsIXULAppInstall> install
215 (do_GetService("@mozilla.org/xulrunner/app-install-service;1"));
216 if (!install) {
217 rv = NS_ERROR_FAILURE;
219 else {
220 rv = install->InstallApplication(appLocation, installTo, leafName);
224 NS_ShutdownXPCOM(nullptr);
226 if (NS_FAILED(rv))
227 return 3;
229 return 0;
232 class AutoAppData
234 public:
235 AutoAppData(nsIFile* aINIFile) : mAppData(nullptr) {
236 nsresult rv = XRE_CreateAppData(aINIFile, &mAppData);
237 if (NS_FAILED(rv))
238 mAppData = nullptr;
240 ~AutoAppData() {
241 if (mAppData)
242 XRE_FreeAppData(mAppData);
245 operator nsXREAppData*() const { return mAppData; }
246 nsXREAppData* operator -> () const { return mAppData; }
248 private:
249 nsXREAppData* mAppData;
252 int main(int argc, char* argv[])
254 char exePath[MAXPATHLEN];
255 nsresult rv = mozilla::BinaryPath::Get(argv[0], exePath);
256 if (NS_FAILED(rv)) {
257 Output(true, "Couldn't calculate the application directory.\n");
258 return 255;
261 char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]);
262 if (!lastSlash || (size_t(lastSlash - exePath) > MAXPATHLEN - sizeof(XPCOM_DLL) - 1))
263 return 255;
265 strcpy(++lastSlash, XPCOM_DLL);
267 rv = XPCOMGlueStartup(exePath);
268 if (NS_FAILED(rv)) {
269 Output(true, "Couldn't load XPCOM.\n");
270 return 255;
273 if (argc > 1 && (IsArg(argv[1], "h") ||
274 IsArg(argv[1], "help") ||
275 IsArg(argv[1], "?")))
277 Usage(argv[0]);
278 return 0;
281 if (argc == 2 && (IsArg(argv[1], "v") || IsArg(argv[1], "version")))
283 nsAutoCString milestone;
284 nsAutoCString version;
285 GetGREVersion(argv[0], &milestone, &version);
286 Output(false, "Mozilla XULRunner %s - %s\n",
287 milestone.get(), version.get());
288 return 0;
291 rv = XPCOMGlueLoadXULFunctions(kXULFuncs);
292 if (NS_FAILED(rv)) {
293 Output(true, "Couldn't load XRE functions.\n");
294 return 255;
297 if (argc > 1) {
298 nsAutoCString milestone;
299 rv = GetGREVersion(argv[0], &milestone, nullptr);
300 if (NS_FAILED(rv))
301 return 2;
303 if (IsArg(argv[1], "gre-version")) {
304 if (argc != 2) {
305 Usage(argv[0]);
306 return 1;
309 printf("%s\n", milestone.get());
310 return 0;
313 if (IsArg(argv[1], "install-app")) {
314 if (argc < 3 || argc > 5) {
315 Usage(argv[0]);
316 return 1;
319 char *appLocation = argv[2];
321 char *installTo = nullptr;
322 if (argc > 3) {
323 installTo = argv[3];
324 if (!*installTo) // left blank?
325 installTo = nullptr;
328 char *leafName = nullptr;
329 if (argc > 4) {
330 leafName = argv[4];
331 if (!*leafName)
332 leafName = nullptr;
335 nsCOMPtr<nsIFile> regDir;
336 rv = GetXULRunnerDir(argv[0], getter_AddRefs(regDir));
337 if (NS_FAILED(rv))
338 return 2;
340 return InstallXULApp(regDir, appLocation, installTo, leafName);
344 const char *appDataFile = getenv("XUL_APP_FILE");
346 if (!(appDataFile && *appDataFile)) {
347 if (argc < 2) {
348 Usage(argv[0]);
349 return 1;
352 if (IsArg(argv[1], "app")) {
353 if (argc == 2) {
354 Usage(argv[0]);
355 return 1;
357 argv[1] = argv[0];
358 ++argv;
359 --argc;
362 appDataFile = argv[1];
363 argv[1] = argv[0];
364 ++argv;
365 --argc;
367 static char kAppEnv[MAXPATHLEN];
368 snprintf(kAppEnv, MAXPATHLEN, "XUL_APP_FILE=%s", appDataFile);
369 putenv(kAppEnv);
372 nsCOMPtr<nsIFile> appDataLF;
373 rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appDataLF));
374 if (NS_FAILED(rv)) {
375 Output(true, "Error: unrecognized application.ini path.\n");
376 return 2;
379 AutoAppData appData(appDataLF);
380 if (!appData) {
381 Output(true, "Error: couldn't parse application.ini.\n");
382 return 2;
385 return XRE_main(argc, argv, appData, 0);