1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=2 sw=4 et tw=80:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is Mozilla Communicator client code, released
18 : * March 31, 1998.
19 : *
20 : * The Initial Developer of the Original Code is
21 : * Netscape Communications Corporation.
22 : * Portions created by the Initial Developer are Copyright (C) 1998
23 : * the Initial Developer. All Rights Reserved.
24 : *
25 : * Contributor(s):
26 : * John Bandhauer <jband@netscape.com>
27 : * Pierre Phaneuf <pp@ludusdesign.com>
28 : * IBM Corp.
29 : * Dan Mosedale <dan.mosedale@oracle.com>
30 : * Serge Gautherie <sgautherie.bz@free.fr>
31 : *
32 : * Alternatively, the contents of this file may be used under the terms of
33 : * either of the GNU General Public License Version 2 or later (the "GPL"),
34 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
35 : * in which case the provisions of the GPL or the LGPL are applicable instead
36 : * of those above. If you wish to allow use of your version of this file only
37 : * under the terms of either the GPL or the LGPL, and not to allow others to
38 : * use your version of this file under the terms of the MPL, indicate your
39 : * decision by deleting the provisions above and replace them with the notice
40 : * and other provisions required by the GPL or the LGPL. If you do not delete
41 : * the provisions above, a recipient may use your version of this file under
42 : * the terms of any one of the MPL, the GPL or the LGPL.
43 : *
44 : * ***** END LICENSE BLOCK ***** */
45 :
46 : /* XPConnect JavaScript interactive shell. */
47 :
48 : #include <stdio.h>
49 :
50 : #include "mozilla/Util.h"
51 :
52 : #include "jsapi.h"
53 : #include "jsdbgapi.h"
54 : #include "jsfriendapi.h"
55 : #include "jsprf.h"
56 : #include "nsXULAppAPI.h"
57 : #include "nsServiceManagerUtils.h"
58 : #include "nsComponentManagerUtils.h"
59 : #include "nsStringAPI.h"
60 : #include "nsIXPConnect.h"
61 : #include "nsIXPCScriptable.h"
62 : #include "nsIInterfaceInfo.h"
63 : #include "nsIInterfaceInfoManager.h"
64 : #include "nsIXPCScriptable.h"
65 : #include "nsIServiceManager.h"
66 : #include "nsIComponentManager.h"
67 : #include "nsIComponentRegistrar.h"
68 : #include "nsILocalFile.h"
69 : #include "nsStringAPI.h"
70 : #include "nsIDirectoryService.h"
71 : #include "nsILocalFile.h"
72 : #include "nsDirectoryServiceDefs.h"
73 : #include "nsAppDirectoryServiceDefs.h"
74 : #include "nscore.h"
75 : #include "nsArrayEnumerator.h"
76 : #include "nsCOMArray.h"
77 : #include "nsDirectoryServiceUtils.h"
78 : #include "nsMemory.h"
79 : #include "nsISupportsImpl.h"
80 : #include "nsIJSRuntimeService.h"
81 : #include "nsCOMPtr.h"
82 : #include "nsAutoPtr.h"
83 : #include "nsIXPCSecurityManager.h"
84 : #include "nsJSPrincipals.h"
85 : #include "xpcpublic.h"
86 : #ifdef XP_MACOSX
87 : #include "xpcshellMacUtils.h"
88 : #endif
89 : #ifdef XP_WIN
90 : #include <windows.h>
91 : #endif
92 :
93 : #ifdef ANDROID
94 : #include <android/log.h>
95 : #endif
96 :
97 : #include "nsIScriptSecurityManager.h"
98 : #include "nsIPrincipal.h"
99 :
100 : // all this crap is needed to do the interactive shell stuff
101 : #include <stdlib.h>
102 : #include <errno.h>
103 : #ifdef HAVE_IO_H
104 : #include <io.h> /* for isatty() */
105 : #endif
106 : #ifdef HAVE_UNISTD_H
107 : #include <unistd.h> /* for isatty() */
108 : #endif
109 :
110 : #include "nsIJSContextStack.h"
111 :
112 : #ifdef MOZ_CRASHREPORTER
113 : #include "nsICrashReporter.h"
114 : #endif
115 :
116 : using namespace mozilla;
117 :
118 : class XPCShellDirProvider : public nsIDirectoryServiceProvider2
119 : {
120 : public:
121 : NS_DECL_ISUPPORTS_INHERITED
122 : NS_DECL_NSIDIRECTORYSERVICEPROVIDER
123 : NS_DECL_NSIDIRECTORYSERVICEPROVIDER2
124 :
125 1387 : XPCShellDirProvider() { }
126 1387 : ~XPCShellDirProvider() { }
127 :
128 : bool SetGREDir(const char *dir);
129 1387 : void ClearGREDir() { mGREDir = nsnull; }
130 :
131 : private:
132 : nsCOMPtr<nsILocalFile> mGREDir;
133 : };
134 :
135 : /***************************************************************************/
136 :
137 : #ifdef JS_THREADSAFE
138 : #define DoBeginRequest(cx) JS_BeginRequest((cx))
139 : #define DoEndRequest(cx) JS_EndRequest((cx))
140 : #else
141 : #define DoBeginRequest(cx) ((void)0)
142 : #define DoEndRequest(cx) ((void)0)
143 : #endif
144 :
145 : /***************************************************************************/
146 :
147 : static const char kXPConnectServiceContractID[] = "@mozilla.org/js/xpc/XPConnect;1";
148 :
149 : #define EXITCODE_RUNTIME_ERROR 3
150 : #define EXITCODE_FILE_NOT_FOUND 4
151 :
152 : FILE *gOutFile = NULL;
153 : FILE *gErrFile = NULL;
154 : FILE *gInFile = NULL;
155 :
156 : int gExitCode = 0;
157 : JSBool gQuitting = false;
158 : static JSBool reportWarnings = true;
159 : static JSBool compileOnly = false;
160 :
161 : JSPrincipals *gJSPrincipals = nsnull;
162 : nsAutoString *gWorkingDirectory = nsnull;
163 :
164 : static JSBool
165 3 : GetLocationProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
166 : {
167 : #if !defined(XP_WIN) && !defined(XP_UNIX)
168 : //XXX: your platform should really implement this
169 : return false;
170 : #else
171 : JSScript *script;
172 3 : JS_DescribeScriptedCaller(cx, &script, NULL);
173 3 : const char *filename = JS_GetScriptFilename(cx, script);
174 :
175 3 : if (filename) {
176 : nsresult rv;
177 : nsCOMPtr<nsIXPConnect> xpc =
178 6 : do_GetService(kXPConnectServiceContractID, &rv);
179 :
180 : #if defined(XP_WIN)
181 : // convert from the system codepage to UTF-16
182 : int bufferSize = MultiByteToWideChar(CP_ACP, 0, filename,
183 : -1, NULL, 0);
184 : nsAutoString filenameString;
185 : filenameString.SetLength(bufferSize);
186 : MultiByteToWideChar(CP_ACP, 0, filename,
187 : -1, (LPWSTR)filenameString.BeginWriting(),
188 : filenameString.Length());
189 : // remove the null terminator
190 : filenameString.SetLength(bufferSize - 1);
191 :
192 : // replace forward slashes with backslashes,
193 : // since nsLocalFileWin chokes on them
194 : PRUnichar *start, *end;
195 :
196 : filenameString.BeginWriting(&start, &end);
197 :
198 : while (start != end) {
199 : if (*start == L'/')
200 : *start = L'\\';
201 : start++;
202 : }
203 : #elif defined(XP_UNIX)
204 6 : NS_ConvertUTF8toUTF16 filenameString(filename);
205 : #endif
206 :
207 6 : nsCOMPtr<nsILocalFile> location;
208 3 : if (NS_SUCCEEDED(rv)) {
209 : rv = NS_NewLocalFile(filenameString,
210 3 : false, getter_AddRefs(location));
211 : }
212 :
213 3 : if (!location && gWorkingDirectory) {
214 : // could be a relative path, try appending it to the cwd
215 : // and then normalize
216 2 : nsAutoString absolutePath(*gWorkingDirectory);
217 1 : absolutePath.Append(filenameString);
218 :
219 : rv = NS_NewLocalFile(absolutePath,
220 1 : false, getter_AddRefs(location));
221 : }
222 :
223 3 : if (location) {
224 6 : nsCOMPtr<nsIXPConnectJSObjectHolder> locationHolder;
225 3 : JSObject *locationObj = NULL;
226 :
227 : bool symlink;
228 : // don't normalize symlinks, because that's kind of confusing
229 6 : if (NS_SUCCEEDED(location->IsSymlink(&symlink)) &&
230 3 : !symlink)
231 0 : location->Normalize();
232 3 : rv = xpc->WrapNative(cx, obj, location,
233 : NS_GET_IID(nsILocalFile),
234 3 : getter_AddRefs(locationHolder));
235 :
236 6 : if (NS_SUCCEEDED(rv) &&
237 3 : NS_SUCCEEDED(locationHolder->GetJSObject(&locationObj))) {
238 3 : *vp = OBJECT_TO_JSVAL(locationObj);
239 : }
240 : }
241 : }
242 :
243 3 : return true;
244 : #endif
245 : }
246 :
247 : #ifdef EDITLINE
248 : extern "C" {
249 : extern JS_EXPORT_API(char *) readline(const char *prompt);
250 : extern JS_EXPORT_API(void) add_history(char *line);
251 : }
252 : #endif
253 :
254 : static JSBool
255 0 : GetLine(JSContext *cx, char *bufp, FILE *file, const char *prompt) {
256 : #ifdef EDITLINE
257 : /*
258 : * Use readline only if file is stdin, because there's no way to specify
259 : * another handle. Are other filehandles interactive?
260 : */
261 : if (file == stdin) {
262 : char *linep = readline(prompt);
263 : if (!linep)
264 : return false;
265 : if (*linep)
266 : add_history(linep);
267 : strcpy(bufp, linep);
268 : JS_free(cx, linep);
269 : bufp += strlen(bufp);
270 : *bufp++ = '\n';
271 : *bufp = '\0';
272 : } else
273 : #endif
274 : {
275 0 : char line[256] = { '\0' };
276 0 : fputs(prompt, gOutFile);
277 0 : fflush(gOutFile);
278 0 : if ((!fgets(line, sizeof line, file) && errno != EINTR) || feof(file))
279 0 : return false;
280 0 : strcpy(bufp, line);
281 : }
282 0 : return true;
283 : }
284 :
285 : static void
286 7902 : my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
287 : {
288 : int i, j, k, n;
289 7902 : char *prefix = NULL, *tmp;
290 : const char *ctmp;
291 7902 : JSStackFrame * fp = nsnull;
292 15804 : nsCOMPtr<nsIXPConnect> xpc;
293 :
294 : // Don't report an exception from inner JS frames as the callers may intend
295 : // to handle it.
296 7902 : while ((fp = JS_FrameIterator(cx, &fp))) {
297 7479 : if (JS_IsScriptFrame(cx, fp)) {
298 : return;
299 : }
300 : }
301 :
302 : // In some cases cx->fp is null here so use XPConnect to tell us about inner
303 : // frames.
304 426 : if ((xpc = do_GetService(nsIXPConnect::GetCID()))) {
305 426 : nsAXPCNativeCallContext *cc = nsnull;
306 426 : xpc->GetCurrentNativeCallContext(&cc);
307 426 : if (cc) {
308 421 : nsAXPCNativeCallContext *prev = cc;
309 842 : while (NS_SUCCEEDED(prev->GetPreviousCallContext(&prev)) && prev) {
310 : PRUint16 lang;
311 397 : if (NS_SUCCEEDED(prev->GetLanguage(&lang)) &&
312 : lang == nsAXPCNativeCallContext::LANG_JS) {
313 : return;
314 : }
315 : }
316 : }
317 : }
318 :
319 29 : if (!report) {
320 0 : fprintf(gErrFile, "%s\n", message);
321 : return;
322 : }
323 :
324 : /* Conditionally ignore reported warnings. */
325 29 : if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings)
326 : return;
327 :
328 29 : if (report->filename)
329 6 : prefix = JS_smprintf("%s:", report->filename);
330 29 : if (report->lineno) {
331 6 : tmp = prefix;
332 6 : prefix = JS_smprintf("%s%u: ", tmp ? tmp : "", report->lineno);
333 6 : JS_free(cx, tmp);
334 : }
335 29 : if (JSREPORT_IS_WARNING(report->flags)) {
336 0 : tmp = prefix;
337 : prefix = JS_smprintf("%s%swarning: ",
338 : tmp ? tmp : "",
339 0 : JSREPORT_IS_STRICT(report->flags) ? "strict " : "");
340 0 : JS_free(cx, tmp);
341 : }
342 :
343 : /* embedded newlines -- argh! */
344 58 : while ((ctmp = strchr(message, '\n')) != 0) {
345 0 : ctmp++;
346 0 : if (prefix) fputs(prefix, gErrFile);
347 0 : fwrite(message, 1, ctmp - message, gErrFile);
348 0 : message = ctmp;
349 : }
350 : /* If there were no filename or lineno, the prefix might be empty */
351 29 : if (prefix)
352 6 : fputs(prefix, gErrFile);
353 29 : fputs(message, gErrFile);
354 :
355 29 : if (!report->linebuf) {
356 29 : fputc('\n', gErrFile);
357 29 : goto out;
358 : }
359 :
360 0 : fprintf(gErrFile, ":\n%s%s\n%s", prefix, report->linebuf, prefix);
361 0 : n = report->tokenptr - report->linebuf;
362 0 : for (i = j = 0; i < n; i++) {
363 0 : if (report->linebuf[i] == '\t') {
364 0 : for (k = (j + 8) & ~7; j < k; j++) {
365 0 : fputc('.', gErrFile);
366 : }
367 0 : continue;
368 : }
369 0 : fputc('.', gErrFile);
370 0 : j++;
371 : }
372 0 : fputs("^\n", gErrFile);
373 : out:
374 29 : if (!JSREPORT_IS_WARNING(report->flags))
375 29 : gExitCode = EXITCODE_RUNTIME_ERROR;
376 29 : JS_free(cx, prefix);
377 : }
378 :
379 : static JSBool
380 0 : ReadLine(JSContext *cx, unsigned argc, jsval *vp)
381 : {
382 : // While 4096 might be quite arbitrary, this is something to be fixed in
383 : // bug 105707. It is also the same limit as in ProcessFile.
384 : char buf[4096];
385 : JSString *str;
386 :
387 : /* If a prompt was specified, construct the string */
388 0 : if (argc > 0) {
389 0 : str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]);
390 0 : if (!str)
391 0 : return false;
392 : } else {
393 0 : str = JSVAL_TO_STRING(JS_GetEmptyStringValue(cx));
394 : }
395 :
396 : /* Get a line from the infile */
397 0 : JSAutoByteString strBytes(cx, str);
398 0 : if (!strBytes || !GetLine(cx, buf, gInFile, strBytes.ptr()))
399 0 : return false;
400 :
401 : /* Strip newline character added by GetLine() */
402 0 : unsigned int buflen = strlen(buf);
403 0 : if (buflen == 0) {
404 0 : if (feof(gInFile)) {
405 0 : JS_SET_RVAL(cx, vp, JSVAL_NULL);
406 0 : return true;
407 : }
408 0 : } else if (buf[buflen - 1] == '\n') {
409 0 : --buflen;
410 : }
411 :
412 : /* Turn buf into a JSString */
413 0 : str = JS_NewStringCopyN(cx, buf, buflen);
414 0 : if (!str)
415 0 : return false;
416 :
417 0 : JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(str));
418 0 : return true;
419 : }
420 :
421 : static JSBool
422 20902 : Print(JSContext *cx, unsigned argc, jsval *vp)
423 : {
424 : unsigned i, n;
425 : JSString *str;
426 :
427 20902 : jsval *argv = JS_ARGV(cx, vp);
428 41813 : for (i = n = 0; i < argc; i++) {
429 20911 : str = JS_ValueToString(cx, argv[i]);
430 20911 : if (!str)
431 0 : return false;
432 41822 : JSAutoByteString strBytes(cx, str);
433 20911 : if (!strBytes)
434 0 : return false;
435 20911 : fprintf(gOutFile, "%s%s", i ? " " : "", strBytes.ptr());
436 41822 : fflush(gOutFile);
437 : }
438 20902 : n++;
439 20902 : if (n)
440 20902 : fputc('\n', gOutFile);
441 20902 : JS_SET_RVAL(cx, vp, JSVAL_VOID);
442 20902 : return true;
443 : }
444 :
445 : static JSBool
446 235740 : Dump(JSContext *cx, unsigned argc, jsval *vp)
447 : {
448 235740 : JS_SET_RVAL(cx, vp, JSVAL_VOID);
449 :
450 : JSString *str;
451 235740 : if (!argc)
452 0 : return true;
453 :
454 235740 : str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]);
455 235740 : if (!str)
456 0 : return false;
457 :
458 471480 : JSAutoByteString bytes(cx, str);
459 235740 : if (!bytes)
460 0 : return false;
461 :
462 : #ifdef ANDROID
463 : __android_log_print(ANDROID_LOG_INFO, "Gecko", bytes.ptr());
464 : #endif
465 235740 : fputs(bytes.ptr(), gOutFile);
466 235740 : fflush(gOutFile);
467 235740 : return true;
468 : }
469 :
470 : static JSBool
471 3417 : Load(JSContext *cx, unsigned argc, jsval *vp)
472 : {
473 3417 : JSObject *obj = JS_THIS_OBJECT(cx, vp);
474 3417 : if (!obj)
475 0 : return false;
476 :
477 3417 : jsval *argv = JS_ARGV(cx, vp);
478 6830 : for (unsigned i = 0; i < argc; i++) {
479 3417 : JSString *str = JS_ValueToString(cx, argv[i]);
480 3417 : if (!str)
481 0 : return false;
482 3417 : argv[i] = STRING_TO_JSVAL(str);
483 6834 : JSAutoByteString filename(cx, str);
484 3417 : if (!filename)
485 0 : return false;
486 3417 : FILE *file = fopen(filename.ptr(), "r");
487 3417 : if (!file) {
488 : JS_ReportError(cx, "cannot open file '%s' for reading",
489 1 : filename.ptr());
490 1 : return false;
491 : }
492 3416 : JSScript *script = JS_CompileUTF8FileHandleForPrincipals(cx, obj, filename.ptr(),
493 6832 : file, gJSPrincipals);
494 3416 : fclose(file);
495 3416 : if (!script)
496 0 : return false;
497 :
498 : jsval result;
499 3416 : if (!compileOnly && !JS_ExecuteScript(cx, obj, script, &result))
500 3 : return false;
501 : }
502 3413 : JS_SET_RVAL(cx, vp, JSVAL_VOID);
503 3413 : return true;
504 : }
505 :
506 : static JSBool
507 1 : Version(JSContext *cx, unsigned argc, jsval *vp)
508 : {
509 1 : if (argc > 0 && JSVAL_IS_INT(JS_ARGV(cx, vp)[0]))
510 1 : JS_SET_RVAL(cx, vp, INT_TO_JSVAL(JS_SetVersion(cx, JSVersion(JSVAL_TO_INT(JS_ARGV(cx, vp)[0])))));
511 : else
512 0 : JS_SET_RVAL(cx, vp, INT_TO_JSVAL(JS_GetVersion(cx)));
513 1 : return true;
514 : }
515 :
516 : static JSBool
517 0 : BuildDate(JSContext *cx, unsigned argc, jsval *vp)
518 : {
519 0 : fprintf(gOutFile, "built on %s at %s\n", __DATE__, __TIME__);
520 0 : JS_SET_RVAL(cx, vp, JSVAL_VOID);
521 0 : return true;
522 : }
523 :
524 : static JSBool
525 1384 : Quit(JSContext *cx, unsigned argc, jsval *vp)
526 : {
527 1384 : gExitCode = 0;
528 1384 : JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp),"/ i", &gExitCode);
529 :
530 1384 : gQuitting = true;
531 : // exit(0);
532 1384 : return false;
533 : }
534 :
535 : static JSBool
536 0 : DumpXPC(JSContext *cx, unsigned argc, jsval *vp)
537 : {
538 0 : int32_t depth = 2;
539 :
540 0 : if (argc > 0) {
541 0 : if (!JS_ValueToInt32(cx, JS_ARGV(cx, vp)[0], &depth))
542 0 : return false;
543 : }
544 :
545 0 : nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
546 0 : if (xpc)
547 0 : xpc->DebugDump(int16_t(depth));
548 0 : JS_SET_RVAL(cx, vp, JSVAL_VOID);
549 0 : return true;
550 : }
551 :
552 : static JSBool
553 2903 : GC(JSContext *cx, unsigned argc, jsval *vp)
554 : {
555 2903 : JS_GC(cx);
556 : #ifdef JS_GCMETER
557 : js_DumpGCStats(JS_GetRuntime(cx), stdout);
558 : #endif
559 2903 : JS_SET_RVAL(cx, vp, JSVAL_VOID);
560 2903 : return true;
561 : }
562 :
563 : #ifdef JS_GC_ZEAL
564 : static JSBool
565 8 : GCZeal(JSContext *cx, unsigned argc, jsval *vp)
566 : {
567 : uint32_t zeal;
568 8 : if (!JS_ValueToECMAUint32(cx, argc ? JS_ARGV(cx, vp)[0] : JSVAL_VOID, &zeal))
569 0 : return false;
570 :
571 8 : JS_SetGCZeal(cx, uint8_t(zeal), JS_DEFAULT_ZEAL_FREQ, false);
572 8 : JS_SET_RVAL(cx, vp, JSVAL_VOID);
573 8 : return true;
574 : }
575 : #endif
576 :
577 : #ifdef DEBUG
578 :
579 : static JSBool
580 0 : DumpHeap(JSContext *cx, unsigned argc, jsval *vp)
581 : {
582 0 : void* startThing = NULL;
583 0 : JSGCTraceKind startTraceKind = JSTRACE_OBJECT;
584 0 : void *thingToFind = NULL;
585 0 : size_t maxDepth = (size_t)-1;
586 0 : void *thingToIgnore = NULL;
587 : FILE *dumpFile;
588 : JSBool ok;
589 :
590 0 : jsval *argv = JS_ARGV(cx, vp);
591 0 : JS_SET_RVAL(cx, vp, JSVAL_VOID);
592 :
593 0 : vp = argv + 0;
594 0 : JSAutoByteString fileName;
595 0 : if (argc > 0 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) {
596 : JSString *str;
597 :
598 0 : str = JS_ValueToString(cx, *vp);
599 0 : if (!str)
600 0 : return false;
601 0 : *vp = STRING_TO_JSVAL(str);
602 0 : if (!fileName.encode(cx, str))
603 0 : return false;
604 : }
605 :
606 0 : vp = argv + 1;
607 0 : if (argc > 1 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) {
608 0 : if (!JSVAL_IS_TRACEABLE(*vp))
609 0 : goto not_traceable_arg;
610 0 : startThing = JSVAL_TO_TRACEABLE(*vp);
611 0 : startTraceKind = JSVAL_TRACE_KIND(*vp);
612 : }
613 :
614 0 : vp = argv + 2;
615 0 : if (argc > 2 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) {
616 0 : if (!JSVAL_IS_TRACEABLE(*vp))
617 0 : goto not_traceable_arg;
618 0 : thingToFind = JSVAL_TO_TRACEABLE(*vp);
619 : }
620 :
621 0 : vp = argv + 3;
622 0 : if (argc > 3 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) {
623 : uint32_t depth;
624 :
625 0 : if (!JS_ValueToECMAUint32(cx, *vp, &depth))
626 0 : return false;
627 0 : maxDepth = depth;
628 : }
629 :
630 0 : vp = argv + 4;
631 0 : if (argc > 4 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) {
632 0 : if (!JSVAL_IS_TRACEABLE(*vp))
633 0 : goto not_traceable_arg;
634 0 : thingToIgnore = JSVAL_TO_TRACEABLE(*vp);
635 : }
636 :
637 0 : if (!fileName) {
638 0 : dumpFile = gOutFile;
639 : } else {
640 0 : dumpFile = fopen(fileName.ptr(), "w");
641 0 : if (!dumpFile) {
642 : fprintf(gErrFile, "dumpHeap: can't open %s: %s\n",
643 0 : fileName.ptr(), strerror(errno));
644 0 : return false;
645 : }
646 : }
647 :
648 : ok = JS_DumpHeap(JS_GetRuntime(cx), dumpFile, startThing, startTraceKind, thingToFind,
649 0 : maxDepth, thingToIgnore);
650 0 : if (dumpFile != gOutFile)
651 0 : fclose(dumpFile);
652 0 : if (!ok)
653 0 : JS_ReportOutOfMemory(cx);
654 0 : return ok;
655 :
656 : not_traceable_arg:
657 : fprintf(gErrFile,
658 : "dumpHeap: argument %u is not null or a heap-allocated thing\n",
659 0 : (unsigned)(vp - argv));
660 0 : return false;
661 : }
662 :
663 : #endif /* DEBUG */
664 :
665 : static JSBool
666 0 : Clear(JSContext *cx, unsigned argc, jsval *vp)
667 : {
668 0 : if (argc > 0 && !JSVAL_IS_PRIMITIVE(JS_ARGV(cx, vp)[0])) {
669 0 : JS_ClearScope(cx, JSVAL_TO_OBJECT(JS_ARGV(cx, vp)[0]));
670 : } else {
671 0 : JS_ReportError(cx, "'clear' requires an object");
672 0 : return false;
673 : }
674 0 : JS_SET_RVAL(cx, vp, JSVAL_VOID);
675 0 : return true;
676 : }
677 :
678 : static JSBool
679 0 : SendCommand(JSContext* cx,
680 : unsigned argc,
681 : jsval* vp)
682 : {
683 0 : if (argc == 0) {
684 0 : JS_ReportError(cx, "Function takes at least one argument!");
685 0 : return false;
686 : }
687 :
688 0 : jsval *argv = JS_ARGV(cx, vp);
689 0 : JSString* str = JS_ValueToString(cx, argv[0]);
690 0 : if (!str) {
691 0 : JS_ReportError(cx, "Could not convert argument 1 to string!");
692 0 : return false;
693 : }
694 :
695 0 : if (argc > 1 && JS_TypeOfValue(cx, argv[1]) != JSTYPE_FUNCTION) {
696 0 : JS_ReportError(cx, "Could not convert argument 2 to function!");
697 0 : return false;
698 : }
699 :
700 0 : if (!XRE_SendTestShellCommand(cx, str, argc > 1 ? &argv[1] : nsnull)) {
701 0 : JS_ReportError(cx, "Couldn't send command!");
702 0 : return false;
703 : }
704 :
705 0 : JS_SET_RVAL(cx, vp, JSVAL_VOID);
706 0 : return true;
707 : }
708 :
709 : static JSBool
710 0 : GetChildGlobalObject(JSContext* cx,
711 : unsigned,
712 : jsval* vp)
713 : {
714 : JSObject* global;
715 0 : if (XRE_GetChildGlobalObject(cx, &global)) {
716 0 : JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(global));
717 0 : return true;
718 : }
719 0 : return false;
720 : }
721 :
722 : /*
723 : * JSContext option name to flag map. The option names are in alphabetical
724 : * order for better reporting.
725 : */
726 : static const struct JSOption {
727 : const char *name;
728 : uint32_t flag;
729 : } js_options[] = {
730 : {"atline", JSOPTION_ATLINE},
731 : {"relimit", JSOPTION_RELIMIT},
732 : {"strict", JSOPTION_STRICT},
733 : {"werror", JSOPTION_WERROR},
734 : {"xml", JSOPTION_XML},
735 : };
736 :
737 : static uint32_t
738 0 : MapContextOptionNameToFlag(JSContext* cx, const char* name)
739 : {
740 0 : for (size_t i = 0; i < ArrayLength(js_options); ++i) {
741 0 : if (strcmp(name, js_options[i].name) == 0)
742 0 : return js_options[i].flag;
743 : }
744 :
745 : char* msg = JS_sprintf_append(NULL,
746 : "unknown option name '%s'."
747 0 : " The valid names are ", name);
748 0 : for (size_t i = 0; i < ArrayLength(js_options); ++i) {
749 0 : if (!msg)
750 0 : break;
751 : msg = JS_sprintf_append(msg, "%s%s", js_options[i].name,
752 0 : (i + 2 < ArrayLength(js_options)
753 : ? ", "
754 0 : : i + 2 == ArrayLength(js_options)
755 : ? " and "
756 0 : : "."));
757 : }
758 0 : if (!msg) {
759 0 : JS_ReportOutOfMemory(cx);
760 : } else {
761 0 : JS_ReportError(cx, msg);
762 0 : free(msg);
763 : }
764 0 : return 0;
765 : }
766 :
767 : static JSBool
768 0 : Options(JSContext *cx, unsigned argc, jsval *vp)
769 : {
770 : uint32_t optset, flag;
771 : JSString *str;
772 : char *names;
773 : JSBool found;
774 :
775 0 : optset = 0;
776 0 : jsval *argv = JS_ARGV(cx, vp);
777 0 : for (unsigned i = 0; i < argc; i++) {
778 0 : str = JS_ValueToString(cx, argv[i]);
779 0 : if (!str)
780 0 : return false;
781 0 : argv[i] = STRING_TO_JSVAL(str);
782 0 : JSAutoByteString opt(cx, str);
783 0 : if (!opt)
784 0 : return false;
785 0 : flag = MapContextOptionNameToFlag(cx, opt.ptr());
786 0 : if (!flag)
787 0 : return false;
788 0 : optset |= flag;
789 : }
790 0 : optset = JS_ToggleOptions(cx, optset);
791 :
792 0 : names = NULL;
793 0 : found = false;
794 0 : for (size_t i = 0; i < ArrayLength(js_options); i++) {
795 0 : if (js_options[i].flag & optset) {
796 0 : found = true;
797 : names = JS_sprintf_append(names, "%s%s",
798 0 : names ? "," : "", js_options[i].name);
799 0 : if (!names)
800 0 : break;
801 : }
802 : }
803 0 : if (!found)
804 0 : names = strdup("");
805 0 : if (!names) {
806 0 : JS_ReportOutOfMemory(cx);
807 0 : return false;
808 : }
809 0 : str = JS_NewStringCopyZ(cx, names);
810 0 : free(names);
811 0 : if (!str)
812 0 : return false;
813 0 : JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(str));
814 0 : return true;
815 : }
816 :
817 : static JSBool
818 133 : Parent(JSContext *cx, unsigned argc, jsval *vp)
819 : {
820 133 : if (argc != 1) {
821 0 : JS_ReportError(cx, "Wrong number of arguments");
822 0 : return false;
823 : }
824 :
825 133 : jsval v = JS_ARGV(cx, vp)[0];
826 133 : if (JSVAL_IS_PRIMITIVE(v)) {
827 0 : JS_ReportError(cx, "Only objects have parents!");
828 0 : return false;
829 : }
830 :
831 133 : *vp = OBJECT_TO_JSVAL(JS_GetParent(JSVAL_TO_OBJECT(v)));
832 133 : return true;
833 : }
834 :
835 : static JSFunctionSpec glob_functions[] = {
836 : {"print", Print, 0,0},
837 : {"readline", ReadLine, 1,0},
838 : {"load", Load, 1,0},
839 : {"quit", Quit, 0,0},
840 : {"version", Version, 1,0},
841 : {"build", BuildDate, 0,0},
842 : {"dumpXPC", DumpXPC, 1,0},
843 : {"dump", Dump, 1,0},
844 : {"gc", GC, 0,0},
845 : #ifdef JS_GC_ZEAL
846 : {"gczeal", GCZeal, 1,0},
847 : #endif
848 : {"clear", Clear, 1,0},
849 : {"options", Options, 0,0},
850 : JS_FN("parent", Parent, 1,0),
851 : #ifdef DEBUG
852 : {"dumpHeap", DumpHeap, 5,0},
853 : #endif
854 : {"sendCommand", SendCommand, 1,0},
855 : {"getChildGlobalObject", GetChildGlobalObject, 0,0},
856 : {nsnull,nsnull,0,0}
857 : };
858 :
859 : JSClass global_class = {
860 : "global", 0,
861 : JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
862 : JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nsnull
863 : };
864 :
865 : static JSBool
866 0 : env_setProperty(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
867 : {
868 : /* XXX porting may be easy, but these don't seem to supply setenv by default */
869 : #if !defined XP_OS2 && !defined SOLARIS
870 : JSString *idstr, *valstr;
871 : int rv;
872 :
873 : jsval idval;
874 0 : if (!JS_IdToValue(cx, id, &idval))
875 0 : return false;
876 :
877 0 : idstr = JS_ValueToString(cx, idval);
878 0 : valstr = JS_ValueToString(cx, *vp);
879 0 : if (!idstr || !valstr)
880 0 : return false;
881 0 : JSAutoByteString name(cx, idstr);
882 0 : if (!name)
883 0 : return false;
884 0 : JSAutoByteString value(cx, valstr);
885 0 : if (!value)
886 0 : return false;
887 : #if defined XP_WIN || defined HPUX || defined OSF1 || defined SCO
888 : {
889 : char *waste = JS_smprintf("%s=%s", name.ptr(), value.ptr());
890 : if (!waste) {
891 : JS_ReportOutOfMemory(cx);
892 : return false;
893 : }
894 : rv = putenv(waste);
895 : #ifdef XP_WIN
896 : /*
897 : * HPUX9 at least still has the bad old non-copying putenv.
898 : *
899 : * Per mail from <s.shanmuganathan@digital.com>, OSF1 also has a putenv
900 : * that will crash if you pass it an auto char array (so it must place
901 : * its argument directly in the char *environ[] array).
902 : */
903 : free(waste);
904 : #endif
905 : }
906 : #else
907 0 : rv = setenv(name.ptr(), value.ptr(), 1);
908 : #endif
909 0 : if (rv < 0) {
910 0 : JS_ReportError(cx, "can't set envariable %s to %s", name.ptr(), value.ptr());
911 0 : return false;
912 : }
913 0 : *vp = STRING_TO_JSVAL(valstr);
914 : #endif /* !defined XP_OS2 && !defined SOLARIS */
915 0 : return true;
916 : }
917 :
918 : static JSBool
919 0 : env_enumerate(JSContext *cx, JSObject *obj)
920 : {
921 : static JSBool reflected;
922 : char **evp, *name, *value;
923 : JSString *valstr;
924 : JSBool ok;
925 :
926 0 : if (reflected)
927 0 : return true;
928 :
929 0 : for (evp = (char **)JS_GetPrivate(obj); (name = *evp) != NULL; evp++) {
930 0 : value = strchr(name, '=');
931 0 : if (!value)
932 0 : continue;
933 0 : *value++ = '\0';
934 0 : valstr = JS_NewStringCopyZ(cx, value);
935 0 : if (!valstr) {
936 0 : ok = false;
937 : } else {
938 : ok = JS_DefineProperty(cx, obj, name, STRING_TO_JSVAL(valstr),
939 0 : NULL, NULL, JSPROP_ENUMERATE);
940 : }
941 0 : value[-1] = '=';
942 0 : if (!ok)
943 0 : return false;
944 : }
945 :
946 0 : reflected = true;
947 0 : return true;
948 : }
949 :
950 : static JSBool
951 0 : env_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
952 : JSObject **objp)
953 : {
954 : JSString *idstr, *valstr;
955 :
956 0 : if (flags & JSRESOLVE_ASSIGNING)
957 0 : return true;
958 :
959 : jsval idval;
960 0 : if (!JS_IdToValue(cx, id, &idval))
961 0 : return false;
962 :
963 0 : idstr = JS_ValueToString(cx, idval);
964 0 : if (!idstr)
965 0 : return false;
966 0 : JSAutoByteString name(cx, idstr);
967 0 : if (!name)
968 0 : return false;
969 0 : const char *value = getenv(name.ptr());
970 0 : if (value) {
971 0 : valstr = JS_NewStringCopyZ(cx, value);
972 0 : if (!valstr)
973 0 : return false;
974 0 : if (!JS_DefinePropertyById(cx, obj, id, STRING_TO_JSVAL(valstr),
975 0 : NULL, NULL, JSPROP_ENUMERATE)) {
976 0 : return false;
977 : }
978 0 : *objp = obj;
979 : }
980 0 : return true;
981 : }
982 :
983 : static JSClass env_class = {
984 : "environment", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
985 : JS_PropertyStub, JS_PropertyStub,
986 : JS_PropertyStub, env_setProperty,
987 : env_enumerate, (JSResolveOp) env_resolve,
988 : JS_ConvertStub, nsnull
989 : };
990 :
991 : /***************************************************************************/
992 :
993 : typedef enum JSShellErrNum {
994 : #define MSG_DEF(name, number, count, exception, format) \
995 : name = number,
996 : #include "jsshell.msg"
997 : #undef MSG_DEF
998 : JSShellErr_Limit
999 : } JSShellErrNum;
1000 :
1001 : JSErrorFormatString jsShell_ErrorFormatString[JSShellErr_Limit] = {
1002 : #define MSG_DEF(name, number, count, exception, format) \
1003 : { format, count } ,
1004 : #include "jsshell.msg"
1005 : #undef MSG_DEF
1006 : };
1007 :
1008 : static const JSErrorFormatString *
1009 0 : my_GetErrorMessage(void *userRef, const char *locale, const unsigned errorNumber)
1010 : {
1011 0 : if (errorNumber == 0 || errorNumber >= JSShellErr_Limit)
1012 0 : return NULL;
1013 :
1014 0 : return &jsShell_ErrorFormatString[errorNumber];
1015 : }
1016 :
1017 : static void
1018 1387 : ProcessFile(JSContext *cx, JSObject *obj, const char *filename, FILE *file,
1019 : JSBool forceTTY)
1020 : {
1021 : JSScript *script;
1022 : jsval result;
1023 : int lineno, startline;
1024 : JSBool ok, hitEOF;
1025 : char *bufp, buffer[4096];
1026 : JSString *str;
1027 :
1028 1387 : if (forceTTY) {
1029 0 : file = stdin;
1030 : } else
1031 : #ifdef HAVE_ISATTY
1032 1387 : if (!isatty(fileno(file)))
1033 : #endif
1034 : {
1035 : /*
1036 : * It's not interactive - just execute it.
1037 : *
1038 : * Support the UNIX #! shell hack; gobble the first line if it starts
1039 : * with '#'. TODO - this isn't quite compatible with sharp variables,
1040 : * as a legal js program (using sharp variables) might start with '#'.
1041 : * But that would require multi-character lookahead.
1042 : */
1043 1387 : int ch = fgetc(file);
1044 1387 : if (ch == '#') {
1045 0 : while ((ch = fgetc(file)) != EOF) {
1046 0 : if (ch == '\n' || ch == '\r')
1047 0 : break;
1048 : }
1049 : }
1050 1387 : ungetc(ch, file);
1051 1387 : DoBeginRequest(cx);
1052 :
1053 : script = JS_CompileUTF8FileHandleForPrincipals(cx, obj, filename, file,
1054 1387 : gJSPrincipals);
1055 :
1056 1387 : if (script && !compileOnly)
1057 1387 : (void)JS_ExecuteScript(cx, obj, script, &result);
1058 1387 : DoEndRequest(cx);
1059 :
1060 1387 : return;
1061 : }
1062 :
1063 : /* It's an interactive filehandle; drop into read-eval-print loop. */
1064 0 : lineno = 1;
1065 0 : hitEOF = false;
1066 0 : do {
1067 0 : bufp = buffer;
1068 0 : *bufp = '\0';
1069 :
1070 : /*
1071 : * Accumulate lines until we get a 'compilable unit' - one that either
1072 : * generates an error (before running out of source) or that compiles
1073 : * cleanly. This should be whenever we get a complete statement that
1074 : * coincides with the end of a line.
1075 : */
1076 0 : startline = lineno;
1077 0 : do {
1078 0 : if (!GetLine(cx, bufp, file, startline == lineno ? "js> " : "")) {
1079 0 : hitEOF = true;
1080 0 : break;
1081 : }
1082 0 : bufp += strlen(bufp);
1083 0 : lineno++;
1084 0 : } while (!JS_BufferIsCompilableUnit(cx, false, obj, buffer, strlen(buffer)));
1085 :
1086 0 : DoBeginRequest(cx);
1087 : /* Clear any pending exception from previous failed compiles. */
1088 0 : JS_ClearPendingException(cx);
1089 : script = JS_CompileScriptForPrincipals(cx, obj, gJSPrincipals, buffer,
1090 0 : strlen(buffer), "typein", startline);
1091 0 : if (script) {
1092 : JSErrorReporter older;
1093 :
1094 0 : if (!compileOnly) {
1095 0 : ok = JS_ExecuteScript(cx, obj, script, &result);
1096 0 : if (ok && result != JSVAL_VOID) {
1097 : /* Suppress error reports from JS_ValueToString(). */
1098 0 : older = JS_SetErrorReporter(cx, NULL);
1099 0 : str = JS_ValueToString(cx, result);
1100 0 : JS_SetErrorReporter(cx, older);
1101 0 : JSAutoByteString bytes;
1102 0 : if (str && bytes.encode(cx, str))
1103 0 : fprintf(gOutFile, "%s\n", bytes.ptr());
1104 : else
1105 0 : ok = false;
1106 : }
1107 : }
1108 : }
1109 0 : DoEndRequest(cx);
1110 0 : } while (!hitEOF && !gQuitting);
1111 :
1112 0 : fprintf(gOutFile, "\n");
1113 : }
1114 :
1115 : static void
1116 1387 : Process(JSContext *cx, JSObject *obj, const char *filename, JSBool forceTTY)
1117 : {
1118 : FILE *file;
1119 :
1120 1387 : if (forceTTY || !filename || strcmp(filename, "-") == 0) {
1121 0 : file = stdin;
1122 : } else {
1123 1387 : file = fopen(filename, "r");
1124 1387 : if (!file) {
1125 : JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
1126 : JSSMSG_CANT_OPEN,
1127 0 : filename, strerror(errno));
1128 0 : gExitCode = EXITCODE_FILE_NOT_FOUND;
1129 0 : return;
1130 : }
1131 : }
1132 :
1133 1387 : ProcessFile(cx, obj, filename, file, forceTTY);
1134 1387 : if (file != stdin)
1135 1387 : fclose(file);
1136 : }
1137 :
1138 : static int
1139 0 : usage(void)
1140 : {
1141 0 : fprintf(gErrFile, "%s\n", JS_GetImplementationVersion());
1142 0 : fprintf(gErrFile, "usage: xpcshell [-g gredir] [-a appdir] [-r manifest]... [-PsSwWxCij] [-v version] [-f scriptfile] [-e script] [scriptfile] [scriptarg...]\n");
1143 0 : return 2;
1144 : }
1145 :
1146 : extern JSClass global_class;
1147 :
1148 : static int
1149 1387 : ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
1150 : {
1151 1387 : const char rcfilename[] = "xpcshell.js";
1152 : FILE *rcfile;
1153 : int i;
1154 : JSObject *argsObj;
1155 1387 : char *filename = NULL;
1156 1387 : JSBool isInteractive = true;
1157 1387 : JSBool forceTTY = false;
1158 :
1159 1387 : rcfile = fopen(rcfilename, "r");
1160 1387 : if (rcfile) {
1161 0 : printf("[loading '%s'...]\n", rcfilename);
1162 0 : ProcessFile(cx, obj, rcfilename, rcfile, false);
1163 0 : fclose(rcfile);
1164 : }
1165 :
1166 : /*
1167 : * Scan past all optional arguments so we can create the arguments object
1168 : * before processing any -f options, which must interleave properly with
1169 : * -v and -w options. This requires two passes, and without getopt, we'll
1170 : * have to keep the option logic here and in the second for loop in sync.
1171 : */
1172 16913 : for (i = 0; i < argc; i++) {
1173 15527 : if (argv[i][0] != '-' || argv[i][1] == '\0') {
1174 1 : ++i;
1175 1 : break;
1176 : }
1177 15526 : switch (argv[i][1]) {
1178 : case 'v':
1179 : case 'f':
1180 : case 'e':
1181 11088 : ++i;
1182 11088 : break;
1183 : default:;
1184 : }
1185 : }
1186 :
1187 : /*
1188 : * Create arguments early and define it to root it, so it's safe from any
1189 : * GC calls nested below, and so it is available to -f <file> arguments.
1190 : */
1191 1387 : argsObj = JS_NewArrayObject(cx, 0, NULL);
1192 1387 : if (!argsObj)
1193 0 : return 1;
1194 1387 : if (!JS_DefineProperty(cx, obj, "arguments", OBJECT_TO_JSVAL(argsObj),
1195 1387 : NULL, NULL, 0)) {
1196 0 : return 1;
1197 : }
1198 :
1199 1388 : for (size_t j = 0, length = argc - i; j < length; j++) {
1200 1 : JSString *str = JS_NewStringCopyZ(cx, argv[i++]);
1201 1 : if (!str)
1202 0 : return 1;
1203 1 : if (!JS_DefineElement(cx, argsObj, j, STRING_TO_JSVAL(str),
1204 1 : NULL, NULL, JSPROP_ENUMERATE)) {
1205 0 : return 1;
1206 : }
1207 : }
1208 :
1209 16913 : for (i = 0; i < argc; i++) {
1210 15527 : if (argv[i][0] != '-' || argv[i][1] == '\0') {
1211 1 : filename = argv[i++];
1212 1 : isInteractive = false;
1213 1 : break;
1214 : }
1215 15526 : switch (argv[i][1]) {
1216 : case 'v':
1217 0 : if (++i == argc) {
1218 0 : return usage();
1219 : }
1220 0 : JS_SetVersion(cx, JSVersion(atoi(argv[i])));
1221 0 : break;
1222 : case 'W':
1223 0 : reportWarnings = false;
1224 0 : break;
1225 : case 'w':
1226 0 : reportWarnings = true;
1227 0 : break;
1228 : case 'S':
1229 0 : JS_ToggleOptions(cx, JSOPTION_WERROR);
1230 : case 's':
1231 1386 : JS_ToggleOptions(cx, JSOPTION_STRICT);
1232 1386 : break;
1233 : case 'x':
1234 0 : JS_ToggleOptions(cx, JSOPTION_XML);
1235 0 : break;
1236 : case 'd':
1237 280 : xpc_ActivateDebugMode();
1238 280 : break;
1239 : case 'P':
1240 0 : if (JS_GetClass(JS_GetPrototype(obj)) != &global_class) {
1241 : JSObject *gobj;
1242 :
1243 0 : if (!JS_DeepFreezeObject(cx, obj))
1244 0 : return false;
1245 0 : gobj = JS_NewGlobalObject(cx, &global_class);
1246 0 : if (!gobj || !JS_SplicePrototype(cx, gobj, obj))
1247 0 : return false;
1248 0 : JS_SetParent(cx, gobj, NULL);
1249 0 : JS_SetGlobalObject(cx, gobj);
1250 0 : obj = gobj;
1251 : }
1252 0 : break;
1253 : case 'f':
1254 1386 : if (++i == argc) {
1255 0 : return usage();
1256 : }
1257 1386 : Process(cx, obj, argv[i], false);
1258 : /*
1259 : * XXX: js -f foo.js should interpret foo.js and then
1260 : * drop into interactive mode, but that breaks test
1261 : * harness. Just execute foo.js for now.
1262 : */
1263 1386 : isInteractive = false;
1264 1386 : break;
1265 : case 'i':
1266 0 : isInteractive = forceTTY = true;
1267 0 : break;
1268 : case 'e':
1269 : {
1270 : jsval rval;
1271 :
1272 9702 : if (++i == argc) {
1273 0 : return usage();
1274 : }
1275 :
1276 9702 : JS_EvaluateScriptForPrincipals(cx, obj, gJSPrincipals, argv[i],
1277 19404 : strlen(argv[i]), "-e", 1, &rval);
1278 :
1279 9702 : isInteractive = false;
1280 9702 : break;
1281 : }
1282 : case 'C':
1283 0 : compileOnly = true;
1284 0 : isInteractive = false;
1285 0 : break;
1286 : case 'm':
1287 1386 : JS_ToggleOptions(cx, JSOPTION_METHODJIT);
1288 1386 : break;
1289 : case 'n':
1290 1386 : JS_ToggleOptions(cx, JSOPTION_TYPE_INFERENCE);
1291 1386 : break;
1292 : default:
1293 0 : return usage();
1294 : }
1295 : }
1296 :
1297 1387 : if (filename || isInteractive)
1298 1 : Process(cx, obj, filename, forceTTY);
1299 1387 : return gExitCode;
1300 : }
1301 :
1302 : /***************************************************************************/
1303 :
1304 : class FullTrustSecMan
1305 : : public nsIScriptSecurityManager
1306 : {
1307 : public:
1308 : NS_DECL_ISUPPORTS
1309 : NS_DECL_NSIXPCSECURITYMANAGER
1310 : NS_DECL_NSISCRIPTSECURITYMANAGER
1311 :
1312 : FullTrustSecMan();
1313 : virtual ~FullTrustSecMan();
1314 :
1315 1387 : void SetSystemPrincipal(nsIPrincipal *aPrincipal) {
1316 1387 : mSystemPrincipal = aPrincipal;
1317 1387 : }
1318 :
1319 : private:
1320 : nsCOMPtr<nsIPrincipal> mSystemPrincipal;
1321 : };
1322 :
1323 0 : NS_INTERFACE_MAP_BEGIN(FullTrustSecMan)
1324 0 : NS_INTERFACE_MAP_ENTRY(nsIXPCSecurityManager)
1325 0 : NS_INTERFACE_MAP_ENTRY(nsIScriptSecurityManager)
1326 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCSecurityManager)
1327 0 : NS_INTERFACE_MAP_END
1328 :
1329 2774 : NS_IMPL_ADDREF(FullTrustSecMan)
1330 2774 : NS_IMPL_RELEASE(FullTrustSecMan)
1331 :
1332 1387 : FullTrustSecMan::FullTrustSecMan()
1333 : {
1334 1387 : mSystemPrincipal = nsnull;
1335 1387 : }
1336 :
1337 2774 : FullTrustSecMan::~FullTrustSecMan()
1338 : {
1339 5548 : }
1340 :
1341 : NS_IMETHODIMP
1342 580210 : FullTrustSecMan::CanCreateWrapper(JSContext * aJSContext, const nsIID & aIID,
1343 : nsISupports *aObj, nsIClassInfo *aClassInfo,
1344 : void * *aPolicy)
1345 : {
1346 580210 : return NS_OK;
1347 : }
1348 :
1349 : NS_IMETHODIMP
1350 126480 : FullTrustSecMan::CanCreateInstance(JSContext * aJSContext, const nsCID & aCID)
1351 : {
1352 126480 : return NS_OK;
1353 : }
1354 :
1355 : NS_IMETHODIMP
1356 0 : FullTrustSecMan::CanGetService(JSContext * aJSContext, const nsCID & aCID)
1357 : {
1358 0 : return NS_OK;
1359 : }
1360 :
1361 : /* void CanAccess (in PRUint32 aAction, in nsIXPCNativeCallContext aCallContext, in JSContextPtr aJSContext, in JSObjectPtr aJSObject, in nsISupports aObj, in nsIClassInfo aClassInfo, in jsval aName, inout voidPtr aPolicy); */
1362 : NS_IMETHODIMP
1363 5519387 : FullTrustSecMan::CanAccess(PRUint32 aAction,
1364 : nsAXPCNativeCallContext *aCallContext,
1365 : JSContext * aJSContext, JSObject * aJSObject,
1366 : nsISupports *aObj, nsIClassInfo *aClassInfo,
1367 : jsid aName, void * *aPolicy)
1368 : {
1369 5519387 : return NS_OK;
1370 : }
1371 :
1372 : /* [noscript] void checkPropertyAccess (in JSContextPtr aJSContext, in JSObjectPtr aJSObject, in string aClassName, in jsid aProperty, in PRUint32 aAction); */
1373 : NS_IMETHODIMP
1374 0 : FullTrustSecMan::CheckPropertyAccess(JSContext * aJSContext,
1375 : JSObject * aJSObject,
1376 : const char *aClassName,
1377 : jsid aProperty, PRUint32 aAction)
1378 : {
1379 0 : return NS_OK;
1380 : }
1381 :
1382 : /* [noscript] void checkLoadURIFromScript (in JSContextPtr cx, in nsIURI uri); */
1383 : NS_IMETHODIMP
1384 0 : FullTrustSecMan::CheckLoadURIFromScript(JSContext * cx, nsIURI *uri)
1385 : {
1386 0 : return NS_OK;
1387 : }
1388 :
1389 : /* void checkLoadURIWithPrincipal (in nsIPrincipal aPrincipal, in nsIURI uri, in unsigned long flags); */
1390 : NS_IMETHODIMP
1391 0 : FullTrustSecMan::CheckLoadURIWithPrincipal(nsIPrincipal *aPrincipal,
1392 : nsIURI *uri, PRUint32 flags)
1393 : {
1394 0 : return NS_OK;
1395 : }
1396 :
1397 : /* void checkLoadURI (in nsIURI from, in nsIURI uri, in unsigned long flags); */
1398 : NS_IMETHODIMP
1399 0 : FullTrustSecMan::CheckLoadURI(nsIURI *from, nsIURI *uri, PRUint32 flags)
1400 : {
1401 0 : return NS_OK;
1402 : }
1403 :
1404 : /* void checkLoadURIStrWithPrincipal (in nsIPrincipal aPrincipal, in AUTF8String uri, in unsigned long flags); */
1405 : NS_IMETHODIMP
1406 0 : FullTrustSecMan::CheckLoadURIStrWithPrincipal(nsIPrincipal *aPrincipal,
1407 : const nsACString & uri,
1408 : PRUint32 flags)
1409 : {
1410 0 : return NS_OK;
1411 : }
1412 :
1413 : /* void checkLoadURIStr (in AUTF8String from, in AUTF8String uri, in unsigned long flags); */
1414 : NS_IMETHODIMP
1415 0 : FullTrustSecMan::CheckLoadURIStr(const nsACString & from,
1416 : const nsACString & uri, PRUint32 flags)
1417 : {
1418 0 : return NS_OK;
1419 : }
1420 :
1421 : /* [noscript] void checkFunctionAccess (in JSContextPtr cx, in voidPtr funObj, in voidPtr targetObj); */
1422 : NS_IMETHODIMP
1423 0 : FullTrustSecMan::CheckFunctionAccess(JSContext * cx, void * funObj,
1424 : void * targetObj)
1425 : {
1426 0 : return NS_OK;
1427 : }
1428 :
1429 : /* [noscript] boolean canExecuteScripts (in JSContextPtr cx, in nsIPrincipal principal); */
1430 : NS_IMETHODIMP
1431 0 : FullTrustSecMan::CanExecuteScripts(JSContext * cx, nsIPrincipal *principal,
1432 : bool *_retval)
1433 : {
1434 0 : *_retval = true;
1435 0 : return NS_OK;
1436 : }
1437 :
1438 : /* [noscript] nsIPrincipal getSubjectPrincipal (); */
1439 : NS_IMETHODIMP
1440 0 : FullTrustSecMan::GetSubjectPrincipal(nsIPrincipal **_retval)
1441 : {
1442 0 : NS_IF_ADDREF(*_retval = mSystemPrincipal);
1443 0 : return *_retval ? NS_OK : NS_ERROR_FAILURE;
1444 : }
1445 :
1446 : /* [noscript] void pushContextPrincipal (in JSContextPtr cx, in JSStackFramePtr fp, in nsIPrincipal principal); */
1447 : NS_IMETHODIMP
1448 0 : FullTrustSecMan::PushContextPrincipal(JSContext * cx, JSStackFrame * fp, nsIPrincipal *principal)
1449 : {
1450 0 : return NS_OK;
1451 : }
1452 :
1453 : /* [noscript] void popContextPrincipal (in JSContextPtr cx); */
1454 : NS_IMETHODIMP
1455 0 : FullTrustSecMan::PopContextPrincipal(JSContext * cx)
1456 : {
1457 0 : return NS_OK;
1458 : }
1459 :
1460 : /* [noscript] nsIPrincipal getSystemPrincipal (); */
1461 : NS_IMETHODIMP
1462 0 : FullTrustSecMan::GetSystemPrincipal(nsIPrincipal **_retval)
1463 : {
1464 0 : NS_IF_ADDREF(*_retval = mSystemPrincipal);
1465 0 : return *_retval ? NS_OK : NS_ERROR_FAILURE;
1466 : }
1467 :
1468 : /* [noscript] nsIPrincipal getCertificatePrincipal (in AUTF8String aCertFingerprint, in AUTF8String aSubjectName, in AUTF8String aPrettyName, in nsISupports aCert, in nsIURI aURI); */
1469 : NS_IMETHODIMP
1470 0 : FullTrustSecMan::GetCertificatePrincipal(const nsACString & aCertFingerprint,
1471 : const nsACString & aSubjectName,
1472 : const nsACString & aPrettyName,
1473 : nsISupports *aCert, nsIURI *aURI,
1474 : nsIPrincipal **_retval)
1475 : {
1476 0 : NS_IF_ADDREF(*_retval = mSystemPrincipal);
1477 0 : return *_retval ? NS_OK : NS_ERROR_FAILURE;
1478 : }
1479 :
1480 : /* [noscript] nsIPrincipal getCodebasePrincipal (in nsIURI aURI); */
1481 : NS_IMETHODIMP
1482 0 : FullTrustSecMan::GetCodebasePrincipal(nsIURI *aURI, nsIPrincipal **_retval)
1483 : {
1484 0 : NS_IF_ADDREF(*_retval = mSystemPrincipal);
1485 0 : return *_retval ? NS_OK : NS_ERROR_FAILURE;
1486 : }
1487 :
1488 : /* [noscript] short requestCapability (in nsIPrincipal principal, in string capability); */
1489 : NS_IMETHODIMP
1490 0 : FullTrustSecMan::RequestCapability(nsIPrincipal *principal,
1491 : const char *capability, PRInt16 *_retval)
1492 : {
1493 0 : *_retval = nsIPrincipal::ENABLE_GRANTED;
1494 0 : return NS_OK;
1495 : }
1496 :
1497 : /* boolean isCapabilityEnabled (in string capability); */
1498 : NS_IMETHODIMP
1499 0 : FullTrustSecMan::IsCapabilityEnabled(const char *capability, bool *_retval)
1500 : {
1501 0 : *_retval = true;
1502 0 : return NS_OK;
1503 : }
1504 :
1505 : /* void enableCapability (in string capability); */
1506 : NS_IMETHODIMP
1507 0 : FullTrustSecMan::EnableCapability(const char *capability)
1508 : {
1509 0 : return NS_OK;;
1510 : }
1511 :
1512 : /* void revertCapability (in string capability); */
1513 : NS_IMETHODIMP
1514 0 : FullTrustSecMan::RevertCapability(const char *capability)
1515 : {
1516 0 : return NS_OK;
1517 : }
1518 :
1519 : /* void disableCapability (in string capability); */
1520 : NS_IMETHODIMP
1521 0 : FullTrustSecMan::DisableCapability(const char *capability)
1522 : {
1523 0 : return NS_OK;
1524 : }
1525 :
1526 : /* void setCanEnableCapability (in AUTF8String certificateFingerprint, in string capability, in short canEnable); */
1527 : NS_IMETHODIMP
1528 0 : FullTrustSecMan::SetCanEnableCapability(const nsACString & certificateFingerprint,
1529 : const char *capability,
1530 : PRInt16 canEnable)
1531 : {
1532 0 : return NS_OK;
1533 : }
1534 :
1535 : /* [noscript] nsIPrincipal getObjectPrincipal (in JSContextPtr cx, in JSObjectPtr obj); */
1536 : NS_IMETHODIMP
1537 0 : FullTrustSecMan::GetObjectPrincipal(JSContext * cx, JSObject * obj,
1538 : nsIPrincipal **_retval)
1539 : {
1540 0 : NS_IF_ADDREF(*_retval = mSystemPrincipal);
1541 0 : return *_retval ? NS_OK : NS_ERROR_FAILURE;
1542 : }
1543 :
1544 : /* [noscript] boolean subjectPrincipalIsSystem (); */
1545 : NS_IMETHODIMP
1546 0 : FullTrustSecMan::SubjectPrincipalIsSystem(bool *_retval)
1547 : {
1548 0 : *_retval = true;
1549 0 : return NS_OK;
1550 : }
1551 :
1552 : /* [noscript] void checkSameOrigin (in JSContextPtr aJSContext, in nsIURI aTargetURI); */
1553 : NS_IMETHODIMP
1554 0 : FullTrustSecMan::CheckSameOrigin(JSContext * aJSContext, nsIURI *aTargetURI)
1555 : {
1556 0 : return NS_OK;
1557 : }
1558 :
1559 : /* void checkSameOriginURI (in nsIURI aSourceURI, in nsIURI aTargetURI); */
1560 : NS_IMETHODIMP
1561 0 : FullTrustSecMan::CheckSameOriginURI(nsIURI *aSourceURI, nsIURI *aTargetURI,
1562 : bool reportError)
1563 : {
1564 0 : return NS_OK;
1565 : }
1566 :
1567 : /* [noscript] nsIPrincipal getPrincipalFromContext (in JSContextPtr cx); */
1568 : NS_IMETHODIMP
1569 0 : FullTrustSecMan::GetPrincipalFromContext(JSContext * cx, nsIPrincipal **_retval)
1570 : {
1571 0 : NS_IF_ADDREF(*_retval = mSystemPrincipal);
1572 0 : return *_retval ? NS_OK : NS_ERROR_FAILURE;
1573 : }
1574 :
1575 : /* [noscript] nsIPrincipal getChannelPrincipal (in nsIChannel aChannel); */
1576 : NS_IMETHODIMP
1577 0 : FullTrustSecMan::GetChannelPrincipal(nsIChannel *aChannel, nsIPrincipal **_retval)
1578 : {
1579 0 : NS_IF_ADDREF(*_retval = mSystemPrincipal);
1580 0 : return *_retval ? NS_OK : NS_ERROR_FAILURE;
1581 : }
1582 :
1583 : /* boolean isSystemPrincipal (in nsIPrincipal aPrincipal); */
1584 : NS_IMETHODIMP
1585 0 : FullTrustSecMan::IsSystemPrincipal(nsIPrincipal *aPrincipal, bool *_retval)
1586 : {
1587 0 : *_retval = aPrincipal == mSystemPrincipal;
1588 0 : return NS_OK;
1589 : }
1590 :
1591 : NS_IMETHODIMP_(nsIPrincipal *)
1592 0 : FullTrustSecMan::GetCxSubjectPrincipal(JSContext *cx)
1593 : {
1594 0 : return mSystemPrincipal;
1595 : }
1596 :
1597 : NS_IMETHODIMP_(nsIPrincipal *)
1598 0 : FullTrustSecMan::GetCxSubjectPrincipalAndFrame(JSContext *cx, JSStackFrame **fp)
1599 : {
1600 0 : *fp = nsnull;
1601 0 : return mSystemPrincipal;
1602 : }
1603 :
1604 : /***************************************************************************/
1605 :
1606 : // #define TEST_InitClassesWithNewWrappedGlobal
1607 :
1608 : #ifdef TEST_InitClassesWithNewWrappedGlobal
1609 : // XXX hacky test code...
1610 : #include "xpctest.h"
1611 :
1612 : class TestGlobal : public nsIXPCTestNoisy, public nsIXPCScriptable
1613 : {
1614 : public:
1615 : NS_DECL_ISUPPORTS
1616 : NS_DECL_NSIXPCTESTNOISY
1617 : NS_DECL_NSIXPCSCRIPTABLE
1618 :
1619 : TestGlobal(){}
1620 : };
1621 :
1622 : NS_IMPL_ISUPPORTS2(TestGlobal, nsIXPCTestNoisy, nsIXPCScriptable)
1623 :
1624 : // The nsIXPCScriptable map declaration that will generate stubs for us...
1625 : #define XPC_MAP_CLASSNAME TestGlobal
1626 : #define XPC_MAP_QUOTED_CLASSNAME "TestGlobal"
1627 : #define XPC_MAP_FLAGS nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY |\
1628 : nsIXPCScriptable::USE_JSSTUB_FOR_DELPROPERTY |\
1629 : nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY
1630 : #include "xpc_map_end.h" /* This will #undef the above */
1631 :
1632 : NS_IMETHODIMP TestGlobal::Squawk() {return NS_OK;}
1633 :
1634 : #endif
1635 :
1636 : // uncomment to install the test 'this' translator
1637 : // #define TEST_TranslateThis
1638 :
1639 : #ifdef TEST_TranslateThis
1640 :
1641 : #include "xpctest.h"
1642 :
1643 : class nsXPCFunctionThisTranslator : public nsIXPCFunctionThisTranslator
1644 : {
1645 : public:
1646 : NS_DECL_ISUPPORTS
1647 : NS_DECL_NSIXPCFUNCTIONTHISTRANSLATOR
1648 :
1649 : nsXPCFunctionThisTranslator();
1650 : virtual ~nsXPCFunctionThisTranslator();
1651 : /* additional members */
1652 : };
1653 :
1654 : /* Implementation file */
1655 : NS_IMPL_ISUPPORTS1(nsXPCFunctionThisTranslator, nsIXPCFunctionThisTranslator)
1656 :
1657 : nsXPCFunctionThisTranslator::nsXPCFunctionThisTranslator()
1658 : {
1659 : /* member initializers and constructor code */
1660 : }
1661 :
1662 : nsXPCFunctionThisTranslator::~nsXPCFunctionThisTranslator()
1663 : {
1664 : /* destructor code */
1665 : #ifdef DEBUG_jband
1666 : printf("destroying nsXPCFunctionThisTranslator\n");
1667 : #endif
1668 : }
1669 :
1670 : /* nsISupports TranslateThis (in nsISupports aInitialThis, in nsIInterfaceInfo aInterfaceInfo, in PRUint16 aMethodIndex, out bool aHideFirstParamFromJS, out nsIIDPtr aIIDOfResult); */
1671 : NS_IMETHODIMP
1672 : nsXPCFunctionThisTranslator::TranslateThis(nsISupports *aInitialThis,
1673 : nsIInterfaceInfo *aInterfaceInfo,
1674 : PRUint16 aMethodIndex,
1675 : bool *aHideFirstParamFromJS,
1676 : nsIID * *aIIDOfResult,
1677 : nsISupports **_retval)
1678 : {
1679 : NS_IF_ADDREF(aInitialThis);
1680 : *_retval = aInitialThis;
1681 : *aHideFirstParamFromJS = false;
1682 : *aIIDOfResult = nsnull;
1683 : return NS_OK;
1684 : }
1685 :
1686 : #endif
1687 :
1688 : // ContextCallback calls are chained
1689 : static JSContextCallback gOldJSContextCallback;
1690 :
1691 : static JSBool
1692 13931 : ContextCallback(JSContext *cx, unsigned contextOp)
1693 : {
1694 13931 : if (gOldJSContextCallback && !gOldJSContextCallback(cx, contextOp))
1695 0 : return false;
1696 :
1697 13931 : if (contextOp == JSCONTEXT_NEW) {
1698 6273 : JS_SetErrorReporter(cx, my_ErrorReporter);
1699 6273 : JS_SetVersion(cx, JSVERSION_LATEST);
1700 : }
1701 13931 : return true;
1702 : }
1703 :
1704 : static bool
1705 1387 : GetCurrentWorkingDirectory(nsAString& workingDirectory)
1706 : {
1707 : #if !defined(XP_WIN) && !defined(XP_UNIX)
1708 : //XXX: your platform should really implement this
1709 : return false;
1710 : #elif XP_WIN
1711 : DWORD requiredLength = GetCurrentDirectoryW(0, NULL);
1712 : workingDirectory.SetLength(requiredLength);
1713 : GetCurrentDirectoryW(workingDirectory.Length(),
1714 : (LPWSTR)workingDirectory.BeginWriting());
1715 : // we got a trailing null there
1716 : workingDirectory.SetLength(requiredLength);
1717 : workingDirectory.Replace(workingDirectory.Length() - 1, 1, L'\\');
1718 : #elif defined(XP_UNIX)
1719 2774 : nsCAutoString cwd;
1720 : // 1024 is just a guess at a sane starting value
1721 1387 : size_t bufsize = 1024;
1722 1387 : char* result = nsnull;
1723 4161 : while (result == nsnull) {
1724 1387 : if (!cwd.SetLength(bufsize))
1725 0 : return false;
1726 1387 : result = getcwd(cwd.BeginWriting(), cwd.Length());
1727 1387 : if (!result) {
1728 0 : if (errno != ERANGE)
1729 0 : return false;
1730 : // need to make the buffer bigger
1731 0 : bufsize *= 2;
1732 : }
1733 : }
1734 : // size back down to the actual string length
1735 1387 : cwd.SetLength(strlen(result) + 1);
1736 1387 : cwd.Replace(cwd.Length() - 1, 1, '/');
1737 1387 : workingDirectory = NS_ConvertUTF8toUTF16(cwd);
1738 : #endif
1739 1387 : return true;
1740 : }
1741 :
1742 : static JSPrincipals *
1743 553 : FindObjectPrincipals(JSObject *obj)
1744 : {
1745 553 : return gJSPrincipals;
1746 : }
1747 :
1748 : static JSSecurityCallbacks shellSecurityCallbacks;
1749 :
1750 : int
1751 1387 : main(int argc, char **argv, char **envp)
1752 : {
1753 : #ifdef XP_MACOSX
1754 : InitAutoreleasePool();
1755 : #endif
1756 : JSRuntime *rt;
1757 : JSContext *cx;
1758 : JSObject *glob, *envobj;
1759 : int result;
1760 : nsresult rv;
1761 :
1762 : #ifdef HAVE_SETBUF
1763 : // unbuffer stdout so that output is in the correct order; note that stderr
1764 : // is unbuffered by default
1765 1387 : setbuf(stdout, 0);
1766 : #endif
1767 :
1768 : #ifdef XRE_HAS_DLL_BLOCKLIST
1769 : XRE_SetupDllBlocklist();
1770 : #endif
1771 :
1772 1387 : gErrFile = stderr;
1773 1387 : gOutFile = stdout;
1774 1387 : gInFile = stdin;
1775 :
1776 1387 : NS_LogInit();
1777 :
1778 2774 : nsCOMPtr<nsILocalFile> appFile;
1779 1387 : rv = XRE_GetBinaryPath(argv[0], getter_AddRefs(appFile));
1780 1387 : if (NS_FAILED(rv)) {
1781 0 : printf("Couldn't find application file.\n");
1782 0 : return 1;
1783 : }
1784 2774 : nsCOMPtr<nsIFile> appDir;
1785 1387 : rv = appFile->GetParent(getter_AddRefs(appDir));
1786 1387 : if (NS_FAILED(rv)) {
1787 0 : printf("Couldn't get application directory.\n");
1788 0 : return 1;
1789 : }
1790 :
1791 2774 : XPCShellDirProvider dirprovider;
1792 :
1793 1387 : if (argc > 1 && !strcmp(argv[1], "-g")) {
1794 1386 : if (argc < 3)
1795 0 : return usage();
1796 :
1797 1386 : if (!dirprovider.SetGREDir(argv[2])) {
1798 0 : printf("SetGREDir failed.\n");
1799 0 : return 1;
1800 : }
1801 1386 : argc -= 2;
1802 1386 : argv += 2;
1803 : }
1804 :
1805 1387 : if (argc > 1 && !strcmp(argv[1], "-a")) {
1806 1386 : if (argc < 3)
1807 0 : return usage();
1808 :
1809 2772 : nsCOMPtr<nsILocalFile> dir;
1810 1386 : rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(dir));
1811 1386 : if (NS_SUCCEEDED(rv)) {
1812 1386 : appDir = do_QueryInterface(dir, &rv);
1813 : }
1814 1386 : if (NS_FAILED(rv)) {
1815 0 : printf("Couldn't use given appdir.\n");
1816 0 : return 1;
1817 : }
1818 1386 : argc -= 2;
1819 2772 : argv += 2;
1820 : }
1821 :
1822 4160 : while (argc > 1 && !strcmp(argv[1], "-r")) {
1823 1386 : if (argc < 3)
1824 0 : return usage();
1825 :
1826 2772 : nsCOMPtr<nsILocalFile> lf;
1827 1386 : rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(lf));
1828 1386 : if (NS_FAILED(rv)) {
1829 0 : printf("Couldn't get manifest file.\n");
1830 0 : return 1;
1831 : }
1832 1386 : XRE_AddManifestLocation(NS_COMPONENT_LOCATION, lf);
1833 :
1834 1386 : argc -= 2;
1835 2772 : argv += 2;
1836 : }
1837 :
1838 : {
1839 1387 : if (argc > 1 && !strcmp(argv[1], "--greomni")) {
1840 0 : nsCOMPtr<nsILocalFile> greOmni;
1841 0 : nsCOMPtr<nsILocalFile> appOmni;
1842 0 : XRE_GetFileFromPath(argv[2], getter_AddRefs(greOmni));
1843 0 : if (argc > 3 && !strcmp(argv[3], "--appomni")) {
1844 0 : XRE_GetFileFromPath(argv[4], getter_AddRefs(appOmni));
1845 0 : argc-=2;
1846 0 : argv+=2;
1847 : } else {
1848 0 : appOmni = greOmni;
1849 : }
1850 :
1851 0 : XRE_InitOmnijar(greOmni, appOmni);
1852 0 : argc-=2;
1853 0 : argv+=2;
1854 : }
1855 :
1856 2774 : nsCOMPtr<nsIServiceManager> servMan;
1857 1387 : rv = NS_InitXPCOM2(getter_AddRefs(servMan), appDir, &dirprovider);
1858 1387 : if (NS_FAILED(rv)) {
1859 0 : printf("NS_InitXPCOM2 failed!\n");
1860 0 : return 1;
1861 : }
1862 :
1863 2774 : nsCOMPtr<nsIJSRuntimeService> rtsvc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
1864 : // get the JSRuntime from the runtime svc
1865 1387 : if (!rtsvc) {
1866 0 : printf("failed to get nsJSRuntimeService!\n");
1867 0 : return 1;
1868 : }
1869 :
1870 1387 : if (NS_FAILED(rtsvc->GetRuntime(&rt)) || !rt) {
1871 0 : printf("failed to get JSRuntime from nsJSRuntimeService!\n");
1872 0 : return 1;
1873 : }
1874 :
1875 1387 : gOldJSContextCallback = JS_SetContextCallback(rt, ContextCallback);
1876 :
1877 1387 : cx = JS_NewContext(rt, 8192);
1878 1387 : if (!cx) {
1879 0 : printf("JS_NewContext failed!\n");
1880 0 : return 1;
1881 : }
1882 :
1883 1387 : xpc_LocalizeContext(cx);
1884 :
1885 2774 : nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
1886 1387 : if (!xpc) {
1887 0 : printf("failed to get nsXPConnect service!\n");
1888 0 : return 1;
1889 : }
1890 :
1891 : // Since the caps security system might set a default security manager
1892 : // we will be sure that the secman on this context gives full trust.
1893 2774 : nsRefPtr<FullTrustSecMan> secman = new FullTrustSecMan();
1894 1387 : xpc->SetSecurityManagerForJSContext(cx, secman, 0xFFFF);
1895 :
1896 2774 : nsCOMPtr<nsIPrincipal> systemprincipal;
1897 :
1898 : // Fetch the system principal and store it away in a global, to use for
1899 : // script compilation in Load() and ProcessFile() (including interactive
1900 : // eval loop)
1901 : {
1902 :
1903 : nsCOMPtr<nsIScriptSecurityManager> securityManager =
1904 2774 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
1905 1387 : if (NS_SUCCEEDED(rv) && securityManager) {
1906 1387 : rv = securityManager->GetSystemPrincipal(getter_AddRefs(systemprincipal));
1907 1387 : if (NS_FAILED(rv)) {
1908 0 : fprintf(gErrFile, "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager service.\n");
1909 : } else {
1910 : // fetch the JS principals and stick in a global
1911 1387 : gJSPrincipals = nsJSPrincipals::get(systemprincipal);
1912 1387 : JS_HoldPrincipals(gJSPrincipals);
1913 1387 : secman->SetSystemPrincipal(systemprincipal);
1914 : }
1915 : } else {
1916 0 : fprintf(gErrFile, "+++ Failed to get ScriptSecurityManager service, running without principals");
1917 : }
1918 : }
1919 :
1920 1387 : const JSSecurityCallbacks *scb = JS_GetSecurityCallbacks(rt);
1921 1387 : NS_ASSERTION(scb, "We are assuming that nsScriptSecurityManager::Init() has been run");
1922 1387 : shellSecurityCallbacks = *scb;
1923 1387 : shellSecurityCallbacks.findObjectPrincipals = FindObjectPrincipals;
1924 1387 : JS_SetSecurityCallbacks(rt, &shellSecurityCallbacks);
1925 :
1926 : #ifdef TEST_TranslateThis
1927 : nsCOMPtr<nsIXPCFunctionThisTranslator>
1928 : translator(new nsXPCFunctionThisTranslator);
1929 : xpc->SetFunctionThisTranslator(NS_GET_IID(nsITestXPCFunctionCallback), translator, nsnull);
1930 : #endif
1931 :
1932 2774 : nsCOMPtr<nsIJSContextStack> cxstack = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
1933 1387 : if (!cxstack) {
1934 0 : printf("failed to get the nsThreadJSContextStack service!\n");
1935 0 : return 1;
1936 : }
1937 :
1938 1387 : if (NS_FAILED(cxstack->Push(cx))) {
1939 0 : printf("failed to push the current JSContext on the nsThreadJSContextStack!\n");
1940 0 : return 1;
1941 : }
1942 :
1943 2774 : nsCOMPtr<nsIXPCScriptable> backstagePass;
1944 1387 : nsresult rv = rtsvc->GetBackstagePass(getter_AddRefs(backstagePass));
1945 1387 : if (NS_FAILED(rv)) {
1946 : fprintf(gErrFile, "+++ Failed to get backstage pass from rtsvc: %8x\n",
1947 0 : rv);
1948 0 : return 1;
1949 : }
1950 :
1951 2774 : nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
1952 1387 : rv = xpc->InitClassesWithNewWrappedGlobal(cx, backstagePass,
1953 : systemprincipal,
1954 : nsIXPConnect::
1955 : FLAG_SYSTEM_GLOBAL_OBJECT,
1956 1387 : getter_AddRefs(holder));
1957 1387 : if (NS_FAILED(rv))
1958 0 : return 1;
1959 :
1960 1387 : rv = holder->GetJSObject(&glob);
1961 1387 : if (NS_FAILED(rv)) {
1962 0 : NS_ASSERTION(glob == nsnull, "bad GetJSObject?");
1963 0 : return 1;
1964 : }
1965 :
1966 1387 : JS_BeginRequest(cx);
1967 : {
1968 2774 : JSAutoEnterCompartment ac;
1969 1387 : if (!ac.enter(cx, glob)) {
1970 0 : JS_EndRequest(cx);
1971 0 : return 1;
1972 : }
1973 :
1974 1387 : if (!JS_InitReflect(cx, glob)) {
1975 0 : JS_EndRequest(cx);
1976 0 : return 1;
1977 : }
1978 :
1979 2774 : if (!JS_DefineFunctions(cx, glob, glob_functions) ||
1980 1387 : !JS_DefineProfilingFunctions(cx, glob)) {
1981 0 : JS_EndRequest(cx);
1982 0 : return 1;
1983 : }
1984 :
1985 1387 : envobj = JS_DefineObject(cx, glob, "environment", &env_class, NULL, 0);
1986 1387 : if (!envobj) {
1987 0 : JS_EndRequest(cx);
1988 0 : return 1;
1989 : }
1990 :
1991 1387 : JS_SetPrivate(envobj, envp);
1992 :
1993 4161 : nsAutoString workingDirectory;
1994 1387 : if (GetCurrentWorkingDirectory(workingDirectory))
1995 1387 : gWorkingDirectory = &workingDirectory;
1996 :
1997 : JS_DefineProperty(cx, glob, "__LOCATION__", JSVAL_VOID,
1998 1387 : GetLocationProperty, NULL, 0);
1999 :
2000 1387 : argc--;
2001 1387 : argv++;
2002 :
2003 1387 : result = ProcessArgs(cx, glob, argv, argc);
2004 :
2005 :
2006 : //#define TEST_CALL_ON_WRAPPED_JS_AFTER_SHUTDOWN 1
2007 :
2008 : #ifdef TEST_CALL_ON_WRAPPED_JS_AFTER_SHUTDOWN
2009 : // test of late call and release (see below)
2010 : nsCOMPtr<nsIJSContextStack> bogus;
2011 : xpc->WrapJS(cx, glob, NS_GET_IID(nsIJSContextStack),
2012 : (void**) getter_AddRefs(bogus));
2013 : #endif
2014 1387 : JS_DropPrincipals(rt, gJSPrincipals);
2015 1387 : JS_ClearScope(cx, glob);
2016 1387 : JS_GC(cx);
2017 : JSContext *oldcx;
2018 1387 : cxstack->Pop(&oldcx);
2019 1387 : NS_ASSERTION(oldcx == cx, "JS thread context push/pop mismatch");
2020 1387 : cxstack = nsnull;
2021 1387 : JS_GC(cx);
2022 : } //this scopes the JSAutoCrossCompartmentCall
2023 1387 : JS_EndRequest(cx);
2024 2774 : JS_DestroyContext(cx);
2025 : } // this scopes the nsCOMPtrs
2026 :
2027 1387 : if (!XRE_ShutdownTestShell())
2028 0 : NS_ERROR("problem shutting down testshell");
2029 :
2030 : #ifdef MOZ_CRASHREPORTER
2031 : // Get the crashreporter service while XPCOM is still active.
2032 : // This is a special exception: it will remain usable after NS_ShutdownXPCOM().
2033 : nsCOMPtr<nsICrashReporter> crashReporter =
2034 2774 : do_GetService("@mozilla.org/toolkit/crash-reporter;1");
2035 : #endif
2036 :
2037 : // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
2038 1387 : rv = NS_ShutdownXPCOM( NULL );
2039 1387 : NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed");
2040 :
2041 : #ifdef TEST_CALL_ON_WRAPPED_JS_AFTER_SHUTDOWN
2042 : // test of late call and release (see above)
2043 : JSContext* bogusCX;
2044 : bogus->Peek(&bogusCX);
2045 : bogus = nsnull;
2046 : #endif
2047 :
2048 1387 : appDir = nsnull;
2049 1387 : appFile = nsnull;
2050 1387 : dirprovider.ClearGREDir();
2051 :
2052 : #ifdef MOZ_CRASHREPORTER
2053 : // Shut down the crashreporter service to prevent leaking some strings it holds.
2054 1387 : if (crashReporter) {
2055 1387 : crashReporter->SetEnabled(false);
2056 1387 : crashReporter = nsnull;
2057 : }
2058 : #endif
2059 :
2060 1387 : NS_LogTerm();
2061 :
2062 : #ifdef XP_MACOSX
2063 : FinishAutoreleasePool();
2064 : #endif
2065 :
2066 1387 : return result;
2067 : }
2068 :
2069 : bool
2070 1386 : XPCShellDirProvider::SetGREDir(const char *dir)
2071 : {
2072 1386 : nsresult rv = XRE_GetFileFromPath(dir, getter_AddRefs(mGREDir));
2073 1386 : return NS_SUCCEEDED(rv);
2074 : }
2075 :
2076 : NS_IMETHODIMP_(nsrefcnt)
2077 20955 : XPCShellDirProvider::AddRef()
2078 : {
2079 20955 : return 2;
2080 : }
2081 :
2082 : NS_IMETHODIMP_(nsrefcnt)
2083 20955 : XPCShellDirProvider::Release()
2084 : {
2085 20955 : return 1;
2086 : }
2087 :
2088 19568 : NS_IMPL_QUERY_INTERFACE2(XPCShellDirProvider,
2089 : nsIDirectoryServiceProvider,
2090 : nsIDirectoryServiceProvider2)
2091 :
2092 : NS_IMETHODIMP
2093 15226 : XPCShellDirProvider::GetFile(const char *prop, bool *persistent,
2094 : nsIFile* *result)
2095 : {
2096 15226 : if (mGREDir && !strcmp(prop, NS_GRE_DIR)) {
2097 1386 : *persistent = true;
2098 1386 : return mGREDir->Clone(result);
2099 13840 : } else if (mGREDir && !strcmp(prop, NS_APP_PREF_DEFAULTS_50_DIR)) {
2100 2772 : nsCOMPtr<nsIFile> file;
2101 1386 : *persistent = true;
2102 8316 : if (NS_FAILED(mGREDir->Clone(getter_AddRefs(file))) ||
2103 4158 : NS_FAILED(file->AppendNative(NS_LITERAL_CSTRING("defaults"))) ||
2104 4158 : NS_FAILED(file->AppendNative(NS_LITERAL_CSTRING("pref"))))
2105 0 : return NS_ERROR_FAILURE;
2106 1386 : NS_ADDREF(*result = file);
2107 1386 : return NS_OK;
2108 : }
2109 :
2110 12454 : return NS_ERROR_FAILURE;
2111 : }
2112 :
2113 : NS_IMETHODIMP
2114 2955 : XPCShellDirProvider::GetFiles(const char *prop, nsISimpleEnumerator* *result)
2115 : {
2116 2955 : if (mGREDir && !strcmp(prop, "ChromeML")) {
2117 0 : nsCOMArray<nsIFile> dirs;
2118 :
2119 0 : nsCOMPtr<nsIFile> file;
2120 0 : mGREDir->Clone(getter_AddRefs(file));
2121 0 : file->AppendNative(NS_LITERAL_CSTRING("chrome"));
2122 0 : dirs.AppendObject(file);
2123 :
2124 : nsresult rv = NS_GetSpecialDirectory(NS_APP_CHROME_DIR,
2125 0 : getter_AddRefs(file));
2126 0 : if (NS_SUCCEEDED(rv))
2127 0 : dirs.AppendObject(file);
2128 :
2129 0 : return NS_NewArrayEnumerator(result, dirs);
2130 2955 : } else if (!strcmp(prop, NS_APP_PREFS_DEFAULTS_DIR_LIST)) {
2131 2778 : nsCOMArray<nsIFile> dirs;
2132 :
2133 2778 : nsCOMPtr<nsIFile> file;
2134 8334 : if (NS_FAILED(NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR,
2135 : getter_AddRefs(file))) ||
2136 4167 : NS_FAILED(file->AppendNative(NS_LITERAL_CSTRING("defaults"))) ||
2137 4167 : NS_FAILED(file->AppendNative(NS_LITERAL_CSTRING("preferences"))))
2138 0 : return NS_ERROR_FAILURE;
2139 :
2140 1389 : dirs.AppendObject(file);
2141 1389 : return NS_NewArrayEnumerator(result, dirs);
2142 : }
2143 1566 : return NS_ERROR_FAILURE;
2144 : }
|