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
17 * The Original Code is Mozilla Communicator client code, released
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.
26 * John Bandhauer <jband@netscape.com>
27 * Pierre Phaneuf <pp@ludusdesign.com>
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. */
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"
63 #include "nsIGenericFactory.h"
64 #include "nsIJSRuntimeService.h"
66 #include "nsAutoPtr.h"
67 #include "nsIXPCSecurityManager.h"
69 #include "xpcshellMacUtils.h"
72 #ifndef XPCONNECT_STANDALONE
73 #include "nsIScriptSecurityManager.h"
74 #include "nsIPrincipal.h"
77 // all this crap is needed to do the interactive shell stuff
81 #include <io.h> /* for isatty() */
84 #include <unistd.h> /* for isatty() */
87 #include "nsIJSContextStack.h"
89 /***************************************************************************/
92 #define DoBeginRequest(cx) JS_BeginRequest((cx))
93 #define DoEndRequest(cx) JS_EndRequest((cx))
95 #define DoBeginRequest(cx) ((void)0)
96 #define DoEndRequest(cx) ((void)0)
99 /***************************************************************************/
101 #define EXITCODE_RUNTIME_ERROR 3
102 #define EXITCODE_FILE_NOT_FOUND 4
104 FILE *gOutFile
= NULL
;
105 FILE *gErrFile
= NULL
;
106 FILE *gInFile
= NULL
;
109 JSBool gQuitting
= JS_FALSE
;
110 static JSBool reportWarnings
= JS_TRUE
;
111 static JSBool compileOnly
= JS_FALSE
;
113 JSPrincipals
*gJSPrincipals
= nsnull
;
116 GetLine(JSContext
*cx
, char *bufp
, FILE *file
, const char *prompt
) {
119 * Use readline only if file is stdin, because there's no way to specify
120 * another handle. Are other filehandles interactive?
123 char *linep
= readline(prompt
);
130 bufp
+= strlen(bufp
);
137 fprintf(gOutFile
, prompt
);
139 if (!fgets(line
, sizeof line
, file
))
147 my_ErrorReporter(JSContext
*cx
, const char *message
, JSErrorReport
*report
)
150 char *prefix
= NULL
, *tmp
;
152 JSStackFrame
* fp
= nsnull
;
153 nsCOMPtr
<nsIXPConnect
> xpc
;
155 // Don't report an exception from inner JS frames as the callers may intend
157 while ((fp
= JS_FrameIterator(cx
, &fp
))) {
158 if (!JS_IsNativeFrame(cx
, fp
)) {
163 // In some cases cx->fp is null here so use XPConnect to tell us about inner
165 if ((xpc
= do_GetService(nsIXPConnect::GetCID()))) {
166 nsAXPCNativeCallContext
*cc
= nsnull
;
167 xpc
->GetCurrentNativeCallContext(&cc
);
169 nsAXPCNativeCallContext
*prev
= cc
;
170 while (NS_SUCCEEDED(prev
->GetPreviousCallContext(&prev
)) && prev
) {
172 if (NS_SUCCEEDED(prev
->GetLanguage(&lang
)) &&
173 lang
== nsAXPCNativeCallContext::LANG_JS
) {
181 fprintf(gErrFile
, "%s\n", message
);
185 /* Conditionally ignore reported warnings. */
186 if (JSREPORT_IS_WARNING(report
->flags
) && !reportWarnings
)
189 if (report
->filename
)
190 prefix
= JS_smprintf("%s:", report
->filename
);
191 if (report
->lineno
) {
193 prefix
= JS_smprintf("%s%u: ", tmp
? tmp
: "", report
->lineno
);
196 if (JSREPORT_IS_WARNING(report
->flags
)) {
198 prefix
= JS_smprintf("%s%swarning: ",
200 JSREPORT_IS_STRICT(report
->flags
) ? "strict " : "");
204 /* embedded newlines -- argh! */
205 while ((ctmp
= strchr(message
, '\n')) != 0) {
207 if (prefix
) fputs(prefix
, gErrFile
);
208 fwrite(message
, 1, ctmp
- message
, gErrFile
);
211 /* If there were no filename or lineno, the prefix might be empty */
213 fputs(prefix
, gErrFile
);
214 fputs(message
, gErrFile
);
216 if (!report
->linebuf
) {
217 fputc('\n', gErrFile
);
221 fprintf(gErrFile
, ":\n%s%s\n%s", prefix
, report
->linebuf
, prefix
);
222 n
= report
->tokenptr
- report
->linebuf
;
223 for (i
= j
= 0; i
< n
; i
++) {
224 if (report
->linebuf
[i
] == '\t') {
225 for (k
= (j
+ 8) & ~7; j
< k
; j
++) {
226 fputc('.', gErrFile
);
230 fputc('.', gErrFile
);
233 fputs("^\n", gErrFile
);
235 if (!JSREPORT_IS_WARNING(report
->flags
))
236 gExitCode
= EXITCODE_RUNTIME_ERROR
;
241 ReadLine(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
243 // While 4096 might be quite arbitrary, this is something to be fixed in
244 // bug 105707. It is also the same limit as in ProcessFile.
248 /* If a prompt was specified, construct the string */
250 str
= JS_ValueToString(cx
, argv
[0]);
253 argv
[0] = STRING_TO_JSVAL(str
);
255 str
= JSVAL_TO_STRING(JS_GetEmptyStringValue(cx
));
258 /* Get a line from the infile */
259 if (!GetLine(cx
, buf
, gInFile
, JS_GetStringBytes(str
)))
262 /* Strip newline character added by GetLine() */
263 unsigned int buflen
= strlen(buf
);
269 } else if (buf
[buflen
- 1] == '\n') {
273 /* Turn buf into a JSString */
274 str
= JS_NewStringCopyN(cx
, buf
, buflen
);
278 *rval
= STRING_TO_JSVAL(str
);
283 Print(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
288 for (i
= n
= 0; i
< argc
; i
++) {
289 str
= JS_ValueToString(cx
, argv
[i
]);
292 fprintf(gOutFile
, "%s%s", i
? " " : "", JS_GetStringBytes(str
));
296 fputc('\n', gOutFile
);
301 Dump(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
307 str
= JS_ValueToString(cx
, argv
[0]);
311 char *bytes
= JS_GetStringBytes(str
);
312 bytes
= strdup(bytes
);
314 fputs(bytes
, gOutFile
);
320 Load(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
324 const char *filename
;
330 for (i
= 0; i
< argc
; i
++) {
331 str
= JS_ValueToString(cx
, argv
[i
]);
334 argv
[i
] = STRING_TO_JSVAL(str
);
335 filename
= JS_GetStringBytes(str
);
336 file
= fopen(filename
, "r");
337 script
= JS_CompileFileHandleForPrincipals(cx
, obj
, filename
, file
,
343 ? JS_ExecuteScript(cx
, obj
, script
, &result
)
345 JS_DestroyScript(cx
, script
);
354 Version(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
356 if (argc
> 0 && JSVAL_IS_INT(argv
[0]))
357 *rval
= INT_TO_JSVAL(JS_SetVersion(cx
, JSVersion(JSVAL_TO_INT(argv
[0]))));
359 *rval
= INT_TO_JSVAL(JS_GetVersion(cx
));
364 BuildDate(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
366 fprintf(gOutFile
, "built on %s at %s\n", __DATE__
, __TIME__
);
371 Quit(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
374 JSJ_SimpleShutdown();
378 JS_ConvertArguments(cx
, argc
, argv
,"/ i", &gExitCode
);
386 DumpXPC(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
391 if (!JS_ValueToInt32(cx
, argv
[0], &depth
))
395 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService(nsIXPConnect::GetCID());
397 xpc
->DebugDump((int16
)depth
);
401 /* XXX needed only by GC() */
405 GC(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
411 preBytes
= rt
->gcBytes
;
413 fprintf(gOutFile
, "before %lu, after %lu, break %08lx\n",
414 (unsigned long)preBytes
, (unsigned long)rt
->gcBytes
,
416 (unsigned long)sbrk(0)
422 js_DumpGCStats(rt
, stdout
);
430 DumpHeap(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
432 char *fileName
= NULL
;
433 void* startThing
= NULL
;
434 uint32 startTraceKind
= 0;
435 void *thingToFind
= NULL
;
436 size_t maxDepth
= (size_t)-1;
437 void *thingToIgnore
= NULL
;
443 if (*vp
!= JSVAL_NULL
&& *vp
!= JSVAL_VOID
) {
446 str
= JS_ValueToString(cx
, *vp
);
449 *vp
= STRING_TO_JSVAL(str
);
450 fileName
= JS_GetStringBytes(str
);
454 if (*vp
!= JSVAL_NULL
&& *vp
!= JSVAL_VOID
) {
455 if (!JSVAL_IS_TRACEABLE(*vp
))
456 goto not_traceable_arg
;
457 startThing
= JSVAL_TO_TRACEABLE(*vp
);
458 startTraceKind
= JSVAL_TRACE_KIND(*vp
);
462 if (*vp
!= JSVAL_NULL
&& *vp
!= JSVAL_VOID
) {
463 if (!JSVAL_IS_TRACEABLE(*vp
))
464 goto not_traceable_arg
;
465 thingToFind
= JSVAL_TO_TRACEABLE(*vp
);
469 if (*vp
!= JSVAL_NULL
&& *vp
!= JSVAL_VOID
) {
472 if (!JS_ValueToECMAUint32(cx
, *vp
, &depth
))
478 if (*vp
!= JSVAL_NULL
&& *vp
!= JSVAL_VOID
) {
479 if (!JSVAL_IS_TRACEABLE(*vp
))
480 goto not_traceable_arg
;
481 thingToIgnore
= JSVAL_TO_TRACEABLE(*vp
);
487 dumpFile
= fopen(fileName
, "w");
489 fprintf(gErrFile
, "dumpHeap: can't open %s: %s\n",
490 fileName
, strerror(errno
));
495 ok
= JS_DumpHeap(cx
, dumpFile
, startThing
, startTraceKind
, thingToFind
,
496 maxDepth
, thingToIgnore
);
497 if (dumpFile
!= gOutFile
)
503 "dumpHeap: argument %u is not null or a heap-allocated thing\n",
504 (unsigned)(vp
- argv
));
511 Clear(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
513 if (argc
> 0 && !JSVAL_IS_PRIMITIVE(argv
[0])) {
514 JS_ClearScope(cx
, JSVAL_TO_OBJECT(argv
[0]));
516 JS_ReportError(cx
, "'clear' requires an object");
522 static JSFunctionSpec glob_functions
[] = {
523 {"print", Print
, 0,0,0},
524 {"readline", ReadLine
, 1,0,0},
525 {"load", Load
, 1,0,0},
526 {"quit", Quit
, 0,0,0},
527 {"version", Version
, 1,0,0},
528 {"build", BuildDate
, 0,0,0},
529 {"dumpXPC", DumpXPC
, 1,0,0},
530 {"dump", Dump
, 1,0,0},
532 {"clear", Clear
, 1,0,0},
534 {"dumpHeap", DumpHeap
, 5,0,0},
537 {"startShark", js_StartShark
, 0,0,0},
538 {"stopShark", js_StopShark
, 0,0,0},
539 {"connectShark", js_ConnectShark
, 0,0,0},
540 {"disconnectShark", js_DisconnectShark
, 0,0,0},
543 {"startCallgrind", js_StartCallgrind
, 0,0,0},
544 {"stopCallgrind", js_StopCallgrind
, 0,0,0},
545 {"dumpCallgrind", js_DumpCallgrind
, 1,0,0},
547 {nsnull
,nsnull
,0,0,0}
550 JSClass global_class
= {
552 JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
,
553 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, JS_FinalizeStub
557 env_setProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
559 /* XXX porting may be easy, but these don't seem to supply setenv by default */
560 #if !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS
561 JSString
*idstr
, *valstr
;
562 const char *name
, *value
;
565 idstr
= JS_ValueToString(cx
, id
);
566 valstr
= JS_ValueToString(cx
, *vp
);
567 if (!idstr
|| !valstr
)
569 name
= JS_GetStringBytes(idstr
);
570 value
= JS_GetStringBytes(valstr
);
571 #if defined XP_WIN || defined HPUX || defined OSF1 || defined IRIX \
574 char *waste
= JS_smprintf("%s=%s", name
, value
);
576 JS_ReportOutOfMemory(cx
);
582 * HPUX9 at least still has the bad old non-copying putenv.
584 * Per mail from <s.shanmuganathan@digital.com>, OSF1 also has a putenv
585 * that will crash if you pass it an auto char array (so it must place
586 * its argument directly in the char *environ[] array).
592 rv
= setenv(name
, value
, 1);
595 JS_ReportError(cx
, "can't set envariable %s to %s", name
, value
);
598 *vp
= STRING_TO_JSVAL(valstr
);
599 #endif /* !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS */
604 env_enumerate(JSContext
*cx
, JSObject
*obj
)
606 static JSBool reflected
;
607 char **evp
, *name
, *value
;
614 for (evp
= (char **)JS_GetPrivate(cx
, obj
); (name
= *evp
) != NULL
; evp
++) {
615 value
= strchr(name
, '=');
619 valstr
= JS_NewStringCopyZ(cx
, value
);
623 ok
= JS_DefineProperty(cx
, obj
, name
, STRING_TO_JSVAL(valstr
),
624 NULL
, NULL
, JSPROP_ENUMERATE
);
636 env_resolve(JSContext
*cx
, JSObject
*obj
, jsval id
, uintN flags
,
639 JSString
*idstr
, *valstr
;
640 const char *name
, *value
;
642 if (flags
& JSRESOLVE_ASSIGNING
)
645 idstr
= JS_ValueToString(cx
, id
);
648 name
= JS_GetStringBytes(idstr
);
649 value
= getenv(name
);
651 valstr
= JS_NewStringCopyZ(cx
, value
);
654 if (!JS_DefineProperty(cx
, obj
, name
, STRING_TO_JSVAL(valstr
),
655 NULL
, NULL
, JSPROP_ENUMERATE
)) {
663 static JSClass env_class
= {
664 "environment", JSCLASS_HAS_PRIVATE
| JSCLASS_NEW_RESOLVE
,
665 JS_PropertyStub
, JS_PropertyStub
,
666 JS_PropertyStub
, env_setProperty
,
667 env_enumerate
, (JSResolveOp
) env_resolve
,
668 JS_ConvertStub
, JS_FinalizeStub
671 /***************************************************************************/
673 typedef enum JSShellErrNum
{
674 #define MSG_DEF(name, number, count, exception, format) \
676 #include "jsshell.msg"
682 JSErrorFormatString jsShell_ErrorFormatString
[JSErr_Limit
] = {
683 #define MSG_DEF(name, number, count, exception, format) \
685 #include "jsshell.msg"
689 static const JSErrorFormatString
*
690 my_GetErrorMessage(void *userRef
, const char *locale
, const uintN errorNumber
)
692 if ((errorNumber
> 0) && (errorNumber
< JSShellErr_Limit
))
693 return &jsShell_ErrorFormatString
[errorNumber
];
700 extern char *readline(const char *prompt
);
701 extern void add_history(char *line
);
707 ProcessFile(JSContext
*cx
, JSObject
*obj
, const char *filename
, FILE *file
,
712 int lineno
, startline
;
714 char *bufp
, buffer
[4096];
721 else if (!isatty(fileno(file
))) {
723 * It's not interactive - just execute it.
725 * Support the UNIX #! shell hack; gobble the first line if it starts
726 * with '#'. TODO - this isn't quite compatible with sharp variables,
727 * as a legal js program (using sharp variables) might start with '#'.
728 * But that would require multi-character lookahead.
730 int ch
= fgetc(file
);
732 while((ch
= fgetc(file
)) != EOF
) {
733 if(ch
== '\n' || ch
== '\r')
740 script
= JS_CompileFileHandleForPrincipals(cx
, obj
, filename
, file
,
745 (void)JS_ExecuteScript(cx
, obj
, script
, &result
);
746 JS_DestroyScript(cx
, script
);
754 /* It's an interactive filehandle; drop into read-eval-print loop. */
762 * Accumulate lines until we get a 'compilable unit' - one that either
763 * generates an error (before running out of source) or that compiles
764 * cleanly. This should be whenever we get a complete statement that
765 * coincides with the end of a line.
769 if (!GetLine(cx
, bufp
, file
, startline
== lineno
? "js> " : "")) {
773 bufp
+= strlen(bufp
);
775 } while (!JS_BufferIsCompilableUnit(cx
, obj
, buffer
, strlen(buffer
)));
778 /* Clear any pending exception from previous failed compiles. */
779 JS_ClearPendingException(cx
);
780 script
= JS_CompileScriptForPrincipals(cx
, obj
, gJSPrincipals
, buffer
,
781 strlen(buffer
), "typein", startline
);
783 JSErrorReporter older
;
786 ok
= JS_ExecuteScript(cx
, obj
, script
, &result
);
787 if (ok
&& result
!= JSVAL_VOID
) {
788 /* Suppress error reports from JS_ValueToString(). */
789 older
= JS_SetErrorReporter(cx
, NULL
);
790 str
= JS_ValueToString(cx
, result
);
791 JS_SetErrorReporter(cx
, older
);
794 fprintf(gOutFile
, "%s\n", JS_GetStringBytes(str
));
799 JS_DestroyScript(cx
, script
);
802 } while (!hitEOF
&& !gQuitting
);
804 fprintf(gOutFile
, "\n");
808 Process(JSContext
*cx
, JSObject
*obj
, const char *filename
, JSBool forceTTY
)
812 if (forceTTY
|| !filename
|| strcmp(filename
, "-") == 0) {
815 file
= fopen(filename
, "r");
817 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
,
819 filename
, strerror(errno
));
820 gExitCode
= EXITCODE_FILE_NOT_FOUND
;
825 ProcessFile(cx
, obj
, filename
, file
, forceTTY
);
831 fprintf(gErrFile
, "%s\n", JS_GetImplementationVersion());
832 fprintf(gErrFile
, "usage: xpcshell [-PswWxCij] [-v version] [-f scriptfile] [-e script] [scriptfile] [scriptarg...]\n");
836 extern JSClass global_class
;
839 ProcessArgs(JSContext
*cx
, JSObject
*obj
, char **argv
, int argc
)
841 const char rcfilename
[] = "xpcshell.js";
845 char *filename
= NULL
;
846 JSBool isInteractive
= JS_TRUE
;
847 JSBool forceTTY
= JS_FALSE
;
849 rcfile
= fopen(rcfilename
, "r");
851 printf("[loading '%s'...]\n", rcfilename
);
852 ProcessFile(cx
, obj
, rcfilename
, rcfile
, JS_FALSE
);
856 * Scan past all optional arguments so we can create the arguments object
857 * before processing any -f options, which must interleave properly with
858 * -v and -w options. This requires two passes, and without getopt, we'll
859 * have to keep the option logic here and in the second for loop in sync.
861 for (i
= 0; i
< argc
; i
++) {
862 if (argv
[i
][0] != '-' || argv
[i
][1] == '\0') {
866 switch (argv
[i
][1]) {
877 * Create arguments early and define it to root it, so it's safe from any
878 * GC calls nested below, and so it is available to -f <file> arguments.
880 argsObj
= JS_NewArrayObject(cx
, 0, NULL
);
883 if (!JS_DefineProperty(cx
, obj
, "arguments", OBJECT_TO_JSVAL(argsObj
),
889 for (j
= 0; j
< length
; j
++) {
890 JSString
*str
= JS_NewStringCopyZ(cx
, argv
[i
++]);
893 if (!JS_DefineElement(cx
, argsObj
, j
, STRING_TO_JSVAL(str
),
894 NULL
, NULL
, JSPROP_ENUMERATE
)) {
899 for (i
= 0; i
< argc
; i
++) {
900 if (argv
[i
][0] != '-' || argv
[i
][1] == '\0') {
901 filename
= argv
[i
++];
902 isInteractive
= JS_FALSE
;
905 switch (argv
[i
][1]) {
910 JS_SetVersion(cx
, JSVersion(atoi(argv
[i
])));
913 reportWarnings
= JS_FALSE
;
916 reportWarnings
= JS_TRUE
;
919 JS_ToggleOptions(cx
, JSOPTION_STRICT
);
922 JS_ToggleOptions(cx
, JSOPTION_XML
);
925 if (JS_GET_CLASS(cx
, JS_GetPrototype(cx
, obj
)) != &global_class
) {
928 if (!JS_SealObject(cx
, obj
, JS_TRUE
))
930 gobj
= JS_NewObject(cx
, &global_class
, NULL
, NULL
);
933 if (!JS_SetPrototype(cx
, gobj
, obj
))
935 JS_SetParent(cx
, gobj
, NULL
);
936 JS_SetGlobalObject(cx
, gobj
);
944 Process(cx
, obj
, argv
[i
], JS_FALSE
);
946 * XXX: js -f foo.js should interpret foo.js and then
947 * drop into interactive mode, but that breaks test
948 * harness. Just execute foo.js for now.
950 isInteractive
= JS_FALSE
;
953 isInteractive
= forceTTY
= JS_TRUE
;
963 JS_EvaluateScript(cx
, obj
, argv
[i
], strlen(argv
[i
]),
966 isInteractive
= JS_FALSE
;
970 compileOnly
= JS_TRUE
;
971 isInteractive
= JS_FALSE
;
974 JS_ToggleOptions(cx
, JSOPTION_JIT
);
986 if (filename
|| isInteractive
)
987 Process(cx
, obj
, filename
, forceTTY
);
991 /***************************************************************************/
993 class FullTrustSecMan
994 #ifndef XPCONNECT_STANDALONE
995 : public nsIScriptSecurityManager
997 : public nsIXPCSecurityManager
1002 NS_DECL_NSIXPCSECURITYMANAGER
1003 #ifndef XPCONNECT_STANDALONE
1004 NS_DECL_NSISCRIPTSECURITYMANAGER
1008 virtual ~FullTrustSecMan();
1010 #ifndef XPCONNECT_STANDALONE
1011 void SetSystemPrincipal(nsIPrincipal
*aPrincipal
) {
1012 mSystemPrincipal
= aPrincipal
;
1016 nsCOMPtr
<nsIPrincipal
> mSystemPrincipal
;
1020 NS_INTERFACE_MAP_BEGIN(FullTrustSecMan
)
1021 NS_INTERFACE_MAP_ENTRY(nsIXPCSecurityManager
)
1022 #ifndef XPCONNECT_STANDALONE
1023 NS_INTERFACE_MAP_ENTRY(nsIScriptSecurityManager
)
1025 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIXPCSecurityManager
)
1026 NS_INTERFACE_MAP_END
1028 NS_IMPL_ADDREF(FullTrustSecMan
)
1029 NS_IMPL_RELEASE(FullTrustSecMan
)
1031 FullTrustSecMan::FullTrustSecMan()
1033 #ifndef XPCONNECT_STANDALONE
1034 mSystemPrincipal
= nsnull
;
1038 FullTrustSecMan::~FullTrustSecMan()
1043 FullTrustSecMan::CanCreateWrapper(JSContext
* aJSContext
, const nsIID
& aIID
,
1044 nsISupports
*aObj
, nsIClassInfo
*aClassInfo
,
1051 FullTrustSecMan::CanCreateInstance(JSContext
* aJSContext
, const nsCID
& aCID
)
1057 FullTrustSecMan::CanGetService(JSContext
* aJSContext
, const nsCID
& aCID
)
1062 #ifndef XPCONNECT_STANDALONE
1063 /* 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); */
1065 FullTrustSecMan::CanAccess(PRUint32 aAction
,
1066 nsAXPCNativeCallContext
*aCallContext
,
1067 JSContext
* aJSContext
, JSObject
* aJSObject
,
1068 nsISupports
*aObj
, nsIClassInfo
*aClassInfo
,
1069 jsval aName
, void * *aPolicy
)
1074 /* [noscript] void checkPropertyAccess (in JSContextPtr aJSContext, in JSObjectPtr aJSObject, in string aClassName, in JSVal aProperty, in PRUint32 aAction); */
1076 FullTrustSecMan::CheckPropertyAccess(JSContext
* aJSContext
,
1077 JSObject
* aJSObject
,
1078 const char *aClassName
,
1079 jsval aProperty
, PRUint32 aAction
)
1084 /* [noscript] void checkConnect (in JSContextPtr aJSContext, in nsIURI aTargetURI, in string aClassName, in string aProperty); */
1086 FullTrustSecMan::CheckConnect(JSContext
* aJSContext
, nsIURI
*aTargetURI
,
1087 const char *aClassName
, const char *aProperty
)
1092 /* [noscript] void checkLoadURIFromScript (in JSContextPtr cx, in nsIURI uri); */
1094 FullTrustSecMan::CheckLoadURIFromScript(JSContext
* cx
, nsIURI
*uri
)
1099 /* void checkLoadURIWithPrincipal (in nsIPrincipal aPrincipal, in nsIURI uri, in unsigned long flags); */
1101 FullTrustSecMan::CheckLoadURIWithPrincipal(nsIPrincipal
*aPrincipal
,
1102 nsIURI
*uri
, PRUint32 flags
)
1107 /* void checkLoadURI (in nsIURI from, in nsIURI uri, in unsigned long flags); */
1109 FullTrustSecMan::CheckLoadURI(nsIURI
*from
, nsIURI
*uri
, PRUint32 flags
)
1114 /* void checkLoadURIStrWithPrincipal (in nsIPrincipal aPrincipal, in AUTF8String uri, in unsigned long flags); */
1116 FullTrustSecMan::CheckLoadURIStrWithPrincipal(nsIPrincipal
*aPrincipal
,
1117 const nsACString
& uri
,
1123 /* void checkLoadURIStr (in AUTF8String from, in AUTF8String uri, in unsigned long flags); */
1125 FullTrustSecMan::CheckLoadURIStr(const nsACString
& from
,
1126 const nsACString
& uri
, PRUint32 flags
)
1131 /* [noscript] void checkFunctionAccess (in JSContextPtr cx, in voidPtr funObj, in voidPtr targetObj); */
1133 FullTrustSecMan::CheckFunctionAccess(JSContext
* cx
, void * funObj
,
1139 /* [noscript] boolean canExecuteScripts (in JSContextPtr cx, in nsIPrincipal principal); */
1141 FullTrustSecMan::CanExecuteScripts(JSContext
* cx
, nsIPrincipal
*principal
,
1148 /* [noscript] nsIPrincipal getSubjectPrincipal (); */
1150 FullTrustSecMan::GetSubjectPrincipal(nsIPrincipal
**_retval
)
1152 NS_IF_ADDREF(*_retval
= mSystemPrincipal
);
1153 return *_retval
? NS_OK
: NS_ERROR_FAILURE
;
1156 /* [noscript] nsIPrincipal getSystemPrincipal (); */
1158 FullTrustSecMan::GetSystemPrincipal(nsIPrincipal
**_retval
)
1160 NS_IF_ADDREF(*_retval
= mSystemPrincipal
);
1161 return *_retval
? NS_OK
: NS_ERROR_FAILURE
;
1164 /* [noscript] nsIPrincipal getCertificatePrincipal (in AUTF8String aCertFingerprint, in AUTF8String aSubjectName, in AUTF8String aPrettyName, in nsISupports aCert, in nsIURI aURI); */
1166 FullTrustSecMan::GetCertificatePrincipal(const nsACString
& aCertFingerprint
,
1167 const nsACString
& aSubjectName
,
1168 const nsACString
& aPrettyName
,
1169 nsISupports
*aCert
, nsIURI
*aURI
,
1170 nsIPrincipal
**_retval
)
1172 NS_IF_ADDREF(*_retval
= mSystemPrincipal
);
1173 return *_retval
? NS_OK
: NS_ERROR_FAILURE
;
1176 /* [noscript] nsIPrincipal getCodebasePrincipal (in nsIURI aURI); */
1178 FullTrustSecMan::GetCodebasePrincipal(nsIURI
*aURI
, nsIPrincipal
**_retval
)
1180 NS_IF_ADDREF(*_retval
= mSystemPrincipal
);
1181 return *_retval
? NS_OK
: NS_ERROR_FAILURE
;
1184 /* [noscript] short requestCapability (in nsIPrincipal principal, in string capability); */
1186 FullTrustSecMan::RequestCapability(nsIPrincipal
*principal
,
1187 const char *capability
, PRInt16
*_retval
)
1189 *_retval
= nsIPrincipal::ENABLE_GRANTED
;
1193 /* boolean isCapabilityEnabled (in string capability); */
1195 FullTrustSecMan::IsCapabilityEnabled(const char *capability
, PRBool
*_retval
)
1201 /* void enableCapability (in string capability); */
1203 FullTrustSecMan::EnableCapability(const char *capability
)
1208 /* void revertCapability (in string capability); */
1210 FullTrustSecMan::RevertCapability(const char *capability
)
1215 /* void disableCapability (in string capability); */
1217 FullTrustSecMan::DisableCapability(const char *capability
)
1222 /* void setCanEnableCapability (in AUTF8String certificateFingerprint, in string capability, in short canEnable); */
1224 FullTrustSecMan::SetCanEnableCapability(const nsACString
& certificateFingerprint
,
1225 const char *capability
,
1231 /* [noscript] nsIPrincipal getObjectPrincipal (in JSContextPtr cx, in JSObjectPtr obj); */
1233 FullTrustSecMan::GetObjectPrincipal(JSContext
* cx
, JSObject
* obj
,
1234 nsIPrincipal
**_retval
)
1236 NS_IF_ADDREF(*_retval
= mSystemPrincipal
);
1237 return *_retval
? NS_OK
: NS_ERROR_FAILURE
;
1240 /* [noscript] boolean subjectPrincipalIsSystem (); */
1242 FullTrustSecMan::SubjectPrincipalIsSystem(PRBool
*_retval
)
1248 /* [noscript] void checkSameOrigin (in JSContextPtr aJSContext, in nsIURI aTargetURI); */
1250 FullTrustSecMan::CheckSameOrigin(JSContext
* aJSContext
, nsIURI
*aTargetURI
)
1255 /* void checkSameOriginURI (in nsIURI aSourceURI, in nsIURI aTargetURI); */
1257 FullTrustSecMan::CheckSameOriginURI(nsIURI
*aSourceURI
, nsIURI
*aTargetURI
,
1263 /* [noscript] nsIPrincipal getPrincipalFromContext (in JSContextPtr cx); */
1265 FullTrustSecMan::GetPrincipalFromContext(JSContext
* cx
, nsIPrincipal
**_retval
)
1267 NS_IF_ADDREF(*_retval
= mSystemPrincipal
);
1268 return *_retval
? NS_OK
: NS_ERROR_FAILURE
;
1271 /* [noscript] nsIPrincipal getChannelPrincipal (in nsIChannel aChannel); */
1273 FullTrustSecMan::GetChannelPrincipal(nsIChannel
*aChannel
, nsIPrincipal
**_retval
)
1275 NS_IF_ADDREF(*_retval
= mSystemPrincipal
);
1276 return *_retval
? NS_OK
: NS_ERROR_FAILURE
;
1279 /* boolean isSystemPrincipal (in nsIPrincipal aPrincipal); */
1281 FullTrustSecMan::IsSystemPrincipal(nsIPrincipal
*aPrincipal
, PRBool
*_retval
)
1283 *_retval
= aPrincipal
== mSystemPrincipal
;
1287 NS_IMETHODIMP_(nsIPrincipal
*)
1288 FullTrustSecMan::GetCxSubjectPrincipal(JSContext
*cx
)
1290 return mSystemPrincipal
;
1293 NS_IMETHODIMP_(nsIPrincipal
*)
1294 FullTrustSecMan::GetCxSubjectPrincipalAndFrame(JSContext
*cx
, JSStackFrame
**fp
)
1297 return mSystemPrincipal
;
1302 /***************************************************************************/
1304 // #define TEST_InitClassesWithNewWrappedGlobal
1306 #ifdef TEST_InitClassesWithNewWrappedGlobal
1307 // XXX hacky test code...
1308 #include "xpctest.h"
1310 class TestGlobal
: public nsIXPCTestNoisy
, public nsIXPCScriptable
1314 NS_DECL_NSIXPCTESTNOISY
1315 NS_DECL_NSIXPCSCRIPTABLE
1320 NS_IMPL_ISUPPORTS2(TestGlobal
, nsIXPCTestNoisy
, nsIXPCScriptable
)
1322 // The nsIXPCScriptable map declaration that will generate stubs for us...
1323 #define XPC_MAP_CLASSNAME TestGlobal
1324 #define XPC_MAP_QUOTED_CLASSNAME "TestGlobal"
1325 #define XPC_MAP_FLAGS nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY |\
1326 nsIXPCScriptable::USE_JSSTUB_FOR_DELPROPERTY |\
1327 nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY
1328 #include "xpc_map_end.h" /* This will #undef the above */
1330 NS_IMETHODIMP
TestGlobal::Squawk() {return NS_OK
;}
1334 // uncomment to install the test 'this' translator
1335 // #define TEST_TranslateThis
1337 #ifdef TEST_TranslateThis
1339 #include "xpctest.h"
1341 class nsXPCFunctionThisTranslator
: public nsIXPCFunctionThisTranslator
1345 NS_DECL_NSIXPCFUNCTIONTHISTRANSLATOR
1347 nsXPCFunctionThisTranslator();
1348 virtual ~nsXPCFunctionThisTranslator();
1349 /* additional members */
1352 /* Implementation file */
1353 NS_IMPL_ISUPPORTS1(nsXPCFunctionThisTranslator
, nsIXPCFunctionThisTranslator
)
1355 nsXPCFunctionThisTranslator::nsXPCFunctionThisTranslator()
1357 /* member initializers and constructor code */
1360 nsXPCFunctionThisTranslator::~nsXPCFunctionThisTranslator()
1362 /* destructor code */
1364 printf("destroying nsXPCFunctionThisTranslator\n");
1368 /* nsISupports TranslateThis (in nsISupports aInitialThis, in nsIInterfaceInfo aInterfaceInfo, in PRUint16 aMethodIndex, out PRBool aHideFirstParamFromJS, out nsIIDPtr aIIDOfResult); */
1370 nsXPCFunctionThisTranslator::TranslateThis(nsISupports
*aInitialThis
,
1371 nsIInterfaceInfo
*aInterfaceInfo
,
1372 PRUint16 aMethodIndex
,
1373 PRBool
*aHideFirstParamFromJS
,
1374 nsIID
* *aIIDOfResult
,
1375 nsISupports
**_retval
)
1377 NS_IF_ADDREF(aInitialThis
);
1378 *_retval
= aInitialThis
;
1379 *aHideFirstParamFromJS
= JS_FALSE
;
1380 *aIIDOfResult
= nsnull
;
1386 // ContextCallback calls are chained
1387 static JSContextCallback gOldJSContextCallback
;
1390 ContextCallback(JSContext
*cx
, uintN contextOp
)
1392 if (gOldJSContextCallback
&& !gOldJSContextCallback(cx
, contextOp
))
1395 if (contextOp
== JSCONTEXT_NEW
) {
1396 JS_SetErrorReporter(cx
, my_ErrorReporter
);
1397 JS_SetVersion(cx
, JSVERSION_LATEST
);
1403 main(int argc
, char **argv
, char **envp
)
1406 InitAutoreleasePool();
1410 JSObject
*glob
, *envobj
;
1415 // unbuffer stdout so that output is in the correct order; note that stderr
1416 // is unbuffered by default
1424 nsCOMPtr
<nsIServiceManager
> servMan
;
1425 rv
= NS_InitXPCOM2(getter_AddRefs(servMan
), nsnull
, nsnull
);
1426 if (NS_FAILED(rv
)) {
1427 printf("NS_InitXPCOM failed!\n");
1431 nsCOMPtr
<nsIComponentRegistrar
> registrar
= do_QueryInterface(servMan
);
1432 NS_ASSERTION(registrar
, "Null nsIComponentRegistrar");
1434 registrar
->AutoRegister(nsnull
);
1437 nsCOMPtr
<nsIJSRuntimeService
> rtsvc
= do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
1438 // get the JSRuntime from the runtime svc
1440 printf("failed to get nsJSRuntimeService!\n");
1444 if (NS_FAILED(rtsvc
->GetRuntime(&rt
)) || !rt
) {
1445 printf("failed to get JSRuntime from nsJSRuntimeService!\n");
1449 gOldJSContextCallback
= JS_SetContextCallback(rt
, ContextCallback
);
1451 cx
= JS_NewContext(rt
, 8192);
1453 printf("JS_NewContext failed!\n");
1457 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService(nsIXPConnect::GetCID());
1459 printf("failed to get nsXPConnect service!\n");
1463 // Since the caps security system might set a default security manager
1464 // we will be sure that the secman on this context gives full trust.
1465 nsRefPtr
<FullTrustSecMan
> secman
= new FullTrustSecMan();
1466 xpc
->SetSecurityManagerForJSContext(cx
, secman
, 0xFFFF);
1468 #ifndef XPCONNECT_STANDALONE
1469 // Fetch the system principal and store it away in a global, to use for
1470 // script compilation in Load() and ProcessFile() (including interactive
1473 nsCOMPtr
<nsIPrincipal
> princ
;
1475 nsCOMPtr
<nsIScriptSecurityManager
> securityManager
=
1476 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
);
1477 if (NS_SUCCEEDED(rv
) && securityManager
) {
1478 rv
= securityManager
->GetSystemPrincipal(getter_AddRefs(princ
));
1479 if (NS_FAILED(rv
)) {
1480 fprintf(gErrFile
, "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager service.\n");
1482 // fetch the JS principals and stick in a global
1483 rv
= princ
->GetJSPrincipals(cx
, &gJSPrincipals
);
1484 if (NS_FAILED(rv
)) {
1485 fprintf(gErrFile
, "+++ Failed to obtain JS principals from SystemPrincipal.\n");
1487 secman
->SetSystemPrincipal(princ
);
1490 fprintf(gErrFile
, "+++ Failed to get ScriptSecurityManager service, running without principals");
1495 #ifdef TEST_TranslateThis
1496 nsCOMPtr
<nsIXPCFunctionThisTranslator
>
1497 translator(new nsXPCFunctionThisTranslator
);
1498 xpc
->SetFunctionThisTranslator(NS_GET_IID(nsITestXPCFunctionCallback
), translator
, nsnull
);
1501 nsCOMPtr
<nsIJSContextStack
> cxstack
= do_GetService("@mozilla.org/js/xpc/ContextStack;1");
1503 printf("failed to get the nsThreadJSContextStack service!\n");
1507 if(NS_FAILED(cxstack
->Push(cx
))) {
1508 printf("failed to push the current JSContext on the nsThreadJSContextStack!\n");
1512 nsCOMPtr
<nsIXPCScriptable
> backstagePass
;
1513 nsresult rv
= rtsvc
->GetBackstagePass(getter_AddRefs(backstagePass
));
1514 if (NS_FAILED(rv
)) {
1515 fprintf(gErrFile
, "+++ Failed to get backstage pass from rtsvc: %8x\n",
1520 nsCOMPtr
<nsIXPConnectJSObjectHolder
> holder
;
1521 rv
= xpc
->InitClassesWithNewWrappedGlobal(cx
, backstagePass
,
1522 NS_GET_IID(nsISupports
),
1524 FLAG_SYSTEM_GLOBAL_OBJECT
,
1525 getter_AddRefs(holder
));
1529 rv
= holder
->GetJSObject(&glob
);
1530 if (NS_FAILED(rv
)) {
1531 NS_ASSERTION(glob
== nsnull
, "bad GetJSObject?");
1535 JS_BeginRequest(cx
);
1537 if (!JS_DefineFunctions(cx
, glob
, glob_functions
)) {
1542 envobj
= JS_DefineObject(cx
, glob
, "environment", &env_class
, NULL
, 0);
1543 if (!envobj
|| !JS_SetPrivate(cx
, envobj
, envp
)) {
1551 result
= ProcessArgs(cx
, glob
, argv
, argc
);
1554 //#define TEST_CALL_ON_WRAPPED_JS_AFTER_SHUTDOWN 1
1556 #ifdef TEST_CALL_ON_WRAPPED_JS_AFTER_SHUTDOWN
1557 // test of late call and release (see below)
1558 nsCOMPtr
<nsIJSContextStack
> bogus
;
1559 xpc
->WrapJS(cx
, glob
, NS_GET_IID(nsIJSContextStack
),
1560 (void**) getter_AddRefs(bogus
));
1563 JSPRINCIPALS_DROP(cx
, gJSPrincipals
);
1564 JS_ClearScope(cx
, glob
);
1567 cxstack
->Pop(&oldcx
);
1568 NS_ASSERTION(oldcx
== cx
, "JS thread context push/pop mismatch");
1571 JS_DestroyContext(cx
);
1572 } // this scopes the nsCOMPtrs
1573 // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
1574 rv
= NS_ShutdownXPCOM( NULL
);
1575 NS_ASSERTION(NS_SUCCEEDED(rv
), "NS_ShutdownXPCOM failed");
1577 #ifdef TEST_CALL_ON_WRAPPED_JS_AFTER_SHUTDOWN
1578 // test of late call and release (see above)
1580 bogus
->Peek(&bogusCX
);
1585 FinishAutoreleasePool();