Bug 435853 Running xpcshell tests involving Mac components leaks memory due to not...
[mozilla-central.git] / js / src / xpconnect / shell / xpcshell.cpp
blobeb0e8e2f943380b866b59d2d1248ab931d44fadf
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=2 sw=4 et tw=80:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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.
17 * The Original Code is Mozilla Communicator client code, released
18 * March 31, 1998.
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.
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>
31 * Alternatively, the contents of this file may be used under the terms of
32 * either of the GNU General Public License Version 2 or later (the "GPL"),
33 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34 * in which case the provisions of the GPL or the LGPL are applicable instead
35 * of those above. If you wish to allow use of your version of this file only
36 * under the terms of either the GPL or the LGPL, and not to allow others to
37 * use your version of this file under the terms of the MPL, indicate your
38 * decision by deleting the provisions above and replace them with the notice
39 * and other provisions required by the GPL or the LGPL. If you do not delete
40 * the provisions above, a recipient may use your version of this file under
41 * the terms of any one of the MPL, the GPL or the LGPL.
43 * ***** END LICENSE BLOCK ***** */
45 /* XPConnect JavaScript interactive shell. */
47 #include <stdio.h>
48 #include "nsServiceManagerUtils.h"
49 #include "nsComponentManagerUtils.h"
50 #include "nsIXPConnect.h"
51 #include "nsIXPCScriptable.h"
52 #include "nsIInterfaceInfo.h"
53 #include "nsIInterfaceInfoManager.h"
54 #include "nsIXPCScriptable.h"
55 #include "nsIServiceManager.h"
56 #include "nsIComponentManager.h"
57 #include "nsIComponentRegistrar.h"
58 #include "jsapi.h"
59 #include "jsprf.h"
60 #include "nscore.h"
61 #include "nsMemory.h"
62 #include "nsIGenericFactory.h"
63 #include "nsIJSRuntimeService.h"
64 #include "nsCOMPtr.h"
65 #include "nsAutoPtr.h"
66 #include "nsIXPCSecurityManager.h"
67 #ifdef XP_MACOSX
68 #include "xpcshellMacUtils.h"
69 #endif
71 #ifndef XPCONNECT_STANDALONE
72 #include "nsIScriptSecurityManager.h"
73 #include "nsIPrincipal.h"
74 #endif
76 // all this crap is needed to do the interactive shell stuff
77 #include <stdlib.h>
78 #include <errno.h>
79 #if defined(XP_WIN) || defined(XP_OS2)
80 #include <io.h> /* for isatty() */
81 #elif defined(XP_UNIX) || defined(XP_BEOS)
82 #include <unistd.h> /* for isatty() */
83 #endif
85 #include "nsIJSContextStack.h"
87 #ifdef MOZ_SHARK
88 #include "jsdbgapi.h"
89 #endif
91 /***************************************************************************/
93 #ifdef JS_THREADSAFE
94 #define DoBeginRequest(cx) JS_BeginRequest((cx))
95 #define DoEndRequest(cx) JS_EndRequest((cx))
96 #else
97 #define DoBeginRequest(cx) ((void)0)
98 #define DoEndRequest(cx) ((void)0)
99 #endif
101 /***************************************************************************/
103 #define EXITCODE_RUNTIME_ERROR 3
104 #define EXITCODE_FILE_NOT_FOUND 4
106 FILE *gOutFile = NULL;
107 FILE *gErrFile = NULL;
109 int gExitCode = 0;
110 JSBool gQuitting = JS_FALSE;
111 static JSBool reportWarnings = JS_TRUE;
112 static JSBool compileOnly = JS_FALSE;
114 JSPrincipals *gJSPrincipals = nsnull;
116 JS_STATIC_DLL_CALLBACK(void)
117 my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
119 int i, j, k, n;
120 char *prefix = NULL, *tmp;
121 const char *ctmp;
123 if (!report) {
124 fprintf(gErrFile, "%s\n", message);
125 return;
128 /* Conditionally ignore reported warnings. */
129 if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings)
130 return;
132 if (report->filename)
133 prefix = JS_smprintf("%s:", report->filename);
134 if (report->lineno) {
135 tmp = prefix;
136 prefix = JS_smprintf("%s%u: ", tmp ? tmp : "", report->lineno);
137 JS_free(cx, tmp);
139 if (JSREPORT_IS_WARNING(report->flags)) {
140 tmp = prefix;
141 prefix = JS_smprintf("%s%swarning: ",
142 tmp ? tmp : "",
143 JSREPORT_IS_STRICT(report->flags) ? "strict " : "");
144 JS_free(cx, tmp);
147 /* embedded newlines -- argh! */
148 while ((ctmp = strchr(message, '\n')) != 0) {
149 ctmp++;
150 if (prefix) fputs(prefix, gErrFile);
151 fwrite(message, 1, ctmp - message, gErrFile);
152 message = ctmp;
154 /* If there were no filename or lineno, the prefix might be empty */
155 if (prefix)
156 fputs(prefix, gErrFile);
157 fputs(message, gErrFile);
159 if (!report->linebuf) {
160 fputc('\n', gErrFile);
161 goto out;
164 fprintf(gErrFile, ":\n%s%s\n%s", prefix, report->linebuf, prefix);
165 n = report->tokenptr - report->linebuf;
166 for (i = j = 0; i < n; i++) {
167 if (report->linebuf[i] == '\t') {
168 for (k = (j + 8) & ~7; j < k; j++) {
169 fputc('.', gErrFile);
171 continue;
173 fputc('.', gErrFile);
174 j++;
176 fputs("^\n", gErrFile);
177 out:
178 if (!JSREPORT_IS_WARNING(report->flags))
179 gExitCode = EXITCODE_RUNTIME_ERROR;
180 JS_free(cx, prefix);
183 JS_STATIC_DLL_CALLBACK(JSBool)
184 Print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
186 uintN i, n;
187 JSString *str;
189 for (i = n = 0; i < argc; i++) {
190 str = JS_ValueToString(cx, argv[i]);
191 if (!str)
192 return JS_FALSE;
193 fprintf(gOutFile, "%s%s", i ? " " : "", JS_GetStringBytes(str));
195 n++;
196 if (n)
197 fputc('\n', gOutFile);
198 return JS_TRUE;
201 JS_STATIC_DLL_CALLBACK(JSBool)
202 Dump(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
204 JSString *str;
205 if (!argc)
206 return JS_TRUE;
208 str = JS_ValueToString(cx, argv[0]);
209 if (!str)
210 return JS_FALSE;
212 char *bytes = JS_GetStringBytes(str);
213 bytes = strdup(bytes);
215 fputs(bytes, gOutFile);
216 free(bytes);
217 return JS_TRUE;
220 JS_STATIC_DLL_CALLBACK(JSBool)
221 Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
223 uintN i;
224 JSString *str;
225 const char *filename;
226 JSScript *script;
227 JSBool ok;
228 jsval result;
229 FILE *file;
231 for (i = 0; i < argc; i++) {
232 str = JS_ValueToString(cx, argv[i]);
233 if (!str)
234 return JS_FALSE;
235 argv[i] = STRING_TO_JSVAL(str);
236 filename = JS_GetStringBytes(str);
237 file = fopen(filename, "r");
238 script = JS_CompileFileHandleForPrincipals(cx, obj, filename, file,
239 gJSPrincipals);
240 if (!script)
241 ok = JS_FALSE;
242 else {
243 ok = !compileOnly
244 ? JS_ExecuteScript(cx, obj, script, &result)
245 : JS_TRUE;
246 JS_DestroyScript(cx, script);
248 if (!ok)
249 return JS_FALSE;
251 return JS_TRUE;
254 JS_STATIC_DLL_CALLBACK(JSBool)
255 Version(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
257 if (argc > 0 && JSVAL_IS_INT(argv[0]))
258 *rval = INT_TO_JSVAL(JS_SetVersion(cx, JSVersion(JSVAL_TO_INT(argv[0]))));
259 else
260 *rval = INT_TO_JSVAL(JS_GetVersion(cx));
261 return JS_TRUE;
264 JS_STATIC_DLL_CALLBACK(JSBool)
265 BuildDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
267 fprintf(gOutFile, "built on %s at %s\n", __DATE__, __TIME__);
268 return JS_TRUE;
271 JS_STATIC_DLL_CALLBACK(JSBool)
272 Quit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
274 #ifdef LIVECONNECT
275 JSJ_SimpleShutdown();
276 #endif
278 gExitCode = 0;
279 JS_ConvertArguments(cx, argc, argv,"/ i", &gExitCode);
281 gQuitting = JS_TRUE;
282 // exit(0);
283 return JS_FALSE;
286 JS_STATIC_DLL_CALLBACK(JSBool)
287 DumpXPC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
289 int32 depth = 2;
291 if (argc > 0) {
292 if (!JS_ValueToInt32(cx, argv[0], &depth))
293 return JS_FALSE;
296 nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
297 if(xpc)
298 xpc->DebugDump((int16)depth);
299 return JS_TRUE;
302 /* XXX needed only by GC() */
303 #include "jscntxt.h"
305 JS_STATIC_DLL_CALLBACK(JSBool)
306 GC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
308 JSRuntime *rt;
309 uint32 preBytes;
311 rt = cx->runtime;
312 preBytes = rt->gcBytes;
313 JS_GC(cx);
314 fprintf(gOutFile, "before %lu, after %lu, break %08lx\n",
315 (unsigned long)preBytes, (unsigned long)rt->gcBytes,
316 #ifdef XP_UNIX
317 (unsigned long)sbrk(0)
318 #else
320 #endif
322 #ifdef JS_GCMETER
323 js_DumpGCStats(rt, stdout);
324 #endif
325 return JS_TRUE;
328 #ifdef DEBUG
330 static JSBool
331 DumpHeap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
333 char *fileName = NULL;
334 void* startThing = NULL;
335 uint32 startTraceKind = 0;
336 void *thingToFind = NULL;
337 size_t maxDepth = (size_t)-1;
338 void *thingToIgnore = NULL;
339 jsval *vp;
340 FILE *dumpFile;
341 JSBool ok;
343 vp = &argv[0];
344 if (*vp != JSVAL_NULL && *vp != JSVAL_VOID) {
345 JSString *str;
347 str = JS_ValueToString(cx, *vp);
348 if (!str)
349 return JS_FALSE;
350 *vp = STRING_TO_JSVAL(str);
351 fileName = JS_GetStringBytes(str);
354 vp = &argv[1];
355 if (*vp != JSVAL_NULL && *vp != JSVAL_VOID) {
356 if (!JSVAL_IS_TRACEABLE(*vp))
357 goto not_traceable_arg;
358 startThing = JSVAL_TO_TRACEABLE(*vp);
359 startTraceKind = JSVAL_TRACE_KIND(*vp);
362 vp = &argv[2];
363 if (*vp != JSVAL_NULL && *vp != JSVAL_VOID) {
364 if (!JSVAL_IS_TRACEABLE(*vp))
365 goto not_traceable_arg;
366 thingToFind = JSVAL_TO_TRACEABLE(*vp);
369 vp = &argv[3];
370 if (*vp != JSVAL_NULL && *vp != JSVAL_VOID) {
371 uint32 depth;
373 if (!JS_ValueToECMAUint32(cx, *vp, &depth))
374 return JS_FALSE;
375 maxDepth = depth;
378 vp = &argv[4];
379 if (*vp != JSVAL_NULL && *vp != JSVAL_VOID) {
380 if (!JSVAL_IS_TRACEABLE(*vp))
381 goto not_traceable_arg;
382 thingToIgnore = JSVAL_TO_TRACEABLE(*vp);
385 if (!fileName) {
386 dumpFile = gOutFile;
387 } else {
388 dumpFile = fopen(fileName, "w");
389 if (!dumpFile) {
390 fprintf(gErrFile, "dumpHeap: can't open %s: %s\n",
391 fileName, strerror(errno));
392 return JS_FALSE;
396 ok = JS_DumpHeap(cx, dumpFile, startThing, startTraceKind, thingToFind,
397 maxDepth, thingToIgnore);
398 if (dumpFile != gOutFile)
399 fclose(dumpFile);
400 return ok;
402 not_traceable_arg:
403 fprintf(gErrFile,
404 "dumpHeap: argument %u is not null or a heap-allocated thing\n",
405 (unsigned)(vp - argv));
406 return JS_FALSE;
409 #endif /* DEBUG */
411 JS_STATIC_DLL_CALLBACK(JSBool)
412 Clear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
414 if (argc > 0 && !JSVAL_IS_PRIMITIVE(argv[0])) {
415 JS_ClearScope(cx, JSVAL_TO_OBJECT(argv[0]));
416 } else {
417 JS_ReportError(cx, "'clear' requires an object");
418 return JS_FALSE;
420 return JS_TRUE;
423 static JSFunctionSpec glob_functions[] = {
424 {"print", Print, 0,0,0},
425 {"load", Load, 1,0,0},
426 {"quit", Quit, 0,0,0},
427 {"version", Version, 1,0,0},
428 {"build", BuildDate, 0,0,0},
429 {"dumpXPC", DumpXPC, 1,0,0},
430 {"dump", Dump, 1,0,0},
431 {"gc", GC, 0,0,0},
432 {"clear", Clear, 1,0,0},
433 #ifdef DEBUG
434 {"dumpHeap", DumpHeap, 5,0,0},
435 #endif
436 #ifdef MOZ_SHARK
437 {"startShark", js_StartShark, 0,0,0},
438 {"stopShark", js_StopShark, 0,0,0},
439 {"connectShark", js_ConnectShark, 0,0,0},
440 {"disconnectShark", js_DisconnectShark, 0,0,0},
441 #endif
442 {nsnull,nsnull,0,0,0}
445 JSClass global_class = {
446 "global", 0,
447 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
448 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
451 static JSBool
452 env_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
454 /* XXX porting may be easy, but these don't seem to supply setenv by default */
455 #if !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS
456 JSString *idstr, *valstr;
457 const char *name, *value;
458 int rv;
460 idstr = JS_ValueToString(cx, id);
461 valstr = JS_ValueToString(cx, *vp);
462 if (!idstr || !valstr)
463 return JS_FALSE;
464 name = JS_GetStringBytes(idstr);
465 value = JS_GetStringBytes(valstr);
466 #if defined XP_WIN || defined HPUX || defined OSF1 || defined IRIX \
467 || defined SCO
469 char *waste = JS_smprintf("%s=%s", name, value);
470 if (!waste) {
471 JS_ReportOutOfMemory(cx);
472 return JS_FALSE;
474 rv = putenv(waste);
475 #ifdef XP_WIN
477 * HPUX9 at least still has the bad old non-copying putenv.
479 * Per mail from <s.shanmuganathan@digital.com>, OSF1 also has a putenv
480 * that will crash if you pass it an auto char array (so it must place
481 * its argument directly in the char *environ[] array).
483 free(waste);
484 #endif
486 #else
487 rv = setenv(name, value, 1);
488 #endif
489 if (rv < 0) {
490 JS_ReportError(cx, "can't set envariable %s to %s", name, value);
491 return JS_FALSE;
493 *vp = STRING_TO_JSVAL(valstr);
494 #endif /* !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS */
495 return JS_TRUE;
498 static JSBool
499 env_enumerate(JSContext *cx, JSObject *obj)
501 static JSBool reflected;
502 char **evp, *name, *value;
503 JSString *valstr;
504 JSBool ok;
506 if (reflected)
507 return JS_TRUE;
509 for (evp = (char **)JS_GetPrivate(cx, obj); (name = *evp) != NULL; evp++) {
510 value = strchr(name, '=');
511 if (!value)
512 continue;
513 *value++ = '\0';
514 valstr = JS_NewStringCopyZ(cx, value);
515 if (!valstr) {
516 ok = JS_FALSE;
517 } else {
518 ok = JS_DefineProperty(cx, obj, name, STRING_TO_JSVAL(valstr),
519 NULL, NULL, JSPROP_ENUMERATE);
521 value[-1] = '=';
522 if (!ok)
523 return JS_FALSE;
526 reflected = JS_TRUE;
527 return JS_TRUE;
530 static JSBool
531 env_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
532 JSObject **objp)
534 JSString *idstr, *valstr;
535 const char *name, *value;
537 if (flags & JSRESOLVE_ASSIGNING)
538 return JS_TRUE;
540 idstr = JS_ValueToString(cx, id);
541 if (!idstr)
542 return JS_FALSE;
543 name = JS_GetStringBytes(idstr);
544 value = getenv(name);
545 if (value) {
546 valstr = JS_NewStringCopyZ(cx, value);
547 if (!valstr)
548 return JS_FALSE;
549 if (!JS_DefineProperty(cx, obj, name, STRING_TO_JSVAL(valstr),
550 NULL, NULL, JSPROP_ENUMERATE)) {
551 return JS_FALSE;
553 *objp = obj;
555 return JS_TRUE;
558 static JSClass env_class = {
559 "environment", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
560 JS_PropertyStub, JS_PropertyStub,
561 JS_PropertyStub, env_setProperty,
562 env_enumerate, (JSResolveOp) env_resolve,
563 JS_ConvertStub, JS_FinalizeStub
566 /***************************************************************************/
568 typedef enum JSShellErrNum {
569 #define MSG_DEF(name, number, count, exception, format) \
570 name = number,
571 #include "jsshell.msg"
572 #undef MSG_DEF
573 JSShellErr_Limit
574 #undef MSGDEF
575 } JSShellErrNum;
577 JSErrorFormatString jsShell_ErrorFormatString[JSErr_Limit] = {
578 #if JS_HAS_DFLT_MSG_STRINGS
579 #define MSG_DEF(name, number, count, exception, format) \
580 { format, count } ,
581 #else
582 #define MSG_DEF(name, number, count, exception, format) \
583 { NULL, count } ,
584 #endif
585 #include "jsshell.msg"
586 #undef MSG_DEF
589 JS_STATIC_DLL_CALLBACK(const JSErrorFormatString *)
590 my_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber)
592 if ((errorNumber > 0) && (errorNumber < JSShellErr_Limit))
593 return &jsShell_ErrorFormatString[errorNumber];
594 else
595 return NULL;
598 #ifdef EDITLINE
599 extern "C" {
600 extern char *readline(const char *prompt);
601 extern void add_history(char *line);
603 #endif
605 static JSBool
606 GetLine(JSContext *cx, char *bufp, FILE *file, const char *prompt) {
607 #ifdef EDITLINE
609 * Use readline only if file is stdin, because there's no way to specify
610 * another handle. Are other filehandles interactive?
612 if (file == stdin) {
613 char *linep = readline(prompt);
614 if (!linep)
615 return JS_FALSE;
616 if (*linep)
617 add_history(linep);
618 strcpy(bufp, linep);
619 JS_free(cx, linep);
620 bufp += strlen(bufp);
621 *bufp++ = '\n';
622 *bufp = '\0';
623 } else
624 #endif
626 char line[256];
627 fprintf(gOutFile, prompt);
628 fflush(gOutFile);
629 if (!fgets(line, sizeof line, file))
630 return JS_FALSE;
631 strcpy(bufp, line);
633 return JS_TRUE;
636 static void
637 ProcessFile(JSContext *cx, JSObject *obj, const char *filename, FILE *file,
638 JSBool forceTTY)
640 JSScript *script;
641 jsval result;
642 int lineno, startline;
643 JSBool ok, hitEOF;
644 char *bufp, buffer[4096];
645 JSString *str;
647 if (forceTTY) {
648 file = stdin;
649 } else if (!isatty(fileno(file))) {
651 * It's not interactive - just execute it.
653 * Support the UNIX #! shell hack; gobble the first line if it starts
654 * with '#'. TODO - this isn't quite compatible with sharp variables,
655 * as a legal js program (using sharp variables) might start with '#'.
656 * But that would require multi-character lookahead.
658 int ch = fgetc(file);
659 if (ch == '#') {
660 while((ch = fgetc(file)) != EOF) {
661 if(ch == '\n' || ch == '\r')
662 break;
665 ungetc(ch, file);
666 DoBeginRequest(cx);
668 script = JS_CompileFileHandleForPrincipals(cx, obj, filename, file,
669 gJSPrincipals);
671 if (script) {
672 if (!compileOnly)
673 (void)JS_ExecuteScript(cx, obj, script, &result);
674 JS_DestroyScript(cx, script);
676 DoEndRequest(cx);
678 return;
681 /* It's an interactive filehandle; drop into read-eval-print loop. */
682 lineno = 1;
683 hitEOF = JS_FALSE;
684 do {
685 bufp = buffer;
686 *bufp = '\0';
689 * Accumulate lines until we get a 'compilable unit' - one that either
690 * generates an error (before running out of source) or that compiles
691 * cleanly. This should be whenever we get a complete statement that
692 * coincides with the end of a line.
694 startline = lineno;
695 do {
696 if (!GetLine(cx, bufp, file, startline == lineno ? "js> " : "")) {
697 hitEOF = JS_TRUE;
698 break;
700 bufp += strlen(bufp);
701 lineno++;
702 } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer)));
704 DoBeginRequest(cx);
705 /* Clear any pending exception from previous failed compiles. */
706 JS_ClearPendingException(cx);
707 script = JS_CompileScriptForPrincipals(cx, obj, gJSPrincipals, buffer,
708 strlen(buffer), "typein", startline);
709 if (script) {
710 JSErrorReporter older;
712 if (!compileOnly) {
713 ok = JS_ExecuteScript(cx, obj, script, &result);
714 if (ok && result != JSVAL_VOID) {
715 /* Suppress error reports from JS_ValueToString(). */
716 older = JS_SetErrorReporter(cx, NULL);
717 str = JS_ValueToString(cx, result);
718 JS_SetErrorReporter(cx, older);
720 if (str)
721 fprintf(gOutFile, "%s\n", JS_GetStringBytes(str));
722 else
723 ok = JS_FALSE;
726 JS_DestroyScript(cx, script);
728 DoEndRequest(cx);
729 } while (!hitEOF && !gQuitting);
731 fprintf(gOutFile, "\n");
734 static void
735 Process(JSContext *cx, JSObject *obj, const char *filename, JSBool forceTTY)
737 FILE *file;
739 if (forceTTY || !filename || strcmp(filename, "-") == 0) {
740 file = stdin;
741 } else {
742 file = fopen(filename, "r");
743 if (!file) {
744 JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
745 JSSMSG_CANT_OPEN,
746 filename, strerror(errno));
747 gExitCode = EXITCODE_FILE_NOT_FOUND;
748 return;
752 ProcessFile(cx, obj, filename, file, forceTTY);
755 static int
756 usage(void)
758 fprintf(gErrFile, "%s\n", JS_GetImplementationVersion());
759 fprintf(gErrFile, "usage: xpcshell [-PswWxCi] [-v version] [-f scriptfile] [-e script] [scriptfile] [scriptarg...]\n");
760 return 2;
763 extern JSClass global_class;
765 static int
766 ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
768 const char rcfilename[] = "xpcshell.js";
769 FILE *rcfile;
770 int i, j, length;
771 JSObject *argsObj;
772 char *filename = NULL;
773 JSBool isInteractive = JS_TRUE;
774 JSBool forceTTY = JS_FALSE;
776 rcfile = fopen(rcfilename, "r");
777 if (rcfile) {
778 printf("[loading '%s'...]\n", rcfilename);
779 ProcessFile(cx, obj, rcfilename, rcfile, JS_FALSE);
783 * Scan past all optional arguments so we can create the arguments object
784 * before processing any -f options, which must interleave properly with
785 * -v and -w options. This requires two passes, and without getopt, we'll
786 * have to keep the option logic here and in the second for loop in sync.
788 for (i = 0; i < argc; i++) {
789 if (argv[i][0] != '-' || argv[i][1] == '\0') {
790 ++i;
791 break;
793 switch (argv[i][1]) {
794 case 'v':
795 case 'f':
796 case 'e':
797 ++i;
798 break;
799 default:;
804 * Create arguments early and define it to root it, so it's safe from any
805 * GC calls nested below, and so it is available to -f <file> arguments.
807 argsObj = JS_NewArrayObject(cx, 0, NULL);
808 if (!argsObj)
809 return 1;
810 if (!JS_DefineProperty(cx, obj, "arguments", OBJECT_TO_JSVAL(argsObj),
811 NULL, NULL, 0)) {
812 return 1;
815 length = argc - i;
816 for (j = 0; j < length; j++) {
817 JSString *str = JS_NewStringCopyZ(cx, argv[i++]);
818 if (!str)
819 return 1;
820 if (!JS_DefineElement(cx, argsObj, j, STRING_TO_JSVAL(str),
821 NULL, NULL, JSPROP_ENUMERATE)) {
822 return 1;
826 for (i = 0; i < argc; i++) {
827 if (argv[i][0] != '-' || argv[i][1] == '\0') {
828 filename = argv[i++];
829 isInteractive = JS_FALSE;
830 break;
832 switch (argv[i][1]) {
833 case 'v':
834 if (++i == argc) {
835 return usage();
837 JS_SetVersion(cx, JSVersion(atoi(argv[i])));
838 break;
839 case 'W':
840 reportWarnings = JS_FALSE;
841 break;
842 case 'w':
843 reportWarnings = JS_TRUE;
844 break;
845 case 's':
846 JS_ToggleOptions(cx, JSOPTION_STRICT);
847 break;
848 case 'x':
849 JS_ToggleOptions(cx, JSOPTION_XML);
850 break;
851 case 'P':
852 if (JS_GET_CLASS(cx, JS_GetPrototype(cx, obj)) != &global_class) {
853 JSObject *gobj;
855 if (!JS_SealObject(cx, obj, JS_TRUE))
856 return JS_FALSE;
857 gobj = JS_NewObject(cx, &global_class, NULL, NULL);
858 if (!gobj)
859 return JS_FALSE;
860 if (!JS_SetPrototype(cx, gobj, obj))
861 return JS_FALSE;
862 JS_SetParent(cx, gobj, NULL);
863 JS_SetGlobalObject(cx, gobj);
864 obj = gobj;
866 break;
867 case 'f':
868 if (++i == argc) {
869 return usage();
871 Process(cx, obj, argv[i], JS_FALSE);
873 * XXX: js -f foo.js should interpret foo.js and then
874 * drop into interactive mode, but that breaks test
875 * harness. Just execute foo.js for now.
877 isInteractive = JS_FALSE;
878 break;
879 case 'i':
880 isInteractive = forceTTY = JS_TRUE;
881 break;
882 case 'e':
884 jsval rval;
886 if (++i == argc) {
887 return usage();
890 JS_EvaluateScript(cx, obj, argv[i], strlen(argv[i]),
891 "-e", 1, &rval);
893 isInteractive = JS_FALSE;
894 break;
896 case 'C':
897 compileOnly = JS_TRUE;
898 isInteractive = JS_FALSE;
899 break;
900 #ifdef MOZ_SHARK
901 case 'k':
902 JS_ConnectShark();
903 break;
904 #endif
905 default:
906 return usage();
910 if (filename || isInteractive)
911 Process(cx, obj, filename, forceTTY);
912 return gExitCode;
915 /***************************************************************************/
917 class FullTrustSecMan
918 #ifndef XPCONNECT_STANDALONE
919 : public nsIScriptSecurityManager
920 #else
921 : public nsIXPCSecurityManager
922 #endif
924 public:
925 NS_DECL_ISUPPORTS
926 NS_DECL_NSIXPCSECURITYMANAGER
927 #ifndef XPCONNECT_STANDALONE
928 NS_DECL_NSISCRIPTSECURITYMANAGER
929 #endif
931 FullTrustSecMan();
932 virtual ~FullTrustSecMan();
934 #ifndef XPCONNECT_STANDALONE
935 void SetSystemPrincipal(nsIPrincipal *aPrincipal) {
936 mSystemPrincipal = aPrincipal;
939 private:
940 nsCOMPtr<nsIPrincipal> mSystemPrincipal;
941 #endif
944 NS_INTERFACE_MAP_BEGIN(FullTrustSecMan)
945 NS_INTERFACE_MAP_ENTRY(nsIXPCSecurityManager)
946 #ifndef XPCONNECT_STANDALONE
947 NS_INTERFACE_MAP_ENTRY(nsIScriptSecurityManager)
948 #endif
949 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCSecurityManager)
950 NS_INTERFACE_MAP_END
952 NS_IMPL_ADDREF(FullTrustSecMan)
953 NS_IMPL_RELEASE(FullTrustSecMan)
955 FullTrustSecMan::FullTrustSecMan()
957 #ifndef XPCONNECT_STANDALONE
958 mSystemPrincipal = nsnull;
959 #endif
962 FullTrustSecMan::~FullTrustSecMan()
966 NS_IMETHODIMP
967 FullTrustSecMan::CanCreateWrapper(JSContext * aJSContext, const nsIID & aIID,
968 nsISupports *aObj, nsIClassInfo *aClassInfo,
969 void * *aPolicy)
971 return NS_OK;
974 NS_IMETHODIMP
975 FullTrustSecMan::CanCreateInstance(JSContext * aJSContext, const nsCID & aCID)
977 return NS_OK;
980 NS_IMETHODIMP
981 FullTrustSecMan::CanGetService(JSContext * aJSContext, const nsCID & aCID)
983 return NS_OK;
986 #ifndef XPCONNECT_STANDALONE
987 /* 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); */
988 NS_IMETHODIMP
989 FullTrustSecMan::CanAccess(PRUint32 aAction,
990 nsAXPCNativeCallContext *aCallContext,
991 JSContext * aJSContext, JSObject * aJSObject,
992 nsISupports *aObj, nsIClassInfo *aClassInfo,
993 jsval aName, void * *aPolicy)
995 return NS_OK;
998 /* [noscript] void checkPropertyAccess (in JSContextPtr aJSContext, in JSObjectPtr aJSObject, in string aClassName, in JSVal aProperty, in PRUint32 aAction); */
999 NS_IMETHODIMP
1000 FullTrustSecMan::CheckPropertyAccess(JSContext * aJSContext,
1001 JSObject * aJSObject,
1002 const char *aClassName,
1003 jsval aProperty, PRUint32 aAction)
1005 return NS_OK;
1008 /* [noscript] void checkConnect (in JSContextPtr aJSContext, in nsIURI aTargetURI, in string aClassName, in string aProperty); */
1009 NS_IMETHODIMP
1010 FullTrustSecMan::CheckConnect(JSContext * aJSContext, nsIURI *aTargetURI,
1011 const char *aClassName, const char *aProperty)
1013 return NS_OK;
1016 /* [noscript] void checkLoadURIFromScript (in JSContextPtr cx, in nsIURI uri); */
1017 NS_IMETHODIMP
1018 FullTrustSecMan::CheckLoadURIFromScript(JSContext * cx, nsIURI *uri)
1020 return NS_OK;
1023 /* void checkLoadURIWithPrincipal (in nsIPrincipal aPrincipal, in nsIURI uri, in unsigned long flags); */
1024 NS_IMETHODIMP
1025 FullTrustSecMan::CheckLoadURIWithPrincipal(nsIPrincipal *aPrincipal,
1026 nsIURI *uri, PRUint32 flags)
1028 return NS_OK;
1031 /* void checkLoadURI (in nsIURI from, in nsIURI uri, in unsigned long flags); */
1032 NS_IMETHODIMP
1033 FullTrustSecMan::CheckLoadURI(nsIURI *from, nsIURI *uri, PRUint32 flags)
1035 return NS_OK;
1038 /* void checkLoadURIStrWithPrincipal (in nsIPrincipal aPrincipal, in AUTF8String uri, in unsigned long flags); */
1039 NS_IMETHODIMP
1040 FullTrustSecMan::CheckLoadURIStrWithPrincipal(nsIPrincipal *aPrincipal,
1041 const nsACString & uri,
1042 PRUint32 flags)
1044 return NS_OK;
1047 /* void checkLoadURIStr (in AUTF8String from, in AUTF8String uri, in unsigned long flags); */
1048 NS_IMETHODIMP
1049 FullTrustSecMan::CheckLoadURIStr(const nsACString & from,
1050 const nsACString & uri, PRUint32 flags)
1052 return NS_OK;
1055 /* [noscript] void checkFunctionAccess (in JSContextPtr cx, in voidPtr funObj, in voidPtr targetObj); */
1056 NS_IMETHODIMP
1057 FullTrustSecMan::CheckFunctionAccess(JSContext * cx, void * funObj,
1058 void * targetObj)
1060 return NS_OK;
1063 /* [noscript] boolean canExecuteScripts (in JSContextPtr cx, in nsIPrincipal principal); */
1064 NS_IMETHODIMP
1065 FullTrustSecMan::CanExecuteScripts(JSContext * cx, nsIPrincipal *principal,
1066 PRBool *_retval)
1068 *_retval = PR_TRUE;
1069 return NS_OK;
1072 /* [noscript] nsIPrincipal getSubjectPrincipal (); */
1073 NS_IMETHODIMP
1074 FullTrustSecMan::GetSubjectPrincipal(nsIPrincipal **_retval)
1076 NS_IF_ADDREF(*_retval = mSystemPrincipal);
1077 return *_retval ? NS_OK : NS_ERROR_FAILURE;
1080 /* [noscript] nsIPrincipal getSystemPrincipal (); */
1081 NS_IMETHODIMP
1082 FullTrustSecMan::GetSystemPrincipal(nsIPrincipal **_retval)
1084 NS_IF_ADDREF(*_retval = mSystemPrincipal);
1085 return *_retval ? NS_OK : NS_ERROR_FAILURE;
1088 /* [noscript] nsIPrincipal getCertificatePrincipal (in AUTF8String aCertFingerprint, in AUTF8String aSubjectName, in AUTF8String aPrettyName, in nsISupports aCert, in nsIURI aURI); */
1089 NS_IMETHODIMP
1090 FullTrustSecMan::GetCertificatePrincipal(const nsACString & aCertFingerprint,
1091 const nsACString & aSubjectName,
1092 const nsACString & aPrettyName,
1093 nsISupports *aCert, nsIURI *aURI,
1094 nsIPrincipal **_retval)
1096 NS_IF_ADDREF(*_retval = mSystemPrincipal);
1097 return *_retval ? NS_OK : NS_ERROR_FAILURE;
1100 /* [noscript] nsIPrincipal getCodebasePrincipal (in nsIURI aURI); */
1101 NS_IMETHODIMP
1102 FullTrustSecMan::GetCodebasePrincipal(nsIURI *aURI, nsIPrincipal **_retval)
1104 NS_IF_ADDREF(*_retval = mSystemPrincipal);
1105 return *_retval ? NS_OK : NS_ERROR_FAILURE;
1108 /* [noscript] short requestCapability (in nsIPrincipal principal, in string capability); */
1109 NS_IMETHODIMP
1110 FullTrustSecMan::RequestCapability(nsIPrincipal *principal,
1111 const char *capability, PRInt16 *_retval)
1113 *_retval = nsIPrincipal::ENABLE_GRANTED;
1114 return NS_OK;
1117 /* boolean isCapabilityEnabled (in string capability); */
1118 NS_IMETHODIMP
1119 FullTrustSecMan::IsCapabilityEnabled(const char *capability, PRBool *_retval)
1121 *_retval = PR_TRUE;
1122 return NS_OK;
1125 /* void enableCapability (in string capability); */
1126 NS_IMETHODIMP
1127 FullTrustSecMan::EnableCapability(const char *capability)
1129 return NS_OK;;
1132 /* void revertCapability (in string capability); */
1133 NS_IMETHODIMP
1134 FullTrustSecMan::RevertCapability(const char *capability)
1136 return NS_OK;
1139 /* void disableCapability (in string capability); */
1140 NS_IMETHODIMP
1141 FullTrustSecMan::DisableCapability(const char *capability)
1143 return NS_OK;
1146 /* void setCanEnableCapability (in AUTF8String certificateFingerprint, in string capability, in short canEnable); */
1147 NS_IMETHODIMP
1148 FullTrustSecMan::SetCanEnableCapability(const nsACString & certificateFingerprint,
1149 const char *capability,
1150 PRInt16 canEnable)
1152 return NS_OK;
1155 /* [noscript] nsIPrincipal getObjectPrincipal (in JSContextPtr cx, in JSObjectPtr obj); */
1156 NS_IMETHODIMP
1157 FullTrustSecMan::GetObjectPrincipal(JSContext * cx, JSObject * obj,
1158 nsIPrincipal **_retval)
1160 NS_IF_ADDREF(*_retval = mSystemPrincipal);
1161 return *_retval ? NS_OK : NS_ERROR_FAILURE;
1164 /* [noscript] boolean subjectPrincipalIsSystem (); */
1165 NS_IMETHODIMP
1166 FullTrustSecMan::SubjectPrincipalIsSystem(PRBool *_retval)
1168 *_retval = PR_TRUE;
1169 return NS_OK;
1172 /* [noscript] void checkSameOrigin (in JSContextPtr aJSContext, in nsIURI aTargetURI); */
1173 NS_IMETHODIMP
1174 FullTrustSecMan::CheckSameOrigin(JSContext * aJSContext, nsIURI *aTargetURI)
1176 return NS_OK;
1179 /* void checkSameOriginURI (in nsIURI aSourceURI, in nsIURI aTargetURI); */
1180 NS_IMETHODIMP
1181 FullTrustSecMan::CheckSameOriginURI(nsIURI *aSourceURI, nsIURI *aTargetURI,
1182 PRBool reportError)
1184 return NS_OK;
1187 /* [noscript] nsIPrincipal getPrincipalFromContext (in JSContextPtr cx); */
1188 NS_IMETHODIMP
1189 FullTrustSecMan::GetPrincipalFromContext(JSContext * cx, nsIPrincipal **_retval)
1191 NS_IF_ADDREF(*_retval = mSystemPrincipal);
1192 return *_retval ? NS_OK : NS_ERROR_FAILURE;
1195 /* [noscript] nsIPrincipal getChannelPrincipal (in nsIChannel aChannel); */
1196 NS_IMETHODIMP
1197 FullTrustSecMan::GetChannelPrincipal(nsIChannel *aChannel, nsIPrincipal **_retval)
1199 NS_IF_ADDREF(*_retval = mSystemPrincipal);
1200 return *_retval ? NS_OK : NS_ERROR_FAILURE;
1203 /* boolean isSystemPrincipal (in nsIPrincipal aPrincipal); */
1204 NS_IMETHODIMP
1205 FullTrustSecMan::IsSystemPrincipal(nsIPrincipal *aPrincipal, PRBool *_retval)
1207 *_retval = aPrincipal == mSystemPrincipal;
1208 return NS_OK;
1211 NS_IMETHODIMP_(nsIPrincipal *)
1212 FullTrustSecMan::GetCxSubjectPrincipal(JSContext *cx)
1214 return mSystemPrincipal;
1217 #endif
1219 /***************************************************************************/
1221 // #define TEST_InitClassesWithNewWrappedGlobal
1223 #ifdef TEST_InitClassesWithNewWrappedGlobal
1224 // XXX hacky test code...
1225 #include "xpctest.h"
1227 class TestGlobal : public nsIXPCTestNoisy, public nsIXPCScriptable
1229 public:
1230 NS_DECL_ISUPPORTS
1231 NS_DECL_NSIXPCTESTNOISY
1232 NS_DECL_NSIXPCSCRIPTABLE
1234 TestGlobal(){}
1237 NS_IMPL_ISUPPORTS2(TestGlobal, nsIXPCTestNoisy, nsIXPCScriptable)
1239 // The nsIXPCScriptable map declaration that will generate stubs for us...
1240 #define XPC_MAP_CLASSNAME TestGlobal
1241 #define XPC_MAP_QUOTED_CLASSNAME "TestGlobal"
1242 #define XPC_MAP_FLAGS nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY |\
1243 nsIXPCScriptable::USE_JSSTUB_FOR_DELPROPERTY |\
1244 nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY
1245 #include "xpc_map_end.h" /* This will #undef the above */
1247 NS_IMETHODIMP TestGlobal::Squawk() {return NS_OK;}
1249 #endif
1251 // uncomment to install the test 'this' translator
1252 // #define TEST_TranslateThis
1254 #ifdef TEST_TranslateThis
1256 #include "xpctest.h"
1258 class nsXPCFunctionThisTranslator : public nsIXPCFunctionThisTranslator
1260 public:
1261 NS_DECL_ISUPPORTS
1262 NS_DECL_NSIXPCFUNCTIONTHISTRANSLATOR
1264 nsXPCFunctionThisTranslator();
1265 virtual ~nsXPCFunctionThisTranslator();
1266 /* additional members */
1269 /* Implementation file */
1270 NS_IMPL_ISUPPORTS1(nsXPCFunctionThisTranslator, nsIXPCFunctionThisTranslator)
1272 nsXPCFunctionThisTranslator::nsXPCFunctionThisTranslator()
1274 /* member initializers and constructor code */
1277 nsXPCFunctionThisTranslator::~nsXPCFunctionThisTranslator()
1279 /* destructor code */
1280 #ifdef DEBUG_jband
1281 printf("destroying nsXPCFunctionThisTranslator\n");
1282 #endif
1285 /* nsISupports TranslateThis (in nsISupports aInitialThis, in nsIInterfaceInfo aInterfaceInfo, in PRUint16 aMethodIndex, out PRBool aHideFirstParamFromJS, out nsIIDPtr aIIDOfResult); */
1286 NS_IMETHODIMP
1287 nsXPCFunctionThisTranslator::TranslateThis(nsISupports *aInitialThis,
1288 nsIInterfaceInfo *aInterfaceInfo,
1289 PRUint16 aMethodIndex,
1290 PRBool *aHideFirstParamFromJS,
1291 nsIID * *aIIDOfResult,
1292 nsISupports **_retval)
1294 NS_IF_ADDREF(aInitialThis);
1295 *_retval = aInitialThis;
1296 *aHideFirstParamFromJS = JS_FALSE;
1297 *aIIDOfResult = nsnull;
1298 return NS_OK;
1301 #endif
1303 JS_STATIC_DLL_CALLBACK(JSBool)
1304 ContextCallback(JSContext *cx, uintN contextOp)
1306 if (contextOp == JSCONTEXT_NEW) {
1307 JS_SetErrorReporter(cx, my_ErrorReporter);
1308 JS_SetVersion(cx, JSVERSION_LATEST);
1310 return JS_TRUE;
1314 main(int argc, char **argv, char **envp)
1316 #ifdef XP_MACOSX
1317 InitAutoreleasePool();
1318 #endif
1319 JSRuntime *rt;
1320 JSContext *cx;
1321 JSObject *glob, *envobj;
1322 int result;
1323 nsresult rv;
1325 // unbuffer stdout so that output is in the correct order; note that stderr
1326 // is unbuffered by default
1327 setbuf(stdout, 0);
1329 gErrFile = stderr;
1330 gOutFile = stdout;
1332 nsCOMPtr<nsIServiceManager> servMan;
1333 rv = NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull);
1334 if (NS_FAILED(rv)) {
1335 printf("NS_InitXPCOM failed!\n");
1336 return 1;
1339 nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(servMan);
1340 NS_ASSERTION(registrar, "Null nsIComponentRegistrar");
1341 if (registrar)
1342 registrar->AutoRegister(nsnull);
1345 nsCOMPtr<nsIJSRuntimeService> rtsvc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
1346 // get the JSRuntime from the runtime svc
1347 if (!rtsvc) {
1348 printf("failed to get nsJSRuntimeService!\n");
1349 return 1;
1352 if (NS_FAILED(rtsvc->GetRuntime(&rt)) || !rt) {
1353 printf("failed to get JSRuntime from nsJSRuntimeService!\n");
1354 return 1;
1357 JS_SetContextCallback(rt, ContextCallback);
1359 cx = JS_NewContext(rt, 8192);
1360 if (!cx) {
1361 printf("JS_NewContext failed!\n");
1362 return 1;
1365 nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
1366 if (!xpc) {
1367 printf("failed to get nsXPConnect service!\n");
1368 return 1;
1371 // Since the caps security system might set a default security manager
1372 // we will be sure that the secman on this context gives full trust.
1373 nsRefPtr<FullTrustSecMan> secman = new FullTrustSecMan();
1374 xpc->SetSecurityManagerForJSContext(cx, secman, 0xFFFF);
1376 #ifndef XPCONNECT_STANDALONE
1377 // Fetch the system principal and store it away in a global, to use for
1378 // script compilation in Load() and ProcessFile() (including interactive
1379 // eval loop)
1381 nsCOMPtr<nsIPrincipal> princ;
1383 nsCOMPtr<nsIScriptSecurityManager> securityManager =
1384 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
1385 if (NS_SUCCEEDED(rv) && securityManager) {
1386 rv = securityManager->GetSystemPrincipal(getter_AddRefs(princ));
1387 if (NS_FAILED(rv)) {
1388 fprintf(gErrFile, "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager service.\n");
1389 } else {
1390 // fetch the JS principals and stick in a global
1391 rv = princ->GetJSPrincipals(cx, &gJSPrincipals);
1392 if (NS_FAILED(rv)) {
1393 fprintf(gErrFile, "+++ Failed to obtain JS principals from SystemPrincipal.\n");
1395 secman->SetSystemPrincipal(princ);
1397 } else {
1398 fprintf(gErrFile, "+++ Failed to get ScriptSecurityManager service, running without principals");
1401 #endif
1403 #ifdef TEST_TranslateThis
1404 nsCOMPtr<nsIXPCFunctionThisTranslator>
1405 translator(new nsXPCFunctionThisTranslator);
1406 xpc->SetFunctionThisTranslator(NS_GET_IID(nsITestXPCFunctionCallback), translator, nsnull);
1407 #endif
1409 nsCOMPtr<nsIJSContextStack> cxstack = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
1410 if (!cxstack) {
1411 printf("failed to get the nsThreadJSContextStack service!\n");
1412 return 1;
1415 if(NS_FAILED(cxstack->Push(cx))) {
1416 printf("failed to push the current JSContext on the nsThreadJSContextStack!\n");
1417 return 1;
1420 nsCOMPtr<nsIXPCScriptable> backstagePass;
1421 nsresult rv = rtsvc->GetBackstagePass(getter_AddRefs(backstagePass));
1422 if (NS_FAILED(rv)) {
1423 fprintf(gErrFile, "+++ Failed to get backstage pass from rtsvc: %8x\n",
1424 rv);
1425 return 1;
1428 nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
1429 rv = xpc->InitClassesWithNewWrappedGlobal(cx, backstagePass,
1430 NS_GET_IID(nsISupports),
1431 nsIXPConnect::
1432 FLAG_SYSTEM_GLOBAL_OBJECT,
1433 getter_AddRefs(holder));
1434 if (NS_FAILED(rv))
1435 return 1;
1437 rv = holder->GetJSObject(&glob);
1438 if (NS_FAILED(rv)) {
1439 NS_ASSERTION(glob == nsnull, "bad GetJSObject?");
1440 return 1;
1443 JS_BeginRequest(cx);
1445 if (!JS_DefineFunctions(cx, glob, glob_functions)) {
1446 JS_EndRequest(cx);
1447 return 1;
1450 envobj = JS_DefineObject(cx, glob, "environment", &env_class, NULL, 0);
1451 if (!envobj || !JS_SetPrivate(cx, envobj, envp)) {
1452 JS_EndRequest(cx);
1453 return 1;
1456 argc--;
1457 argv++;
1459 result = ProcessArgs(cx, glob, argv, argc);
1462 //#define TEST_CALL_ON_WRAPPED_JS_AFTER_SHUTDOWN 1
1464 #ifdef TEST_CALL_ON_WRAPPED_JS_AFTER_SHUTDOWN
1465 // test of late call and release (see below)
1466 nsCOMPtr<nsIJSContextStack> bogus;
1467 xpc->WrapJS(cx, glob, NS_GET_IID(nsIJSContextStack),
1468 (void**) getter_AddRefs(bogus));
1469 #endif
1471 JSPRINCIPALS_DROP(cx, gJSPrincipals);
1472 JS_ClearScope(cx, glob);
1473 JS_GC(cx);
1474 JSContext *oldcx;
1475 cxstack->Pop(&oldcx);
1476 NS_ASSERTION(oldcx == cx, "JS thread context push/pop mismatch");
1477 cxstack = nsnull;
1478 JS_GC(cx);
1479 JS_DestroyContext(cx);
1480 xpc->SyncJSContexts();
1481 } // this scopes the nsCOMPtrs
1482 // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
1483 rv = NS_ShutdownXPCOM( NULL );
1484 NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed");
1486 #ifdef TEST_CALL_ON_WRAPPED_JS_AFTER_SHUTDOWN
1487 // test of late call and release (see above)
1488 JSContext* bogusCX;
1489 bogus->Peek(&bogusCX);
1490 bogus = nsnull;
1491 #endif
1493 #ifdef XP_MACOSX
1494 FinishAutoreleasePool();
1495 #endif
1497 return result;