Bumping manifests a=b2g-bump
[gecko.git] / xulrunner / stub / nsXULStub.cpp
blob61dbab90d464b2235e05c9e679241615541866c4
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 "nsXPCOMGlue.h"
6 #include "nsINIParser.h"
7 #include "nsXPCOMPrivate.h" // for XP MAXPATHLEN
8 #include "nsXULAppAPI.h"
9 #include "nsIFile.h"
11 #include <stdarg.h>
13 #ifdef XP_WIN
14 #include <windows.h>
15 #include <io.h>
16 #define snprintf _snprintf
17 #define vsnprintf _vsnprintf
18 #define strcasecmp _stricmp
19 #define PATH_SEPARATOR_CHAR '\\'
20 #define R_OK 04
21 #elif defined(XP_MACOSX)
22 #include <unistd.h>
23 #include <sys/stat.h>
24 #include <CoreFoundation/CoreFoundation.h>
25 #define PATH_SEPARATOR_CHAR '/'
26 #else
27 #include <unistd.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #define PATH_SEPARATOR_CHAR '/'
31 #endif
33 #ifdef XP_WIN
34 #define XRE_DONT_PROTECT_DLL_LOAD
35 #include "nsWindowsWMain.cpp"
36 #endif
38 #define VERSION_MAXLEN 128
40 static void Output(bool isError, const char *fmt, ... )
42 va_list ap;
43 va_start(ap, fmt);
45 #if (defined(XP_WIN) && !MOZ_WINCONSOLE)
46 char msg[2048];
48 vsnprintf(msg, sizeof(msg), fmt, ap);
50 UINT flags = MB_OK;
51 if (isError)
52 flags |= MB_ICONERROR;
53 else
54 flags |= MB_ICONINFORMATION;
56 wchar_t wide_msg[1024];
57 MultiByteToWideChar(CP_ACP,
59 msg,
60 -1,
61 wide_msg,
62 sizeof(wide_msg) / sizeof(wchar_t));
64 MessageBoxW(nullptr, wide_msg, L"XULRunner", flags);
65 #else
66 vfprintf(stderr, fmt, ap);
67 #endif
69 va_end(ap);
72 /**
73 * Return true if |arg| matches the given argument name.
75 static bool IsArg(const char* arg, const char* s)
77 if (*arg == '-')
79 if (*++arg == '-')
80 ++arg;
81 return !strcasecmp(arg, s);
84 #if defined(XP_WIN)
85 if (*arg == '/')
86 return !strcasecmp(++arg, s);
87 #endif
89 return false;
92 /**
93 * Return true if |aDir| is a valid file/directory.
95 static bool FolderExists(const char* aDir)
97 #ifdef XP_WIN
98 wchar_t wideDir[MAX_PATH];
99 MultiByteToWideChar(CP_UTF8, 0, aDir, -1, wideDir, MAX_PATH);
100 DWORD fileAttrs = GetFileAttributesW(wideDir);
101 return fileAttrs != INVALID_FILE_ATTRIBUTES;
102 #else
103 return access(aDir, R_OK) == 0;
104 #endif
107 static nsresult GetRealPath(const char* appDataFile, char* *aResult)
109 #ifdef XP_WIN
110 wchar_t wAppDataFile[MAX_PATH];
111 wchar_t wIniPath[MAX_PATH];
112 MultiByteToWideChar(CP_UTF8, 0, appDataFile, -1, wAppDataFile, MAX_PATH);
113 _wfullpath(wIniPath, wAppDataFile, MAX_PATH);
114 WideCharToMultiByte(CP_UTF8, 0, wIniPath, -1, *aResult, MAX_PATH, 0, 0);
115 #else
116 struct stat fileStat;
117 if (!realpath(appDataFile, *aResult) || stat(*aResult, &fileStat))
118 return NS_ERROR_FAILURE;
119 #endif
120 if (!*aResult || !**aResult)
121 return NS_ERROR_FAILURE;
123 return NS_OK;
126 class AutoAppData
128 public:
129 AutoAppData(nsIFile* aINIFile) : mAppData(nullptr) {
130 nsresult rv = XRE_CreateAppData(aINIFile, &mAppData);
131 if (NS_FAILED(rv))
132 mAppData = nullptr;
134 ~AutoAppData() {
135 if (mAppData)
136 XRE_FreeAppData(mAppData);
139 operator nsXREAppData*() const { return mAppData; }
140 nsXREAppData* operator -> () const { return mAppData; }
142 private:
143 nsXREAppData* mAppData;
146 XRE_CreateAppDataType XRE_CreateAppData;
147 XRE_FreeAppDataType XRE_FreeAppData;
148 XRE_mainType XRE_main;
151 main(int argc, char **argv)
153 nsresult rv;
154 char *lastSlash;
156 char iniPath[MAXPATHLEN];
157 char tmpPath[MAXPATHLEN];
158 char greDir[MAXPATHLEN];
159 bool greFound = false;
161 #if defined(XP_MACOSX)
162 CFBundleRef appBundle = CFBundleGetMainBundle();
163 if (!appBundle)
164 return 1;
166 CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(appBundle);
167 if (!resourcesURL)
168 return 1;
170 CFURLRef absResourcesURL = CFURLCopyAbsoluteURL(resourcesURL);
171 CFRelease(resourcesURL);
172 if (!absResourcesURL)
173 return 1;
175 CFURLRef iniFileURL =
176 CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
177 absResourcesURL,
178 CFSTR("application.ini"),
179 false);
180 CFRelease(absResourcesURL);
181 if (!iniFileURL)
182 return 1;
184 CFStringRef iniPathStr =
185 CFURLCopyFileSystemPath(iniFileURL, kCFURLPOSIXPathStyle);
186 CFRelease(iniFileURL);
187 if (!iniPathStr)
188 return 1;
190 CFStringGetCString(iniPathStr, iniPath, sizeof(iniPath),
191 kCFStringEncodingUTF8);
192 CFRelease(iniPathStr);
194 #else
196 #ifdef XP_WIN
197 wchar_t wide_path[MAX_PATH];
198 if (!::GetModuleFileNameW(nullptr, wide_path, MAX_PATH))
199 return 1;
201 WideCharToMultiByte(CP_UTF8, 0, wide_path,-1,
202 iniPath, MAX_PATH, nullptr, nullptr);
204 #else
205 // on unix, there is no official way to get the path of the current binary.
206 // instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to
207 // multiple applications, we will try a series of techniques:
209 // 1) use realpath() on argv[0], which works unless we're loaded from the
210 // PATH
211 // 2) manually walk through the PATH and look for ourself
212 // 3) give up
214 struct stat fileStat;
215 strncpy(tmpPath, argv[0], sizeof(tmpPath));
216 lastSlash = strrchr(tmpPath, '/');
217 if (lastSlash) {
218 *lastSlash = 0;
219 realpath(tmpPath, iniPath);
220 } else {
221 const char *path = getenv("PATH");
222 if (!path)
223 return 1;
225 char *pathdup = strdup(path);
226 if (!pathdup)
227 return 1;
229 bool found = false;
230 char *token = strtok(pathdup, ":");
231 while (token) {
232 sprintf(tmpPath, "%s/%s", token, argv[0]);
233 if (stat(tmpPath, &fileStat) == 0) {
234 found = true;
235 lastSlash = strrchr(tmpPath, '/');
236 *lastSlash = 0;
237 realpath(tmpPath, iniPath);
238 break;
240 token = strtok(nullptr, ":");
242 free (pathdup);
243 if (!found)
244 return 1;
246 lastSlash = iniPath + strlen(iniPath);
247 *lastSlash = '/';
248 #endif
250 #ifndef XP_UNIX
251 lastSlash = strrchr(iniPath, PATH_SEPARATOR_CHAR);
252 if (!lastSlash)
253 return 1;
254 #endif
256 *(++lastSlash) = '\0';
258 // On Linux/Win, look for XULRunner in appdir/xulrunner
260 snprintf(greDir, sizeof(greDir),
261 "%sxulrunner" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL,
262 iniPath);
264 greFound = FolderExists(greDir);
266 #ifdef XP_UNIX
267 if (greFound) {
268 char resolved_greDir[MAXPATHLEN] = "";
269 if (realpath(greDir, resolved_greDir) && *resolved_greDir) {
270 strncpy(greDir, resolved_greDir, MAXPATHLEN);
273 #endif
275 strncpy(lastSlash, "application.ini", sizeof(iniPath) - (lastSlash - iniPath));
277 #endif
279 // If -app parameter was passed in, it is now time to take it under
280 // consideration.
281 const char *appDataFile;
282 appDataFile = getenv("XUL_APP_FILE");
283 if (!appDataFile || !*appDataFile)
284 if (argc > 1 && IsArg(argv[1], "app")) {
285 if (argc == 2) {
286 Output(false, "specify APP-FILE (optional)\n");
287 return 1;
289 argv[1] = argv[0];
290 ++argv;
291 --argc;
293 appDataFile = argv[1];
294 argv[1] = argv[0];
295 ++argv;
296 --argc;
298 char kAppEnv[MAXPATHLEN];
299 snprintf(kAppEnv, MAXPATHLEN, "XUL_APP_FILE=%s", appDataFile);
300 if (putenv(kAppEnv))
301 Output(false, "Couldn't set %s.\n", kAppEnv);
303 char *result = (char*) calloc(sizeof(char), MAXPATHLEN);
304 if (NS_FAILED(GetRealPath(appDataFile, &result))) {
305 Output(true, "Invalid application.ini path.\n");
306 return 1;
309 // We have a valid application.ini path passed in to the -app parameter
310 // but not yet a valid greDir, so lets look for it also on the same folder
311 // as the stub.
312 if (!greFound) {
313 lastSlash = strrchr(iniPath, PATH_SEPARATOR_CHAR);
314 if (!lastSlash)
315 return 1;
317 *(++lastSlash) = '\0';
319 snprintf(greDir, sizeof(greDir), "%s" XPCOM_DLL, iniPath);
320 greFound = FolderExists(greDir);
323 // copy it back.
324 strcpy(iniPath, result);
327 nsINIParser parser;
328 rv = parser.Init(iniPath);
329 if (NS_FAILED(rv)) {
330 fprintf(stderr, "Could not read application.ini\n");
331 return 1;
334 if (!greFound) {
335 #ifdef XP_MACOSX
336 // Check for <bundle>/Contents/Frameworks/XUL.framework/Versions/Current/libmozglue.dylib
337 CFURLRef fwurl = CFBundleCopyPrivateFrameworksURL(appBundle);
338 CFURLRef absfwurl = nullptr;
339 if (fwurl) {
340 absfwurl = CFURLCopyAbsoluteURL(fwurl);
341 CFRelease(fwurl);
344 if (absfwurl) {
345 CFURLRef xulurl =
346 CFURLCreateCopyAppendingPathComponent(nullptr, absfwurl,
347 CFSTR("XUL.framework/Versions/Current"),
348 true);
350 if (xulurl) {
351 CFURLRef xpcomurl =
352 CFURLCreateCopyAppendingPathComponent(nullptr, xulurl,
353 CFSTR("libmozglue.dylib"),
354 false);
356 if (xpcomurl) {
357 char tbuffer[MAXPATHLEN];
359 if (CFURLGetFileSystemRepresentation(xpcomurl, true,
360 (UInt8*) tbuffer,
361 sizeof(tbuffer)) &&
362 access(tbuffer, R_OK | X_OK) == 0) {
363 if (realpath(tbuffer, greDir)) {
364 greFound = true;
366 else {
367 greDir[0] = '\0';
371 CFRelease(xpcomurl);
374 CFRelease(xulurl);
377 CFRelease(absfwurl);
379 #endif
380 if (!greFound) {
381 Output(false, "Could not find the Mozilla runtime.\n");
382 return 1;
386 rv = XPCOMGlueStartup(greDir);
387 if (NS_FAILED(rv)) {
388 if (rv == NS_ERROR_OUT_OF_MEMORY) {
389 char applicationName[2000] = "this application";
390 parser.GetString("App", "Name", applicationName, sizeof(applicationName));
391 Output(true, "Not enough memory available to start %s.\n",
392 applicationName);
393 } else {
394 Output(true, "Couldn't load XPCOM.\n");
396 return 1;
399 static const nsDynamicFunctionLoad kXULFuncs[] = {
400 { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData },
401 { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData },
402 { "XRE_main", (NSFuncPtr*) &XRE_main },
403 { nullptr, nullptr }
406 rv = XPCOMGlueLoadXULFunctions(kXULFuncs);
407 if (NS_FAILED(rv)) {
408 Output(true, "Couldn't load XRE functions.\n");
409 return 1;
412 NS_LogInit();
414 int retval;
416 { // Scope COMPtr and AutoAppData
417 nsCOMPtr<nsIFile> iniFile;
418 #ifdef XP_WIN
419 // On Windows iniPath is UTF-8 encoded so we need to convert it.
420 rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(iniPath), false,
421 getter_AddRefs(iniFile));
422 #else
423 rv = NS_NewNativeLocalFile(nsDependentCString(iniPath), false,
424 getter_AddRefs(iniFile));
425 #endif
426 if (NS_FAILED(rv)) {
427 Output(true, "Couldn't find application.ini file.\n");
428 return 1;
431 AutoAppData appData(iniFile);
432 if (!appData) {
433 Output(true, "Error: couldn't parse application.ini.\n");
434 return 1;
437 NS_ASSERTION(appData->directory, "Failed to get app directory.");
439 if (!appData->xreDirectory) {
440 // chop "libxul.so" off the GRE path
441 lastSlash = strrchr(greDir, PATH_SEPARATOR_CHAR);
442 if (lastSlash) {
443 *lastSlash = '\0';
445 #ifdef XP_WIN
446 // same as iniPath.
447 NS_NewLocalFile(NS_ConvertUTF8toUTF16(greDir), false,
448 &appData->xreDirectory);
449 #else
450 NS_NewNativeLocalFile(nsDependentCString(greDir), false,
451 &appData->xreDirectory);
452 #endif
455 retval = XRE_main(argc, argv, appData, 0);
458 NS_LogTerm();
460 return retval;