|
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/. */ |
|
4 |
|
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 |
|
14 |
|
15 #include "nsAppRunner.h" |
|
16 #include "nsIFile.h" |
|
17 #include "nsCOMPtr.h" |
|
18 #include "nsMemory.h" |
|
19 #include "nsCRTGlue.h" |
|
20 #include "nsStringAPI.h" |
|
21 #include "nsServiceManagerUtils.h" |
|
22 #include "plstr.h" |
|
23 #include "prprf.h" |
|
24 #include "prenv.h" |
|
25 #include "nsINIParser.h" |
|
26 |
|
27 #ifdef XP_WIN |
|
28 #include "nsWindowsWMain.cpp" |
|
29 #endif |
|
30 |
|
31 #include "BinaryPath.h" |
|
32 |
|
33 #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL |
|
34 |
|
35 using namespace mozilla; |
|
36 |
|
37 /** |
|
38 * Output a string to the user. This method is really only meant to be used to |
|
39 * output last-ditch error messages designed for developers NOT END USERS. |
|
40 * |
|
41 * @param isError |
|
42 * Pass true to indicate severe errors. |
|
43 * @param fmt |
|
44 * printf-style format string followed by arguments. |
|
45 */ |
|
46 static void Output(bool isError, const char *fmt, ... ) |
|
47 { |
|
48 va_list ap; |
|
49 va_start(ap, fmt); |
|
50 |
|
51 #if (defined(XP_WIN) && !MOZ_WINCONSOLE) |
|
52 char16_t msg[2048]; |
|
53 _vsnwprintf(msg, sizeof(msg)/sizeof(msg[0]), NS_ConvertUTF8toUTF16(fmt).get(), ap); |
|
54 |
|
55 UINT flags = MB_OK; |
|
56 if (isError) |
|
57 flags |= MB_ICONERROR; |
|
58 else |
|
59 flags |= MB_ICONINFORMATION; |
|
60 |
|
61 MessageBoxW(nullptr, msg, L"XULRunner", flags); |
|
62 #else |
|
63 vfprintf(stderr, fmt, ap); |
|
64 #endif |
|
65 |
|
66 va_end(ap); |
|
67 } |
|
68 |
|
69 /** |
|
70 * Return true if |arg| matches the given argument name. |
|
71 */ |
|
72 static bool IsArg(const char* arg, const char* s) |
|
73 { |
|
74 if (*arg == '-') |
|
75 { |
|
76 if (*++arg == '-') |
|
77 ++arg; |
|
78 return !strcasecmp(arg, s); |
|
79 } |
|
80 |
|
81 #if defined(XP_WIN) |
|
82 if (*arg == '/') |
|
83 return !strcasecmp(++arg, s); |
|
84 #endif |
|
85 |
|
86 return false; |
|
87 } |
|
88 |
|
89 static nsresult |
|
90 GetGREVersion(const char *argv0, |
|
91 nsACString *aMilestone, |
|
92 nsACString *aVersion) |
|
93 { |
|
94 if (aMilestone) |
|
95 aMilestone->Assign("<Error>"); |
|
96 if (aVersion) |
|
97 aVersion->Assign("<Error>"); |
|
98 |
|
99 nsCOMPtr<nsIFile> iniFile; |
|
100 nsresult rv = BinaryPath::GetFile(argv0, getter_AddRefs(iniFile)); |
|
101 if (NS_FAILED(rv)) |
|
102 return rv; |
|
103 |
|
104 iniFile->SetNativeLeafName(NS_LITERAL_CSTRING("platform.ini")); |
|
105 |
|
106 nsINIParser parser; |
|
107 rv = parser.Init(iniFile); |
|
108 if (NS_FAILED(rv)) |
|
109 return rv; |
|
110 |
|
111 if (aMilestone) { |
|
112 rv = parser.GetString("Build", "Milestone", *aMilestone); |
|
113 if (NS_FAILED(rv)) |
|
114 return rv; |
|
115 } |
|
116 if (aVersion) { |
|
117 rv = parser.GetString("Build", "BuildID", *aVersion); |
|
118 if (NS_FAILED(rv)) |
|
119 return rv; |
|
120 } |
|
121 return NS_OK; |
|
122 } |
|
123 |
|
124 /** |
|
125 * A helper class which calls NS_LogInit/NS_LogTerm in its scope. |
|
126 */ |
|
127 class ScopedLogging |
|
128 { |
|
129 public: |
|
130 ScopedLogging() { NS_LogInit(); } |
|
131 ~ScopedLogging() { NS_LogTerm(); } |
|
132 }; |
|
133 |
|
134 static void Usage(const char *argv0) |
|
135 { |
|
136 nsAutoCString milestone; |
|
137 GetGREVersion(argv0, &milestone, nullptr); |
|
138 |
|
139 // display additional information (XXX make localizable?) |
|
140 Output(false, |
|
141 "Mozilla XULRunner %s\n\n" |
|
142 "Usage: " XULRUNNER_PROGNAME " [OPTIONS]\n" |
|
143 " " XULRUNNER_PROGNAME " APP-FILE [APP-OPTIONS...]\n" |
|
144 "\n" |
|
145 "OPTIONS\n" |
|
146 " --app specify APP-FILE (optional)\n" |
|
147 " -h, --help show this message\n" |
|
148 " -v, --version show version\n" |
|
149 " --gre-version print the GRE version string on stdout\n" |
|
150 "\n" |
|
151 "APP-FILE\n" |
|
152 " Application initialization file.\n" |
|
153 "\n" |
|
154 "APP-OPTIONS\n" |
|
155 " Application specific options.\n", |
|
156 milestone.get()); |
|
157 } |
|
158 |
|
159 XRE_GetFileFromPathType XRE_GetFileFromPath; |
|
160 XRE_CreateAppDataType XRE_CreateAppData; |
|
161 XRE_FreeAppDataType XRE_FreeAppData; |
|
162 XRE_mainType XRE_main; |
|
163 |
|
164 static const nsDynamicFunctionLoad kXULFuncs[] = { |
|
165 { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath }, |
|
166 { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData }, |
|
167 { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData }, |
|
168 { "XRE_main", (NSFuncPtr*) &XRE_main }, |
|
169 { nullptr, nullptr } |
|
170 }; |
|
171 |
|
172 class AutoAppData |
|
173 { |
|
174 public: |
|
175 AutoAppData(nsIFile* aINIFile) : mAppData(nullptr) { |
|
176 nsresult rv = XRE_CreateAppData(aINIFile, &mAppData); |
|
177 if (NS_FAILED(rv)) |
|
178 mAppData = nullptr; |
|
179 } |
|
180 ~AutoAppData() { |
|
181 if (mAppData) |
|
182 XRE_FreeAppData(mAppData); |
|
183 } |
|
184 |
|
185 operator nsXREAppData*() const { return mAppData; } |
|
186 nsXREAppData* operator -> () const { return mAppData; } |
|
187 |
|
188 private: |
|
189 nsXREAppData* mAppData; |
|
190 }; |
|
191 |
|
192 int main(int argc, char* argv[]) |
|
193 { |
|
194 char exePath[MAXPATHLEN]; |
|
195 nsresult rv = mozilla::BinaryPath::Get(argv[0], exePath); |
|
196 if (NS_FAILED(rv)) { |
|
197 Output(true, "Couldn't calculate the application directory.\n"); |
|
198 return 255; |
|
199 } |
|
200 |
|
201 char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]); |
|
202 if (!lastSlash || (size_t(lastSlash - exePath) > MAXPATHLEN - sizeof(XPCOM_DLL) - 1)) |
|
203 return 255; |
|
204 |
|
205 strcpy(++lastSlash, XPCOM_DLL); |
|
206 |
|
207 rv = XPCOMGlueStartup(exePath); |
|
208 if (NS_FAILED(rv)) { |
|
209 Output(true, "Couldn't load XPCOM.\n"); |
|
210 return 255; |
|
211 } |
|
212 |
|
213 ScopedLogging log; |
|
214 |
|
215 if (argc > 1 && (IsArg(argv[1], "h") || |
|
216 IsArg(argv[1], "help") || |
|
217 IsArg(argv[1], "?"))) |
|
218 { |
|
219 Usage(argv[0]); |
|
220 return 0; |
|
221 } |
|
222 |
|
223 if (argc == 2 && (IsArg(argv[1], "v") || IsArg(argv[1], "version"))) |
|
224 { |
|
225 nsAutoCString milestone; |
|
226 nsAutoCString version; |
|
227 GetGREVersion(argv[0], &milestone, &version); |
|
228 Output(false, "Mozilla XULRunner %s - %s\n", |
|
229 milestone.get(), version.get()); |
|
230 return 0; |
|
231 } |
|
232 |
|
233 rv = XPCOMGlueLoadXULFunctions(kXULFuncs); |
|
234 if (NS_FAILED(rv)) { |
|
235 Output(true, "Couldn't load XRE functions.\n"); |
|
236 return 255; |
|
237 } |
|
238 |
|
239 if (argc > 1) { |
|
240 nsAutoCString milestone; |
|
241 rv = GetGREVersion(argv[0], &milestone, nullptr); |
|
242 if (NS_FAILED(rv)) |
|
243 return 2; |
|
244 |
|
245 if (IsArg(argv[1], "gre-version")) { |
|
246 if (argc != 2) { |
|
247 Usage(argv[0]); |
|
248 return 1; |
|
249 } |
|
250 |
|
251 printf("%s\n", milestone.get()); |
|
252 return 0; |
|
253 } |
|
254 |
|
255 if (IsArg(argv[1], "install-app")) { |
|
256 Output(true, "--install-app support has been removed. Use 'python install-app.py' instead.\n"); |
|
257 return 1; |
|
258 } |
|
259 } |
|
260 |
|
261 const char *appDataFile = getenv("XUL_APP_FILE"); |
|
262 |
|
263 if (!(appDataFile && *appDataFile)) { |
|
264 if (argc < 2) { |
|
265 Usage(argv[0]); |
|
266 return 1; |
|
267 } |
|
268 |
|
269 if (IsArg(argv[1], "app")) { |
|
270 if (argc == 2) { |
|
271 Usage(argv[0]); |
|
272 return 1; |
|
273 } |
|
274 argv[1] = argv[0]; |
|
275 ++argv; |
|
276 --argc; |
|
277 } |
|
278 |
|
279 appDataFile = argv[1]; |
|
280 argv[1] = argv[0]; |
|
281 ++argv; |
|
282 --argc; |
|
283 |
|
284 static char kAppEnv[MAXPATHLEN]; |
|
285 snprintf(kAppEnv, MAXPATHLEN, "XUL_APP_FILE=%s", appDataFile); |
|
286 putenv(kAppEnv); |
|
287 } |
|
288 |
|
289 nsCOMPtr<nsIFile> appDataLF; |
|
290 rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appDataLF)); |
|
291 if (NS_FAILED(rv)) { |
|
292 Output(true, "Error: unrecognized application.ini path.\n"); |
|
293 return 2; |
|
294 } |
|
295 |
|
296 AutoAppData appData(appDataLF); |
|
297 if (!appData) { |
|
298 Output(true, "Error: couldn't parse application.ini.\n"); |
|
299 return 2; |
|
300 } |
|
301 |
|
302 return XRE_main(argc, argv, appData, 0); |
|
303 } |