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"
16 #define snprintf _snprintf
17 #define vsnprintf _vsnprintf
18 #define strcasecmp _stricmp
19 #define PATH_SEPARATOR_CHAR '\\'
21 #elif defined(XP_MACOSX)
24 #include <CoreFoundation/CoreFoundation.h>
25 #define PATH_SEPARATOR_CHAR '/'
28 #include <sys/types.h>
30 #define PATH_SEPARATOR_CHAR '/'
34 #define XRE_DONT_PROTECT_DLL_LOAD
35 #include "nsWindowsWMain.cpp"
38 #define VERSION_MAXLEN 128
40 static void Output(bool isError
, const char *fmt
, ... )
45 #if (defined(XP_WIN) && !MOZ_WINCONSOLE)
48 vsnprintf(msg
, sizeof(msg
), fmt
, ap
);
52 flags
|= MB_ICONERROR
;
54 flags
|= MB_ICONINFORMATION
;
56 wchar_t wide_msg
[1024];
57 MultiByteToWideChar(CP_ACP
,
62 sizeof(wide_msg
) / sizeof(wchar_t));
64 MessageBoxW(nullptr, wide_msg
, L
"XULRunner", flags
);
66 vfprintf(stderr
, fmt
, ap
);
73 * Return true if |arg| matches the given argument name.
75 static bool IsArg(const char* arg
, const char* s
)
81 return !strcasecmp(arg
, s
);
86 return !strcasecmp(++arg
, s
);
93 * Return true if |aDir| is a valid file/directory.
95 static bool FolderExists(const char* aDir
)
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
;
103 return access(aDir
, R_OK
) == 0;
107 static nsresult
GetRealPath(const char* appDataFile
, char* *aResult
)
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);
116 struct stat fileStat
;
117 if (!realpath(appDataFile
, *aResult
) || stat(*aResult
, &fileStat
))
118 return NS_ERROR_FAILURE
;
120 if (!*aResult
|| !**aResult
)
121 return NS_ERROR_FAILURE
;
129 AutoAppData(nsIFile
* aINIFile
) : mAppData(nullptr) {
130 nsresult rv
= XRE_CreateAppData(aINIFile
, &mAppData
);
136 XRE_FreeAppData(mAppData
);
139 operator nsXREAppData
*() const { return mAppData
; }
140 nsXREAppData
* operator -> () const { return mAppData
; }
143 nsXREAppData
* mAppData
;
146 XRE_CreateAppDataType XRE_CreateAppData
;
147 XRE_FreeAppDataType XRE_FreeAppData
;
148 XRE_mainType XRE_main
;
151 main(int argc
, char **argv
)
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();
166 CFURLRef resourcesURL
= CFBundleCopyResourcesDirectoryURL(appBundle
);
170 CFURLRef absResourcesURL
= CFURLCopyAbsoluteURL(resourcesURL
);
171 CFRelease(resourcesURL
);
172 if (!absResourcesURL
)
175 CFURLRef iniFileURL
=
176 CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault
,
178 CFSTR("application.ini"),
180 CFRelease(absResourcesURL
);
184 CFStringRef iniPathStr
=
185 CFURLCopyFileSystemPath(iniFileURL
, kCFURLPOSIXPathStyle
);
186 CFRelease(iniFileURL
);
190 CFStringGetCString(iniPathStr
, iniPath
, sizeof(iniPath
),
191 kCFStringEncodingUTF8
);
192 CFRelease(iniPathStr
);
197 wchar_t wide_path
[MAX_PATH
];
198 if (!::GetModuleFileNameW(nullptr, wide_path
, MAX_PATH
))
201 WideCharToMultiByte(CP_UTF8
, 0, wide_path
,-1,
202 iniPath
, MAX_PATH
, nullptr, nullptr);
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
211 // 2) manually walk through the PATH and look for ourself
214 struct stat fileStat
;
215 strncpy(tmpPath
, argv
[0], sizeof(tmpPath
));
216 lastSlash
= strrchr(tmpPath
, '/');
219 realpath(tmpPath
, iniPath
);
221 const char *path
= getenv("PATH");
225 char *pathdup
= strdup(path
);
230 char *token
= strtok(pathdup
, ":");
232 sprintf(tmpPath
, "%s/%s", token
, argv
[0]);
233 if (stat(tmpPath
, &fileStat
) == 0) {
235 lastSlash
= strrchr(tmpPath
, '/');
237 realpath(tmpPath
, iniPath
);
240 token
= strtok(nullptr, ":");
246 lastSlash
= iniPath
+ strlen(iniPath
);
251 lastSlash
= strrchr(iniPath
, PATH_SEPARATOR_CHAR
);
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
,
264 greFound
= FolderExists(greDir
);
268 char resolved_greDir
[MAXPATHLEN
] = "";
269 if (realpath(greDir
, resolved_greDir
) && *resolved_greDir
) {
270 strncpy(greDir
, resolved_greDir
, MAXPATHLEN
);
275 strncpy(lastSlash
, "application.ini", sizeof(iniPath
) - (lastSlash
- iniPath
));
279 // If -app parameter was passed in, it is now time to take it under
281 const char *appDataFile
;
282 appDataFile
= getenv("XUL_APP_FILE");
283 if (!appDataFile
|| !*appDataFile
)
284 if (argc
> 1 && IsArg(argv
[1], "app")) {
286 Output(false, "specify APP-FILE (optional)\n");
293 appDataFile
= argv
[1];
298 char kAppEnv
[MAXPATHLEN
];
299 snprintf(kAppEnv
, MAXPATHLEN
, "XUL_APP_FILE=%s", appDataFile
);
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");
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
313 lastSlash
= strrchr(iniPath
, PATH_SEPARATOR_CHAR
);
317 *(++lastSlash
) = '\0';
319 snprintf(greDir
, sizeof(greDir
), "%s" XPCOM_DLL
, iniPath
);
320 greFound
= FolderExists(greDir
);
324 strcpy(iniPath
, result
);
328 rv
= parser
.Init(iniPath
);
330 fprintf(stderr
, "Could not read application.ini\n");
336 // Check for <bundle>/Contents/Frameworks/XUL.framework/Versions/Current/libmozglue.dylib
337 CFURLRef fwurl
= CFBundleCopyPrivateFrameworksURL(appBundle
);
338 CFURLRef absfwurl
= nullptr;
340 absfwurl
= CFURLCopyAbsoluteURL(fwurl
);
346 CFURLCreateCopyAppendingPathComponent(nullptr, absfwurl
,
347 CFSTR("XUL.framework/Versions/Current"),
352 CFURLCreateCopyAppendingPathComponent(nullptr, xulurl
,
353 CFSTR("libmozglue.dylib"),
357 char tbuffer
[MAXPATHLEN
];
359 if (CFURLGetFileSystemRepresentation(xpcomurl
, true,
362 access(tbuffer
, R_OK
| X_OK
) == 0) {
363 if (realpath(tbuffer
, greDir
)) {
381 Output(false, "Could not find the Mozilla runtime.\n");
386 rv
= XPCOMGlueStartup(greDir
);
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",
394 Output(true, "Couldn't load XPCOM.\n");
399 static const nsDynamicFunctionLoad kXULFuncs
[] = {
400 { "XRE_CreateAppData", (NSFuncPtr
*) &XRE_CreateAppData
},
401 { "XRE_FreeAppData", (NSFuncPtr
*) &XRE_FreeAppData
},
402 { "XRE_main", (NSFuncPtr
*) &XRE_main
},
406 rv
= XPCOMGlueLoadXULFunctions(kXULFuncs
);
408 Output(true, "Couldn't load XRE functions.\n");
416 { // Scope COMPtr and AutoAppData
417 nsCOMPtr
<nsIFile
> iniFile
;
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
));
423 rv
= NS_NewNativeLocalFile(nsDependentCString(iniPath
), false,
424 getter_AddRefs(iniFile
));
427 Output(true, "Couldn't find application.ini file.\n");
431 AutoAppData
appData(iniFile
);
433 Output(true, "Error: couldn't parse application.ini.\n");
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
);
447 NS_NewLocalFile(NS_ConvertUTF8toUTF16(greDir
), false,
448 &appData
->xreDirectory
);
450 NS_NewNativeLocalFile(nsDependentCString(greDir
), false,
451 &appData
->xreDirectory
);
455 retval
= XRE_main(argc
, argv
, appData
, 0);