Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / extensions / jssh / nsJSSh.cpp
blob13b68785e693afa1219af919de239dff6f2b1144
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is the Mozilla JavaScript Shell project.
17 * The Initial Developer of the Original Code is
18 * Alex Fritze.
19 * Portions created by the Initial Developer are Copyright (C) 2003
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Alex Fritze <alex@croczilla.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsJSSh.h"
40 #include "nsIJSRuntimeService.h"
41 #include "nsIServiceManager.h"
42 #include "nsIXPConnect.h"
43 #include "nsIProxyObjectManager.h"
44 #include "nsIScriptSecurityManager.h"
45 #include "nsIIOService.h"
46 #include "nsNetCID.h"
47 #include "nsIChannel.h"
48 #include "nsThreadUtils.h"
49 #include "nsServiceManagerUtils.h"
50 #include "nsXPCOMCIDInternal.h"
51 #include "nsMemory.h"
52 #include "nsAutoPtr.h"
54 #ifdef PR_LOGGING
55 PRLogModuleInfo *gJSShLog = PR_NewLogModule("jssh");
56 #endif
58 //**********************************************************************
59 // Javascript Environment
61 const char *gWelcome = "Welcome to the Mozilla JavaScript Shell!\n";
62 const char *gGoodbye = "Goodbye!\n";
64 // GetJSShGlobal: helper for native js functions to obtain the global
65 // JSSh object
66 PRBool GetJSShGlobal(JSContext *cx, JSObject *obj, nsJSSh** shell)
68 JSAutoRequest ar(cx);
70 #ifdef DEBUG
71 // printf("GetJSShGlobal(cx=%p, obj=%p)\n", cx, obj);
72 #endif
73 JSObject *parent, *global = obj;
74 if (!global) {
75 NS_ERROR("need a non-null obj to find script global");
76 return PR_FALSE;
79 // in most of our cases, 'global' is already the correct obj, since
80 // we use bound methods. For cases where we call
81 // GetJSShGlobal from an unbound method, we need to walk the
82 // parent chain:
83 // XXX I think the comment above is obsolete. We only call
84 // GetJSShGlobal from bound methods, in which case the
85 // parent is the global obj. For non-bound methods, walking the
86 // parent chain to obtain the global object will only work when the
87 // method is rooted in the current script context, so it is not
88 // reliable (???). ASSERTION below to test the assumption. Once proven,
89 // remove loop.
90 while ((parent = JS_GetParent(cx, global))) {
91 NS_ERROR("Parent chain weirdness. Probably benign, but we should not reach this.");
92 #ifdef DEBUG
93 // printf(" obj's parent = %p\n", parent);
94 #endif
95 global = parent;
98 // JSClass* clazz = JS_GET_CLASS(cx, global);
99 // if (!IS_WRAPPER_CLASS(clazz)) {
100 // NS_ERROR("the script global's class is not of the right type");
101 // return PR_FALSE;
102 // }
104 // XXX use GetWrappedNativeOfJSObject
105 nsIXPConnectWrappedNative *wrapper = static_cast<nsIXPConnectWrappedNative*>(JS_GetPrivate(cx, global));
106 nsCOMPtr<nsISupports> native;
107 wrapper->GetNative(getter_AddRefs(native));
108 nsCOMPtr<nsIJSSh> jssh = do_QueryInterface(native);
109 NS_ASSERTION(jssh, "no jssh global");
110 *shell = static_cast<nsJSSh*>((nsIJSSh*)(jssh.get()));
111 return PR_TRUE;
114 static void
115 my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
117 // xxx getting the global obj from the cx. will that give us grief?
118 JSObject* obj = JS_GetGlobalObject(cx);
119 nsJSSh* shell;
120 if (!GetJSShGlobal(cx, obj, &shell)) return;
122 // XXX use JSErrorReport for better info
124 PRUint32 bytesWritten;
125 if (shell->mOutput) {
126 if (shell->mEmitHeader) {
127 char buf[80];
128 sprintf(buf, "[%d]", strlen(message));
129 shell->mOutput->Write(buf, strlen(buf), &bytesWritten);
131 shell->mOutput->Write(message, strlen(message), &bytesWritten);
135 static JSBool
136 Print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
138 nsJSSh* shell;
139 if (!GetJSShGlobal(cx, obj, &shell)) return JS_FALSE;
141 JSAutoRequest ar(cx);
143 PRUint32 bytesWritten;
145 #ifdef DEBUG
146 // nsCOMPtr<nsIThread> thread;
147 // nsIThread::GetCurrent(getter_AddRefs(thread));
148 // printf("printing on thread %p, shell %p, output %p, cx=%p, obj=%p\n", thread.get(), shell, shell->mOutput, cx, obj);
149 #endif
151 for (unsigned int i=0; i<argc; ++i) {
152 JSString *str = JS_ValueToString(cx, argv[i]);
153 if (!str) return JS_FALSE;
154 if (shell->mOutput) {
155 if (shell->mEmitHeader) {
156 char buf[80];
157 sprintf(buf, "[%d]", JS_GetStringLength(str));
158 shell->mOutput->Write(buf, strlen(buf), &bytesWritten);
160 shell->mOutput->Write(JS_GetStringBytes(str), JS_GetStringLength(str), &bytesWritten);
162 else
163 printf("%s", JS_GetStringBytes(str)); // use cout if no output stream given.
164 #ifdef DEBUG
165 // printf("%s", JS_GetStringBytes(str));
166 #endif
168 return JS_TRUE;
171 static JSBool
172 Quit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
174 nsJSSh* shell;
175 if (!GetJSShGlobal(cx, obj, &shell)) return JS_FALSE;
177 PRUint32 bytesWritten;
179 if (shell->mOutput)
180 shell->mOutput->Write(gGoodbye, strlen(gGoodbye), &bytesWritten);
181 shell->mQuit = PR_TRUE;
183 return JS_TRUE;
186 static JSBool
187 Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
189 nsJSSh* shell;
191 JSAutoRequest ar(cx);
193 if (!GetJSShGlobal(cx, obj, &shell)) return JS_FALSE;
195 for (unsigned int i=0; i<argc; ++i) {
196 JSString *str = JS_ValueToString(cx, argv[i]);
197 if (!str) return JS_FALSE;
198 //argv[i] = STRING_TO_JSVAL(str);
199 const char *url = JS_GetStringBytes(str);
200 if (!shell->LoadURL(url, rval))
201 return JS_FALSE;
203 return JS_TRUE;
206 static JSBool
207 FlushEventQueue(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
209 nsJSSh* shell;
210 if (!GetJSShGlobal(cx, obj, &shell)) return JS_FALSE;
212 NS_ProcessPendingEvents(nsnull);
214 return JS_TRUE;
217 static JSBool
218 Suspend(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
220 nsJSSh* shell;
221 if (!GetJSShGlobal(cx, obj, &shell)) return JS_FALSE;
223 nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
225 PR_AtomicIncrement(&shell->mSuspendCount);
227 while (shell->mSuspendCount) {
228 LOG(("|"));
229 NS_ProcessNextEvent(thread);
232 return JS_TRUE;
235 static JSBool
236 Resume(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
238 nsJSSh* shell;
239 if (!GetJSShGlobal(cx, obj, &shell)) return JS_FALSE;
241 PR_AtomicDecrement(&shell->mSuspendCount);
243 return JS_TRUE;
246 static JSBool
247 AddressOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
249 if (argc!=1) return JS_FALSE;
251 JSAutoRequest ar(cx);
253 // xxx If argv[0] is not an obj already, we'll get a transient
254 // address from JS_ValueToObject. Maybe we should throw an exception
255 // instead.
257 JSObject *arg_obj;
258 if (!JS_ValueToObject(cx, argv[0], &arg_obj)) {
259 return JS_FALSE;
262 char buf[80];
263 sprintf(buf, "%p", arg_obj);
264 JSString *str = JS_NewStringCopyZ(cx, buf);
265 *rval = STRING_TO_JSVAL(str);
266 return JS_TRUE;
269 static JSBool
270 SetProtocol(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
272 if (argc!=1) return JS_FALSE;
273 nsJSSh* shell;
274 if (!GetJSShGlobal(cx, obj, &shell)) return JS_FALSE;
276 JSAutoRequest ar(cx);
278 JSString *str = JS_ValueToString(cx, argv[0]);
279 if (!str) return JS_FALSE;
280 char *protocol = JS_GetStringBytes(str);
282 if (!strcmp(protocol, "interactive")) {
283 shell->mEmitHeader = PR_FALSE;
284 shell->mPrompt = NS_LITERAL_CSTRING("\n> ");
285 shell->mProtocol = protocol;
287 else if (!strcmp(protocol, "synchronous")) {
288 shell->mEmitHeader = PR_TRUE;
289 shell->mPrompt = NS_LITERAL_CSTRING("\n> ");
290 shell->mProtocol = protocol;
292 else if (!strcmp(protocol, "plain")) {
293 shell->mEmitHeader = PR_FALSE;
294 shell->mPrompt = NS_LITERAL_CSTRING("\n");
295 shell->mProtocol = protocol;
297 else return JS_FALSE;
299 return JS_TRUE;
302 static JSBool
303 GetProtocol(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
305 nsJSSh* shell;
306 if (!GetJSShGlobal(cx, obj, &shell)) return JS_FALSE;
308 JSAutoRequest ar(cx);
310 JSString *str = JS_NewStringCopyZ(cx, shell->mProtocol.get());
311 *rval = STRING_TO_JSVAL(str);
312 return JS_TRUE;
315 static JSBool
316 SetContextObj(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
318 nsJSSh* shell;
319 if (!GetJSShGlobal(cx, obj, &shell)) return JS_FALSE;
321 JSAutoRequest ar(cx);
323 if (argc!=1) return JS_FALSE;
325 JSObject *arg_obj;
326 if (!JS_ValueToObject(cx, argv[0], &arg_obj)) {
327 return JS_FALSE;
330 if (shell->mContextObj != shell->mGlobal)
331 JS_RemoveRoot(cx, &(shell->mContextObj));
333 shell->mContextObj = arg_obj;
335 if (shell->mContextObj != shell->mGlobal)
336 JS_AddRoot(cx, &(shell->mContextObj));
338 return JS_TRUE;
341 static JSBool
342 DebugBreak(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
344 nsJSSh* shell;
345 if (!GetJSShGlobal(cx, obj, &shell)) return JS_FALSE;
347 NS_BREAK();
349 return JS_TRUE;
352 static JSBool
353 GetInputStream(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
355 nsJSSh* shell;
356 if (!GetJSShGlobal(cx, obj, &shell)) return JS_FALSE;
358 JSAutoRequest ar(cx);
360 nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
361 if (!xpc) {
362 NS_ERROR("failed to get xpconnect service");
363 return JS_FALSE;
366 nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
367 xpc->WrapNative(cx, shell->mGlobal, shell->mInput,
368 NS_GET_IID(nsIInputStream),
369 getter_AddRefs(wrapper));
370 if (!wrapper) {
371 NS_ERROR("could not wrap input stream object");
372 return JS_FALSE;
375 JSObject* wrapper_jsobj = nsnull;
376 wrapper->GetJSObject(&wrapper_jsobj);
377 NS_ASSERTION(wrapper_jsobj, "could not get jsobject of wrapped native");
379 *rval = OBJECT_TO_JSVAL(wrapper_jsobj);
381 return JS_TRUE;
384 static JSBool
385 GetOutputStream(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
387 nsJSSh* shell;
388 if (!GetJSShGlobal(cx, obj, &shell)) return JS_FALSE;
390 JSAutoRequest ar(cx);
392 nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
393 if (!xpc) {
394 NS_ERROR("failed to get xpconnect service");
395 return JS_FALSE;
398 nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
399 xpc->WrapNative(cx, shell->mGlobal, shell->mOutput,
400 NS_GET_IID(nsIOutputStream),
401 getter_AddRefs(wrapper));
402 if (!wrapper) {
403 NS_ERROR("could not wrap output stream object");
404 return JS_FALSE;
407 JSObject* wrapper_jsobj = nsnull;
408 wrapper->GetJSObject(&wrapper_jsobj);
409 NS_ASSERTION(wrapper_jsobj, "could not get jsobject of wrapped native");
411 *rval = OBJECT_TO_JSVAL(wrapper_jsobj);
413 return JS_TRUE;
416 // these all need JSFUN_BOUND_METHOD flags, so that we can do
417 // things like:
418 // win.p = print, where win is rooted in some other global
419 // object.
420 static JSFunctionSpec global_functions[] = {
421 {"print", Print, 1, JSFUN_BOUND_METHOD, 0},
422 {"dump", Print, 1, JSFUN_BOUND_METHOD, 0},
423 {"quit", Quit, 0, JSFUN_BOUND_METHOD, 0},
424 {"exit", Quit, 0, JSFUN_BOUND_METHOD, 0},
425 {"load", Load, 1, JSFUN_BOUND_METHOD, 0},
426 {"suspend", Suspend, 0, JSFUN_BOUND_METHOD, 0},
427 {"resume", Resume, 0, JSFUN_BOUND_METHOD, 0},
428 {"flushEventQueue", FlushEventQueue,0, JSFUN_BOUND_METHOD, 0},
429 {"addressOf", AddressOf, 1, 0, 0},
430 {"setProtocol", SetProtocol, 1, JSFUN_BOUND_METHOD, 0},
431 {"getProtocol", GetProtocol, 0, JSFUN_BOUND_METHOD, 0},
432 {"setContextObj", SetContextObj, 1, JSFUN_BOUND_METHOD, 0},
433 {"debugBreak", DebugBreak, 0, JSFUN_BOUND_METHOD, 0},
434 {"getInputStream", GetInputStream, 0, JSFUN_BOUND_METHOD, 0},
435 {"getOutputStream", GetOutputStream,0, JSFUN_BOUND_METHOD, 0},
436 {nsnull, nsnull, 0, 0, 0}
440 //**********************************************************************
441 // nsJSSh Implementation
443 nsJSSh::nsJSSh(nsIInputStream* input,
444 nsIOutputStream*output,
445 const nsACString &startupURI) :
446 mInput(input), mOutput(output), mQuit(PR_FALSE), mStartupURI(startupURI),
447 mSuspendCount(0), mPrompt("\n> "),
448 mEmitHeader(PR_FALSE), mProtocol("interactive")
452 nsJSSh::~nsJSSh()
454 LOG(("JSSh: ~connection!\n"));
457 already_AddRefed<nsIRunnable>
458 CreateJSSh(nsIInputStream* input, nsIOutputStream*output,
459 const nsACString &startupURI)
461 nsIRunnable* obj = new nsJSSh(input, output, startupURI);
462 NS_IF_ADDREF(obj);
463 return obj;
466 //----------------------------------------------------------------------
467 // nsISupports methods:
469 NS_IMPL_THREADSAFE_ADDREF(nsJSSh)
470 NS_IMPL_THREADSAFE_RELEASE(nsJSSh)
472 NS_INTERFACE_MAP_BEGIN(nsJSSh)
473 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJSSh)
474 NS_INTERFACE_MAP_ENTRY(nsIRunnable)
475 NS_INTERFACE_MAP_ENTRY(nsIJSSh)
476 NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
477 NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)
478 NS_INTERFACE_MAP_END
481 //----------------------------------------------------------------------
482 // nsIRunnable methods:
484 NS_IMETHODIMP nsJSSh::Run()
486 nsCOMPtr<nsIJSSh> proxied_shell;
487 if (!NS_IsMainThread()) {
488 nsCOMPtr<nsIProxyObjectManager> pom = do_GetService(NS_XPCOMPROXY_CONTRACTID);
489 NS_ASSERTION(pom, "uh-oh, no proxy object manager!");
490 pom->GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
491 NS_GET_IID(nsIJSSh),
492 (nsIJSSh*)this,
493 NS_PROXY_SYNC,
494 getter_AddRefs(proxied_shell));
496 else {
497 LOG(("jssh shell will block main thread!\n"));
498 proxied_shell = this;
500 proxied_shell->Init();
502 if (mInput) {
503 // read-eval-print loop
504 PRUint32 bytesWritten;
505 if (mOutput && !mProtocol.Equals(NS_LITERAL_CSTRING("plain")))
506 mOutput->Write(gWelcome, strlen(gWelcome), &bytesWritten);
508 while (!mQuit) {
509 if (mOutput)
510 mOutput->Write(mPrompt.get(), mPrompt.Length(), &bytesWritten);
512 // accumulate input until we get a compilable unit:
513 PRBool iscompilable;
514 mBufferPtr = 0;
515 #ifdef DEBUG
516 // nsCOMPtr<nsIThread> thread;
517 // nsIThread::GetCurrent(getter_AddRefs(thread));
518 // printf("blocking on thread %p\n", thread.get());
519 #endif
520 do {
521 PRUint32 bytesRead = 0;
522 mInput->Read(mBuffer+mBufferPtr, 1, &bytesRead);
523 if (bytesRead) {
524 ++mBufferPtr;
526 else {
527 // connection was terminated by the client
528 mQuit = PR_TRUE;
529 break;
531 // XXX signal buffer overflow ??
532 // XXX ideally we want a dynamically resizing buffer.
533 }while (mBufferPtr<cBufferSize &&
534 (mBuffer[mBufferPtr-1]!=10 || (NS_SUCCEEDED(proxied_shell->IsBufferCompilable(&iscompilable)) && !iscompilable)));
535 NS_ASSERTION(mBufferPtr<cBufferSize, "buffer overflow");
537 proxied_shell->ExecuteBuffer();
541 proxied_shell->Cleanup();
543 if (!NS_IsMainThread()) {
544 // Shutdown the current thread, which must be done from the main thread.
545 nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
546 nsCOMPtr<nsIThread> proxied_thread;
547 nsCOMPtr<nsIProxyObjectManager> pom = do_GetService(NS_XPCOMPROXY_CONTRACTID);
548 NS_ASSERTION(pom, "uh-oh, no proxy object manager!");
549 pom->GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
550 NS_GET_IID(nsIThread),
551 thread.get(),
552 NS_PROXY_ASYNC,
553 getter_AddRefs(proxied_thread));
554 if (proxied_thread)
555 proxied_thread->Shutdown();
557 return NS_OK;
560 //----------------------------------------------------------------------
561 // nsIJSSh methods
563 NS_IMETHODIMP nsJSSh::Init()
565 nsCOMPtr<nsIScriptSecurityManager> ssm = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
566 if (!ssm) {
567 NS_ERROR("failed to get script security manager");
568 return NS_ERROR_FAILURE;
571 ssm->GetSystemPrincipal(getter_AddRefs(mPrincipal));
572 if (!mPrincipal) {
573 NS_ERROR("failed to get system principal");
574 return NS_ERROR_FAILURE;
577 nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
578 if (!xpc) {
579 NS_ERROR("failed to get xpconnect service");
580 return NS_ERROR_FAILURE;
583 nsCOMPtr<nsIJSRuntimeService> rtsvc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
584 // get the JSRuntime from the runtime svc
585 if (!rtsvc) {
586 NS_ERROR("failed to get nsJSRuntimeService");
587 return NS_ERROR_FAILURE;
590 JSRuntime *rt = nsnull;
591 if (NS_FAILED(rtsvc->GetRuntime(&rt)) || !rt) {
592 NS_ERROR("failed to get JSRuntime from nsJSRuntimeService");
593 return NS_ERROR_FAILURE;
596 mJSContext = JS_NewContext(rt, 8192);
597 if (!mJSContext) {
598 NS_ERROR("JS_NewContext failed");
599 return NS_ERROR_FAILURE;
602 JSAutoRequest ar(mJSContext);
604 // Enable e4x:
605 JS_SetOptions(mJSContext, JS_GetOptions(mJSContext) | JSOPTION_XML);
607 // Always use the latest js version
608 JS_SetVersion(mJSContext, JSVERSION_LATEST);
610 mContextStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
611 if (!mContextStack) {
612 NS_ERROR("failed to get the nsThreadJSContextStack service");
613 return NS_ERROR_FAILURE;
616 JS_SetErrorReporter(mJSContext, my_ErrorReporter);
618 nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
619 xpc->InitClassesWithNewWrappedGlobal(mJSContext, (nsIJSSh*)this,
620 NS_GET_IID(nsISupports),
621 PR_TRUE,
622 getter_AddRefs(holder));
623 if (!holder) {
624 NS_ERROR("global initialization failed");
625 return NS_ERROR_FAILURE;
628 holder->GetJSObject(&mGlobal);
629 if (!mGlobal) {
630 NS_ERROR("bad global object");
631 return NS_ERROR_FAILURE;
633 mContextObj = mGlobal;
635 if (!JS_DefineFunctions(mJSContext, mGlobal, global_functions)) {
636 NS_ERROR("failed to initialise global functions");
637 return NS_ERROR_FAILURE;
640 if (!mStartupURI.IsEmpty())
641 LoadURL(mStartupURI.get());
643 return NS_OK;
646 NS_IMETHODIMP nsJSSh::Cleanup()
648 nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
649 if (!xpc) {
650 NS_ERROR("failed to get xpconnect service");
651 return NS_ERROR_FAILURE;
655 JSAutoRequest ar(mJSContext);
657 if (mContextObj != mGlobal)
658 JS_RemoveRoot(mJSContext, &(mContextObj));
660 JS_ClearScope(mJSContext, mGlobal);
661 JS_GC(mJSContext);
664 JS_DestroyContext(mJSContext);
665 return NS_OK;
668 NS_IMETHODIMP nsJSSh::ExecuteBuffer()
670 #ifdef DEBUG
671 // nsCOMPtr<nsIThread> thread;
672 // nsIThread::GetCurrent(getter_AddRefs(thread));
673 // printf("executing on thread %p\n", thread.get());
674 #endif
676 JS_BeginRequest(mJSContext);
677 JS_ClearPendingException(mJSContext);
678 JSPrincipals *jsprincipals;
679 mPrincipal->GetJSPrincipals(mJSContext, &jsprincipals);
681 if(NS_FAILED(mContextStack->Push(mJSContext))) {
682 NS_ERROR("failed to push the current JSContext on the nsThreadJSContextStack");
683 return NS_ERROR_FAILURE;
686 JSScript *script = JS_CompileScriptForPrincipals(mJSContext, mContextObj, jsprincipals, mBuffer, mBufferPtr, "interactive", 0);
688 if (script) {
689 jsval result;
690 if (JS_ExecuteScript(mJSContext, mContextObj, script, &result) && result!=JSVAL_VOID && mOutput) {
691 // XXX for some wrapped native objects the following code will crash; probably because the
692 // native object is getting released before we reach this:
693 JSString *str = JS_ValueToString(mJSContext, result);
694 if (str) {
695 nsDependentString chars(reinterpret_cast<const PRUnichar*>
696 (JS_GetStringChars(str)),
697 JS_GetStringLength(str));
698 NS_ConvertUTF16toUTF8 cstr(chars);
699 PRUint32 bytesWritten;
700 mOutput->Write(cstr.get(), cstr.Length(), &bytesWritten);
703 JS_DestroyScript(mJSContext, script);
706 JSContext *oldcx;
707 mContextStack->Pop(&oldcx);
708 NS_ASSERTION(oldcx == mJSContext, "JS thread context push/pop mismatch");
710 JSPRINCIPALS_DROP(mJSContext, jsprincipals);
712 JS_EndRequest(mJSContext);
714 return NS_OK;
717 NS_IMETHODIMP nsJSSh::IsBufferCompilable(PRBool *_retval)
719 JSAutoRequest ar(mJSContext);
720 *_retval = JS_BufferIsCompilableUnit(mJSContext, mContextObj, mBuffer, mBufferPtr);
721 return NS_OK;
724 //----------------------------------------------------------------------
725 // nsIScriptObjectPrincipal methods:
727 nsIPrincipal *
728 nsJSSh::GetPrincipal()
730 return mPrincipal;
733 //----------------------------------------------------------------------
734 // nsIXPCScriptable methods:
736 #define XPC_MAP_CLASSNAME nsJSSh
737 #define XPC_MAP_QUOTED_CLASSNAME "JSSh"
738 #define XPC_MAP_WANT_NEWRESOLVE
739 #define XPC_MAP_FLAGS nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY | \
740 nsIXPCScriptable::USE_JSSTUB_FOR_DELPROPERTY | \
741 nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY | \
742 nsIXPCScriptable::DONT_ENUM_STATIC_PROPS | \
743 nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE | \
744 nsIXPCScriptable::DONT_REFLECT_INTERFACE_NAMES
745 #include "xpc_map_end.h" /* This will #undef the above */
747 /* PRBool newResolve (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx,
748 in JSObjectPtr obj, in JSVal id, in PRUint32 flags, out JSObjectPtr objp); */
749 NS_IMETHODIMP
750 nsJSSh::NewResolve(nsIXPConnectWrappedNative *wrapper,
751 JSContext * cx, JSObject * obj,
752 jsval id, PRUint32 flags,
753 JSObject * *objp, PRBool *_retval)
755 JSBool resolved;
757 JSAutoRequest ar(cx);
759 *_retval = JS_ResolveStandardClass(cx, obj, id, &resolved);
760 if (*_retval && resolved)
761 *objp = obj;
762 return NS_OK;
765 //----------------------------------------------------------------------
766 // Implementation helpers:
768 PRBool nsJSSh::LoadURL(const char *url, jsval* retval)
770 nsCOMPtr<nsIIOService> ioserv = do_GetService(NS_IOSERVICE_CONTRACTID);
771 if (!ioserv) {
772 NS_ERROR("could not get io service");
773 return PR_FALSE;
776 nsCOMPtr<nsIChannel> channel;
777 ioserv->NewChannel(nsDependentCString(url), nsnull, nsnull, getter_AddRefs(channel));
778 if (!channel) {
779 NS_ERROR("could not create channel");
780 return PR_FALSE;
783 nsCOMPtr<nsIInputStream> instream;
784 channel->Open(getter_AddRefs(instream));
785 if (!instream) {
786 NS_ERROR("could not open stream");
787 return PR_FALSE;
790 nsCString buffer;
791 nsAutoArrayPtr<char> buf(new char[1024]);
792 if (!buf) {
793 NS_ERROR("could not alloc buffer");
794 return PR_FALSE;
797 PRUint32 bytesRead = 0;
799 do {
800 if (NS_FAILED(instream->Read(buf, 1024, &bytesRead))) {
801 NS_ERROR("stream read error");
802 return PR_FALSE;
804 buffer.Append(buf, bytesRead);
805 LOG(("appended %d bytes:\n%s", bytesRead, buffer.get()));
806 } while (bytesRead > 0);
808 LOG(("loaded %d bytes:\n%s", buffer.Length(), buffer.get()));
810 JS_BeginRequest(mJSContext);
811 JSPrincipals *jsprincipals;
812 mPrincipal->GetJSPrincipals(mJSContext, &jsprincipals);
814 if(NS_FAILED(mContextStack->Push(mJSContext))) {
815 NS_ERROR("failed to push the current JSContext on the nsThreadJSContextStack");
816 return NS_ERROR_FAILURE;
819 jsval result;
820 JSBool ok = JS_EvaluateScriptForPrincipals(mJSContext, mContextObj,
821 jsprincipals, buffer.get(),
822 buffer.Length(),
823 url, 1, &result);
824 JSPRINCIPALS_DROP(mJSContext, jsprincipals);
826 JSContext *oldcx;
827 mContextStack->Pop(&oldcx);
828 NS_ASSERTION(oldcx == mJSContext, "JS thread context push/pop mismatch");
830 if (ok && retval) *retval=result;
832 JS_EndRequest(mJSContext);
834 return ok;