head 1.7; access; symbols OSSP_JS_1_6_20070208:1.7 MOZILLA_JS_1_6_20070208:1.1.1.2 MOZILLA_JS_1_6_20070102:1.1.1.2 MOZILLA_JS_1_6_20060916:1.1.1.2 OSSP_JS_1_6_20060820:1.7 MOZILLA_JS_1_6_20060820:1.1.1.2 OSSP_JS_1_6_20060803:1.7 MOZILLA_JS_1_6_20060803:1.1.1.2 OSSP_JS_1_6_20060731:1.4 MOZILLA_JS_1_6_20060731:1.1.1.2 OSSP_JS_1_6_20060730:1.4 MOZILLA_JS_1_6_20060730:1.1.1.2 OSSP_JS_1_6_20060729:1.3 MOZILLA_JS_1_6_20060729:1.1.1.2 OSSP_JS_1_6_20060724:1.3 MOZILLA_JS_1_6_20060724:1.1.1.2 MOZILLA_JS_1_6_20060722:1.1.1.1 OSSP_JS_1_6_20060722:1.1.1.1 MOZILLA:1.1.1; locks; strict; comment @ * @; 1.7 date 2006.08.03.13.19.20; author rse; state Exp; branches; next 1.6; commitid 9Bvk8Ze7oUq2ToHr; 1.6 date 2006.08.03.12.41.28; author rse; state Exp; branches; next 1.5; commitid kujso7TfogkZFoHr; 1.5 date 2006.08.03.12.30.16; author rse; state Exp; branches; next 1.4; commitid eoBuOGsTHMzdCoHr; 1.4 date 2006.07.30.08.00.45; author rse; state Exp; branches; next 1.3; commitid MYsn6PDUAj5JfRGr; 1.3 date 2006.07.24.18.38.26; author rse; state Exp; branches; next 1.2; commitid ZjrCVkA43HotY8Gr; 1.2 date 2006.07.23.18.34.15; author rse; state Exp; branches; next 1.1; commitid gVEVhueKwq30Z0Gr; 1.1 date 2006.01.06.16.49.15; author rse; state Exp; branches 1.1.1.1; next ; commitid yL3y5cCdrhpJcQFr; 1.1.1.1 date 2006.01.06.16.49.15; author rse; state Exp; branches; next 1.1.1.2; commitid yL3y5cCdrhpJcQFr; 1.1.1.2 date 2006.04.04.14.09.44; author rse; state Exp; branches; next ; commitid 8tZybjOP9mCIV8Gr; desc @@ 1.7 log @Add optional Dynamic Shared Object (DSO) support (see src/jsdso.[ch]). This comes in two flavors: 1. Provide two public C API functions... JSBool JS_DSOLoad (JSContext *cx, int *id, const char *filename); JSBool JS_DSOUnload (JSContext *cx, int id); ...as an ultra-thin wrapper around the POSIX dlopen(3) API. It especially mimics the BSD RTLD behaviour of calling pre-defined functions (mandatory "js_DSO_load" and optional "js_DSO_unload") inside the DSO after/before the dlopen/dlclose calls. This allows the DSOs to perform their init/shutdown actions. 2. Provide a small JavaScript global object "DSO" which binds the two public DSO C API functions into the JavaScript language as "DSO.load" and "DSO.unload". The "DSO" object can be created by the friend C API function js_InitDSOClass(). This function is used by the command-linne interface "js" by default. As a result the OSSP Mozilla JavaScript engine is now able to dynamically load C extensions similar to what other programming languages provide since a longer time. @ text @/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sw=4 et tw=80: * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * JS shell. */ #include "jsstddef.h" #include #include #include #include #include "jstypes.h" #include "jsarena.h" #include "jsutil.h" #include "jsprf.h" #include "jsapi.h" #include "jsatom.h" #include "jscntxt.h" #include "jsdbgapi.h" #include "jsemit.h" #include "jsfun.h" #include "jsgc.h" #include "jslock.h" #include "jsobj.h" #include "jsparse.h" #include "jsscope.h" #include "jsscript.h" #ifdef OSSP #if defined(JS_HAS_FILE_OBJECT) && (JS_HAS_FILE_OBJECT - 0) /* OSSP BUGFIX */ #include "jsfile.h" #endif #if defined(JS_HAS_DSO_OBJECT) && (JS_HAS_DSO_OBJECT -0) #include "jsdso.h" #endif #endif #ifdef PERLCONNECT #include "perlconnect/jsperl.h" #endif #ifdef LIVECONNECT #include "jsjava.h" #endif #ifdef JSDEBUGGER #include "jsdebug.h" #ifdef JSDEBUGGER_JAVA_UI #include "jsdjava.h" #endif /* JSDEBUGGER_JAVA_UI */ #ifdef JSDEBUGGER_C_UI #include "jsdb.h" #endif /* JSDEBUGGER_C_UI */ #endif /* JSDEBUGGER */ #ifdef XP_UNIX #include #include #include #endif #if defined(XP_WIN) || defined(XP_OS2) #include /* for isatty() */ #endif #define EXITCODE_RUNTIME_ERROR 3 #define EXITCODE_FILE_NOT_FOUND 4 size_t gStackChunkSize = 8192; static size_t gMaxStackSize = 0; static jsuword gStackBase; int gExitCode = 0; JSBool gQuitting = JS_FALSE; FILE *gErrFile = NULL; FILE *gOutFile = NULL; #ifdef JSDEBUGGER static JSDContext *_jsdc; #ifdef JSDEBUGGER_JAVA_UI static JSDJContext *_jsdjc; #endif /* JSDEBUGGER_JAVA_UI */ #endif /* JSDEBUGGER */ static JSBool reportWarnings = JS_TRUE; static JSBool compileOnly = JS_FALSE; typedef enum JSShellErrNum { #define MSG_DEF(name, number, count, exception, format) \ name = number, #include "jsshell.msg" #undef MSG_DEF JSShellErr_Limit #undef MSGDEF } JSShellErrNum; static const JSErrorFormatString * my_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber); #ifdef EDITLINE extern char *readline(const char *prompt); extern void add_history(char *line); #endif static JSBool GetLine(JSContext *cx, char *bufp, FILE *file, const char *prompt) { #ifdef EDITLINE /* * Use readline only if file is stdin, because there's no way to specify * another handle. Are other filehandles interactive? */ if (file == stdin) { char *linep = readline(prompt); if (!linep) return JS_FALSE; if (linep[0] != '\0') add_history(linep); strcpy(bufp, linep); JS_free(cx, linep); bufp += strlen(bufp); *bufp++ = '\n'; *bufp = '\0'; } else #endif { char line[256]; fprintf(gOutFile, prompt); fflush(gOutFile); if (!fgets(line, sizeof line, file)) return JS_FALSE; strcpy(bufp, line); } return JS_TRUE; } static void Process(JSContext *cx, JSObject *obj, char *filename) { JSBool ok, hitEOF; JSScript *script; jsval result; JSString *str; char buffer[4096]; char *bufp; int lineno; int startline; FILE *file; jsuword stackLimit; if (!filename || strcmp(filename, "-") == 0) { file = stdin; } else { file = fopen(filename, "r"); if (!file) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_CANT_OPEN, filename, strerror(errno)); gExitCode = EXITCODE_FILE_NOT_FOUND; return; } } if (gMaxStackSize == 0) { /* * Disable checking for stack overflow if limit is zero. */ stackLimit = 0; } else { #if JS_STACK_GROWTH_DIRECTION > 0 stackLimit = gStackBase + gMaxStackSize; #else stackLimit = gStackBase - gMaxStackSize; #endif } JS_SetThreadStackLimit(cx, stackLimit); #if defined(OSSP) && defined(XP_WIN) if (filename) { #else if (!isatty(fileno(file))) { #endif /* * It's not interactive - just execute it. * * Support the UNIX #! shell hack; gobble the first line if it starts * with '#'. TODO - this isn't quite compatible with sharp variables, * as a legal js program (using sharp variables) might start with '#'. * But that would require multi-character lookahead. */ int ch = fgetc(file); if (ch == '#') { while((ch = fgetc(file)) != EOF) { if (ch == '\n' || ch == '\r') break; } } ungetc(ch, file); script = JS_CompileFileHandle(cx, obj, filename, file); if (script) { if (!compileOnly) (void)JS_ExecuteScript(cx, obj, script, &result); JS_DestroyScript(cx, script); } return; } /* It's an interactive filehandle; drop into read-eval-print loop. */ lineno = 1; hitEOF = JS_FALSE; do { bufp = buffer; *bufp = '\0'; /* * Accumulate lines until we get a 'compilable unit' - one that either * generates an error (before running out of source) or that compiles * cleanly. This should be whenever we get a complete statement that * coincides with the end of a line. */ startline = lineno; do { if (!GetLine(cx, bufp, file, startline == lineno ? "js> " : "")) { hitEOF = JS_TRUE; break; } bufp += strlen(bufp); lineno++; } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer))); /* Clear any pending exception from previous failed compiles. */ JS_ClearPendingException(cx); script = JS_CompileScript(cx, obj, buffer, strlen(buffer), "typein", startline); if (script) { if (!compileOnly) { ok = JS_ExecuteScript(cx, obj, script, &result); if (ok && result != JSVAL_VOID) { str = JS_ValueToString(cx, result); if (str) fprintf(gOutFile, "%s\n", JS_GetStringBytes(str)); else ok = JS_FALSE; } } JS_DestroyScript(cx, script); } } while (!hitEOF && !gQuitting); fprintf(gOutFile, "\n"); return; } static int usage(void) { fprintf(gErrFile, "%s\n", JS_GetImplementationVersion()); fprintf(gErrFile, "usage: js [-PswWxC] [-b branchlimit] [-c stackchunksize] [-v version] [-f scriptfile] [-e script] [-S maxstacksize] [scriptfile] [scriptarg...]\n"); return 2; } static uint32 gBranchCount; static uint32 gBranchLimit; static JSBool my_BranchCallback(JSContext *cx, JSScript *script) { if (++gBranchCount == gBranchLimit) { if (script) { if (script->filename) fprintf(gErrFile, "%s:", script->filename); fprintf(gErrFile, "%u: script branch callback (%u callbacks)\n", script->lineno, gBranchLimit); } else { fprintf(gErrFile, "native branch callback (%u callbacks)\n", gBranchLimit); } gBranchCount = 0; return JS_FALSE; } if ((gBranchCount & 0x3fff) == 1) JS_MaybeGC(cx); return JS_TRUE; } extern JSClass global_class; static int ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc) { int i, j, length; JSObject *argsObj; char *filename = NULL; JSBool isInteractive = JS_TRUE; /* * Scan past all optional arguments so we can create the arguments object * before processing any -f options, which must interleave properly with * -v and -w options. This requires two passes, and without getopt, we'll * have to keep the option logic here and in the second for loop in sync. */ for (i = 0; i < argc; i++) { if (argv[i][0] != '-' || argv[i][1] == '\0') { ++i; break; } switch (argv[i][1]) { case 'b': case 'c': case 'f': case 'e': case 'v': case 'S': ++i; break; default:; } } /* * Create arguments early and define it to root it, so it's safe from any * GC calls nested below, and so it is available to -f arguments. */ argsObj = JS_NewArrayObject(cx, 0, NULL); if (!argsObj) return 1; if (!JS_DefineProperty(cx, obj, "arguments", OBJECT_TO_JSVAL(argsObj), NULL, NULL, 0)) { return 1; } length = argc - i; for (j = 0; j < length; j++) { JSString *str = JS_NewStringCopyZ(cx, argv[i++]); if (!str) return 1; if (!JS_DefineElement(cx, argsObj, j, STRING_TO_JSVAL(str), NULL, NULL, JSPROP_ENUMERATE)) { return 1; } } for (i = 0; i < argc; i++) { if (argv[i][0] != '-' || argv[i][1] == '\0') { filename = argv[i++]; isInteractive = JS_FALSE; break; } switch (argv[i][1]) { case 'v': if (++i == argc) { return usage(); } JS_SetVersion(cx, (JSVersion) atoi(argv[i])); break; case 'w': reportWarnings = JS_TRUE; break; case 'W': reportWarnings = JS_FALSE; break; case 's': JS_ToggleOptions(cx, JSOPTION_STRICT); break; case 'x': JS_ToggleOptions(cx, JSOPTION_XML); break; case 'P': if (JS_GET_CLASS(cx, JS_GetPrototype(cx, obj)) != &global_class) { JSObject *gobj; if (!JS_SealObject(cx, obj, JS_TRUE)) return JS_FALSE; gobj = JS_NewObject(cx, &global_class, NULL, NULL); if (!gobj) return JS_FALSE; if (!JS_SetPrototype(cx, gobj, obj)) return JS_FALSE; JS_SetParent(cx, gobj, NULL); JS_SetGlobalObject(cx, gobj); obj = gobj; } break; case 'b': gBranchLimit = atoi(argv[++i]); JS_SetBranchCallback(cx, my_BranchCallback); JS_ToggleOptions(cx, JSOPTION_NATIVE_BRANCH_CALLBACK); break; case 'c': /* set stack chunk size */ gStackChunkSize = atoi(argv[++i]); break; case 'f': if (++i == argc) { return usage(); } Process(cx, obj, argv[i]); /* * XXX: js -f foo.js should interpret foo.js and then * drop into interactive mode, but that breaks the test * harness. Just execute foo.js for now. */ isInteractive = JS_FALSE; break; case 'e': { jsval rval; if (++i == argc) { return usage(); } /* Pass a filename of -e to imitate PERL */ JS_EvaluateScript(cx, obj, argv[i], strlen(argv[i]), "-e", 1, &rval); isInteractive = JS_FALSE; break; } case 'C': compileOnly = JS_TRUE; isInteractive = JS_FALSE; break; case 'S': if (++i == argc) { return usage(); } /* Set maximum stack size. */ gMaxStackSize = atoi(argv[i]); break; default: return usage(); } } if (filename || isInteractive) Process(cx, obj, filename); return gExitCode; } static JSBool Version(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { if (argc > 0 && JSVAL_IS_INT(argv[0])) *rval = INT_TO_JSVAL(JS_SetVersion(cx, (JSVersion) JSVAL_TO_INT(argv[0]))); else *rval = INT_TO_JSVAL(JS_GetVersion(cx)); return JS_TRUE; } static struct { const char *name; uint32 flag; } js_options[] = { {"strict", JSOPTION_STRICT}, {"werror", JSOPTION_WERROR}, {"atline", JSOPTION_ATLINE}, {"xml", JSOPTION_XML}, {0, 0} }; static JSBool Options(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { uint32 optset, flag; uintN i, j, found; JSString *str; const char *opt; char *names; optset = 0; for (i = 0; i < argc; i++) { str = JS_ValueToString(cx, argv[i]); if (!str) return JS_FALSE; opt = JS_GetStringBytes(str); for (j = 0; js_options[j].name; j++) { if (strcmp(js_options[j].name, opt) == 0) { optset |= js_options[j].flag; break; } } } optset = JS_ToggleOptions(cx, optset); names = NULL; found = 0; while (optset != 0) { flag = optset; optset &= optset - 1; flag &= ~optset; for (j = 0; js_options[j].name; j++) { if (js_options[j].flag == flag) { names = JS_sprintf_append(names, "%s%s", names ? "," : "", js_options[j].name); found++; break; } } } if (!found) names = strdup(""); if (!names) { JS_ReportOutOfMemory(cx); return JS_FALSE; } str = JS_NewString(cx, names, strlen(names)); if (!str) { free(names); return JS_FALSE; } *rval = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { uintN i; JSString *str; const char *filename; JSScript *script; JSBool ok; jsval result; uint32 oldopts; for (i = 0; i < argc; i++) { str = JS_ValueToString(cx, argv[i]); if (!str) return JS_FALSE; argv[i] = STRING_TO_JSVAL(str); filename = JS_GetStringBytes(str); errno = 0; oldopts = JS_GetOptions(cx); JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO); script = JS_CompileFile(cx, obj, filename); if (!script) { ok = JS_FALSE; } else { ok = !compileOnly ? JS_ExecuteScript(cx, obj, script, &result) : JS_TRUE; JS_DestroyScript(cx, script); } JS_SetOptions(cx, oldopts); if (!ok) return JS_FALSE; } return JS_TRUE; } /* * function readline() * Provides a hook for scripts to read a line from stdin. */ static JSBool ReadLine(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { #define BUFSIZE 256 FILE *from; char *buf, *tmp; size_t bufsize, buflength, gotlength; JSString *str; from = stdin; buflength = 0; bufsize = BUFSIZE; buf = JS_malloc(cx, bufsize); if (!buf) return JS_FALSE; while ((gotlength = js_fgets(buf + buflength, bufsize - buflength, from)) > 0) { buflength += gotlength; /* Are we done? */ if (buf[buflength - 1] == '\n') { buf[buflength - 1] = '\0'; break; } /* Else, grow our buffer for another pass. */ tmp = JS_realloc(cx, buf, bufsize * 2); if (!tmp) { JS_free(cx, buf); return JS_FALSE; } bufsize *= 2; buf = tmp; } /* Treat the empty string specially. */ if (buflength == 0) { *rval = JS_GetEmptyStringValue(cx); JS_free(cx, buf); return JS_TRUE; } /* Shrink the buffer to the real size. */ tmp = JS_realloc(cx, buf, buflength); if (!tmp) { JS_free(cx, buf); return JS_FALSE; } buf = tmp; /* * Turn buf into a JSString. Note that buflength includes the trailing null * character. */ str = JS_NewString(cx, buf, buflength - 1); if (!str) { JS_free(cx, buf); return JS_FALSE; } *rval = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool Print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { uintN i, n; JSString *str; for (i = n = 0; i < argc; i++) { str = JS_ValueToString(cx, argv[i]); if (!str) return JS_FALSE; fprintf(gOutFile, "%s%s", i ? " " : "", JS_GetStringBytes(str)); } n++; if (n) fputc('\n', gOutFile); return JS_TRUE; } static JSBool Help(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool Quit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { #ifdef LIVECONNECT JSJ_SimpleShutdown(); #endif JS_ConvertArguments(cx, argc, argv,"/ i", &gExitCode); gQuitting = JS_TRUE; return JS_FALSE; } #ifdef GC_MARK_DEBUG extern JS_FRIEND_DATA(FILE *) js_DumpGCHeap; #endif static JSBool GC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSRuntime *rt; uint32 preBytes; rt = cx->runtime; preBytes = rt->gcBytes; #ifdef GC_MARK_DEBUG if (argc && JSVAL_IS_STRING(argv[0])) { char *name = JS_GetStringBytes(JSVAL_TO_STRING(argv[0])); FILE *file = fopen(name, "w"); if (!file) { fprintf(gErrFile, "gc: can't open %s: %s\n", strerror(errno)); return JS_FALSE; } js_DumpGCHeap = file; } else { js_DumpGCHeap = stdout; } #endif JS_GC(cx); #ifdef GC_MARK_DEBUG if (js_DumpGCHeap != stdout) fclose(js_DumpGCHeap); js_DumpGCHeap = NULL; #endif fprintf(gOutFile, "before %lu, after %lu, break %08lx\n", (unsigned long)preBytes, (unsigned long)rt->gcBytes, #ifdef XP_UNIX (unsigned long)sbrk(0) #else 0 #endif ); #ifdef JS_GCMETER js_DumpGCStats(rt, stdout); #endif return JS_TRUE; } static JSScript * ValueToScript(JSContext *cx, jsval v) { JSScript *script; JSFunction *fun; if (!JSVAL_IS_PRIMITIVE(v) && JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_ScriptClass) { script = (JSScript *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); } else { fun = JS_ValueToFunction(cx, v); if (!fun) return NULL; script = FUN_SCRIPT(fun); } return script; } static JSBool GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp, int32 *ip) { jsval v; uintN intarg; JSScript *script; *scriptp = cx->fp->down->script; *ip = 0; if (argc != 0) { v = argv[0]; intarg = 0; if (!JSVAL_IS_PRIMITIVE(v) && (JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_FunctionClass || JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_ScriptClass)) { script = ValueToScript(cx, v); if (!script) return JS_FALSE; *scriptp = script; intarg++; } if (argc > intarg) { if (!JS_ValueToInt32(cx, argv[intarg], ip)) return JS_FALSE; } } return JS_TRUE; } static JSTrapStatus TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure) { JSString *str; JSStackFrame *caller; str = (JSString *) closure; caller = JS_GetScriptedCaller(cx, NULL); if (!JS_EvaluateScript(cx, caller->scopeChain, JS_GetStringBytes(str), JS_GetStringLength(str), caller->script->filename, caller->script->lineno, rval)) { return JSTRAP_ERROR; } if (*rval != JSVAL_VOID) return JSTRAP_RETURN; return JSTRAP_CONTINUE; } static JSBool Trap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSString *str; JSScript *script; int32 i; if (argc == 0) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_TRAP_USAGE); return JS_FALSE; } argc--; str = JS_ValueToString(cx, argv[argc]); if (!str) return JS_FALSE; argv[argc] = STRING_TO_JSVAL(str); if (!GetTrapArgs(cx, argc, argv, &script, &i)) return JS_FALSE; return JS_SetTrap(cx, script, script->code + i, TrapHandler, str); } static JSBool Untrap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSScript *script; int32 i; if (!GetTrapArgs(cx, argc, argv, &script, &i)) return JS_FALSE; JS_ClearTrap(cx, script, script->code + i, NULL, NULL); return JS_TRUE; } static JSBool LineToPC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSScript *script; int32 i; uintN lineno; jsbytecode *pc; if (argc == 0) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_LINE2PC_USAGE); return JS_FALSE; } script = cx->fp->down->script; if (!GetTrapArgs(cx, argc, argv, &script, &i)) return JS_FALSE; lineno = (i == 0) ? script->lineno : (uintN)i; pc = JS_LineNumberToPC(cx, script, lineno); if (!pc) return JS_FALSE; *rval = INT_TO_JSVAL(PTRDIFF(pc, script->code, jsbytecode)); return JS_TRUE; } static JSBool PCToLine(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSScript *script; int32 i; uintN lineno; if (!GetTrapArgs(cx, argc, argv, &script, &i)) return JS_FALSE; lineno = JS_PCToLineNumber(cx, script, script->code + i); if (!lineno) return JS_FALSE; *rval = INT_TO_JSVAL(lineno); return JS_TRUE; } #ifdef DEBUG static void SrcNotes(JSContext *cx, JSScript *script) { uintN offset, delta, caseOff; jssrcnote *notes, *sn; JSSrcNoteType type; jsatomid atomIndex; JSAtom *atom; fprintf(gOutFile, "\nSource notes:\n"); offset = 0; notes = SCRIPT_NOTES(script); for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { delta = SN_DELTA(sn); offset += delta; fprintf(gOutFile, "%3u: %5u [%4u] %-8s", PTRDIFF(sn, notes, jssrcnote), offset, delta, js_SrcNoteSpec[SN_TYPE(sn)].name); type = (JSSrcNoteType) SN_TYPE(sn); switch (type) { case SRC_SETLINE: fprintf(gOutFile, " lineno %u", (uintN) js_GetSrcNoteOffset(sn, 0)); break; case SRC_FOR: fprintf(gOutFile, " cond %u update %u tail %u", (uintN) js_GetSrcNoteOffset(sn, 0), (uintN) js_GetSrcNoteOffset(sn, 1), (uintN) js_GetSrcNoteOffset(sn, 2)); break; case SRC_COND: case SRC_IF_ELSE: case SRC_WHILE: case SRC_PCBASE: case SRC_PCDELTA: fprintf(gOutFile, " offset %u", (uintN) js_GetSrcNoteOffset(sn, 0)); break; case SRC_LABEL: case SRC_LABELBRACE: case SRC_BREAK2LABEL: case SRC_CONT2LABEL: case SRC_FUNCDEF: { const char *bytes; JSFunction *fun; JSString *str; atomIndex = (jsatomid) js_GetSrcNoteOffset(sn, 0); atom = js_GetAtom(cx, &script->atomMap, atomIndex); if (type != SRC_FUNCDEF) { bytes = js_AtomToPrintableString(cx, atom); } else { fun = (JSFunction *) JS_GetPrivate(cx, ATOM_TO_OBJECT(atom)); str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT); bytes = str ? JS_GetStringBytes(str) : "N/A"; } fprintf(gOutFile, " atom %u (%s)", (uintN)atomIndex, bytes); break; } case SRC_SWITCH: fprintf(gOutFile, " length %u", (uintN) js_GetSrcNoteOffset(sn, 0)); caseOff = (uintN) js_GetSrcNoteOffset(sn, 1); if (caseOff) fprintf(gOutFile, " first case offset %u", caseOff); break; case SRC_CATCH: delta = (uintN) js_GetSrcNoteOffset(sn, 0); if (delta) fprintf(gOutFile, " guard size %u", delta); break; default:; } fputc('\n', gOutFile); } } static JSBool Notes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { uintN i; JSScript *script; for (i = 0; i < argc; i++) { script = ValueToScript(cx, argv[i]); if (!script) continue; SrcNotes(cx, script); } return JS_TRUE; } static JSBool TryNotes(JSContext *cx, JSScript *script) { JSTryNote *tn = script->trynotes; if (!tn) return JS_TRUE; fprintf(gOutFile, "\nException table:\nstart\tend\tcatch\n"); while (tn->start && tn->catchStart) { fprintf(gOutFile, " %d\t%d\t%d\n", tn->start, tn->start + tn->length, tn->catchStart); tn++; } return JS_TRUE; } static JSBool Disassemble(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSBool lines; uintN i; JSScript *script; if (argc > 0 && JSVAL_IS_STRING(argv[0]) && !strcmp(JS_GetStringBytes(JSVAL_TO_STRING(argv[0])), "-l")) { lines = JS_TRUE; argv++, argc--; } else { lines = JS_FALSE; } for (i = 0; i < argc; i++) { script = ValueToScript(cx, argv[i]); if (!script) continue; if (JSVAL_IS_FUNCTION(cx, argv[i])) { JSFunction *fun = JS_ValueToFunction(cx, argv[i]); if (fun && (fun->flags & JSFUN_FLAGS_MASK)) { uint8 flags = fun->flags; fputs("flags:", stdout); #define SHOW_FLAG(flag) if (flags & JSFUN_##flag) fputs(" " #flag, stdout); SHOW_FLAG(LAMBDA); SHOW_FLAG(SETTER); SHOW_FLAG(GETTER); SHOW_FLAG(BOUND_METHOD); SHOW_FLAG(HEAVYWEIGHT); #undef SHOW_FLAG putchar('\n'); } } if (!js_Disassemble(cx, script, lines, stdout)) return JS_FALSE; SrcNotes(cx, script); TryNotes(cx, script); } return JS_TRUE; } static JSBool DisassWithSrc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { #define LINE_BUF_LEN 512 uintN i, len, line1, line2, bupline; JSScript *script; FILE *file; char linebuf[LINE_BUF_LEN]; jsbytecode *pc, *end; static char sep[] = ";-------------------------"; for (i = 0; i < argc; i++) { script = ValueToScript(cx, argv[i]); if (!script) continue; if (!script || !script->filename) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_FILE_SCRIPTS_ONLY); return JS_FALSE; } file = fopen(script->filename, "r"); if (!file) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_CANT_OPEN, script->filename, strerror(errno)); return JS_FALSE; } pc = script->code; end = pc + script->length; /* burn the leading lines */ line2 = JS_PCToLineNumber(cx, script, pc); for (line1 = 0; line1 < line2 - 1; line1++) fgets(linebuf, LINE_BUF_LEN, file); bupline = 0; while (pc < end) { line2 = JS_PCToLineNumber(cx, script, pc); if (line2 < line1) { if (bupline != line2) { bupline = line2; fprintf(gOutFile, "%s %3u: BACKUP\n", sep, line2); } } else { if (bupline && line1 == line2) fprintf(gOutFile, "%s %3u: RESTORE\n", sep, line2); bupline = 0; while (line1 < line2) { if (!fgets(linebuf, LINE_BUF_LEN, file)) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_UNEXPECTED_EOF, script->filename); goto bail; } line1++; fprintf(gOutFile, "%s %3u: %s", sep, line1, linebuf); } } len = js_Disassemble1(cx, script, pc, PTRDIFF(pc, script->code, jsbytecode), JS_TRUE, stdout); if (!len) return JS_FALSE; pc += len; } bail: fclose(file); } return JS_TRUE; #undef LINE_BUF_LEN } static JSBool Tracing(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSBool bval; JSString *str; if (argc == 0) { *rval = BOOLEAN_TO_JSVAL(cx->tracefp != 0); return JS_TRUE; } switch (JS_TypeOfValue(cx, argv[0])) { case JSTYPE_NUMBER: bval = JSVAL_IS_INT(argv[0]) ? JSVAL_TO_INT(argv[0]) : (jsint) *JSVAL_TO_DOUBLE(argv[0]); break; case JSTYPE_BOOLEAN: bval = JSVAL_TO_BOOLEAN(argv[0]); break; default: str = JS_ValueToString(cx, argv[0]); if (!str) return JS_FALSE; fprintf(gErrFile, "tracing: illegal argument %s\n", JS_GetStringBytes(str)); return JS_TRUE; } cx->tracefp = bval ? stderr : NULL; return JS_TRUE; } typedef struct DumpAtomArgs { JSContext *cx; FILE *fp; } DumpAtomArgs; static int DumpAtom(JSHashEntry *he, int i, void *arg) { DumpAtomArgs *args = (DumpAtomArgs *)arg; FILE *fp = args->fp; JSAtom *atom = (JSAtom *)he; fprintf(fp, "%3d %08x %5lu ", i, (uintN)he->keyHash, (unsigned long)atom->number); if (ATOM_IS_STRING(atom)) fprintf(fp, "\"%s\"\n", js_AtomToPrintableString(args->cx, atom)); else if (ATOM_IS_INT(atom)) fprintf(fp, "%ld\n", (long)ATOM_TO_INT(atom)); else fprintf(fp, "%.16g\n", *ATOM_TO_DOUBLE(atom)); return HT_ENUMERATE_NEXT; } static void DumpScope(JSContext *cx, JSObject *obj, FILE *fp) { uintN i; JSScope *scope; JSScopeProperty *sprop; i = 0; scope = OBJ_SCOPE(obj); for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) { if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop)) continue; #ifdef OSSP fprintf(fp, "%3u %lx", i, (unsigned long)sprop); #else fprintf(fp, "%3u %p", i, sprop); #endif if (JSID_IS_INT(sprop->id)) { fprintf(fp, " [%ld]", (long)JSVAL_TO_INT(sprop->id)); } else if (JSID_IS_ATOM(sprop->id)) { JSAtom *atom = JSID_TO_ATOM(sprop->id); fprintf(fp, " \"%s\"", js_AtomToPrintableString(cx, atom)); } else { jsval v = OBJECT_TO_JSVAL(JSID_TO_OBJECT(sprop->id)); fprintf(fp, " \"%s\"", js_ValueToPrintableString(cx, v)); } #define DUMP_ATTR(name) if (sprop->attrs & JSPROP_##name) fputs(" " #name, fp) DUMP_ATTR(ENUMERATE); DUMP_ATTR(READONLY); DUMP_ATTR(PERMANENT); DUMP_ATTR(EXPORTED); DUMP_ATTR(GETTER); DUMP_ATTR(SETTER); #undef DUMP_ATTR fprintf(fp, " slot %lu flags %x shortid %d\n", #ifdef OSSP (unsigned long)sprop->slot, sprop->flags, sprop->shortid); #else sprop->slot, sprop->flags, sprop->shortid); #endif } } static JSBool DumpStats(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { uintN i; JSString *str; const char *bytes; JSAtom *atom; JSObject *obj2; JSProperty *prop; jsval value; for (i = 0; i < argc; i++) { str = JS_ValueToString(cx, argv[i]); if (!str) return JS_FALSE; bytes = JS_GetStringBytes(str); if (strcmp(bytes, "arena") == 0) { #ifdef JS_ARENAMETER JS_DumpArenaStats(stdout); #endif } else if (strcmp(bytes, "atom") == 0) { DumpAtomArgs args; fprintf(gOutFile, "\natom table contents:\n"); args.cx = cx; args.fp = stdout; JS_HashTableEnumerateEntries(cx->runtime->atomState.table, DumpAtom, &args); #ifdef HASHMETER JS_HashTableDumpMeter(cx->runtime->atomState.table, DumpAtom, stdout); #endif } else if (strcmp(bytes, "global") == 0) { DumpScope(cx, cx->globalObject, stdout); } else { atom = js_Atomize(cx, bytes, JS_GetStringLength(str), 0); if (!atom) return JS_FALSE; if (!js_FindProperty(cx, ATOM_TO_JSID(atom), &obj, &obj2, &prop)) return JS_FALSE; if (prop) { OBJ_DROP_PROPERTY(cx, obj2, prop); if (!OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &value)) return JS_FALSE; } if (!prop || !JSVAL_IS_OBJECT(value)) { fprintf(gErrFile, "js: invalid stats argument %s\n", bytes); continue; } obj = JSVAL_TO_OBJECT(value); if (obj) DumpScope(cx, obj, stdout); } } return JS_TRUE; } #endif /* DEBUG */ #ifdef TEST_EXPORT static JSBool DoExport(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSAtom *atom; JSObject *obj2; JSProperty *prop; JSBool ok; uintN attrs; if (argc != 2) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_DOEXP_USAGE); return JS_FALSE; } if (!JS_ValueToObject(cx, argv[0], &obj)) return JS_FALSE; argv[0] = OBJECT_TO_JSVAL(obj); atom = js_ValueToStringAtom(cx, argv[1]); if (!atom) return JS_FALSE; if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop)) return JS_FALSE; if (!prop) { ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, NULL, NULL, JSPROP_EXPORTED, NULL); } else { ok = OBJ_GET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, &attrs); if (ok) { attrs |= JSPROP_EXPORTED; ok = OBJ_SET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, &attrs); } OBJ_DROP_PROPERTY(cx, obj2, prop); } return ok; } #endif #ifdef TEST_CVTARGS #include static const char * EscapeWideString(jschar *w) { static char enuf[80]; static char hex[] = "0123456789abcdef"; jschar u; unsigned char b, c; int i, j; if (!w) return ""; for (i = j = 0; i < sizeof enuf - 1; i++, j++) { u = w[j]; if (u == 0) break; b = (unsigned char)(u >> 8); c = (unsigned char)(u); if (b) { if (i >= sizeof enuf - 6) break; enuf[i++] = '\\'; enuf[i++] = 'u'; enuf[i++] = hex[b >> 4]; enuf[i++] = hex[b & 15]; enuf[i++] = hex[c >> 4]; enuf[i] = hex[c & 15]; } else if (!isprint(c)) { if (i >= sizeof enuf - 4) break; enuf[i++] = '\\'; enuf[i++] = 'x'; enuf[i++] = hex[c >> 4]; enuf[i] = hex[c & 15]; } else { enuf[i] = (char)c; } } enuf[i] = 0; return enuf; } #include static JSBool ZZ_formatter(JSContext *cx, const char *format, JSBool fromJS, jsval **vpp, va_list *app) { jsval *vp; va_list ap; jsdouble re, im; printf("entering ZZ_formatter"); vp = *vpp; ap = *app; if (fromJS) { if (!JS_ValueToNumber(cx, vp[0], &re)) return JS_FALSE; if (!JS_ValueToNumber(cx, vp[1], &im)) return JS_FALSE; *va_arg(ap, jsdouble *) = re; *va_arg(ap, jsdouble *) = im; } else { re = va_arg(ap, jsdouble); im = va_arg(ap, jsdouble); if (!JS_NewNumberValue(cx, re, &vp[0])) return JS_FALSE; if (!JS_NewNumberValue(cx, im, &vp[1])) return JS_FALSE; } *vpp = vp + 2; *app = ap; printf("leaving ZZ_formatter"); return JS_TRUE; } static JSBool ConvertArgs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSBool b = JS_FALSE; jschar c = 0; int32 i = 0, j = 0; uint32 u = 0; jsdouble d = 0, I = 0, re = 0, im = 0; char *s = NULL; JSString *str = NULL; jschar *w = NULL; JSObject *obj2 = NULL; JSFunction *fun = NULL; jsval v = JSVAL_VOID; JSBool ok; if (!JS_AddArgumentFormatter(cx, "ZZ", ZZ_formatter)) return JS_FALSE;; ok = JS_ConvertArguments(cx, argc, argv, "b/ciujdIsSWofvZZ*", &b, &c, &i, &u, &j, &d, &I, &s, &str, &w, &obj2, &fun, &v, &re, &im); JS_RemoveArgumentFormatter(cx, "ZZ"); if (!ok) return JS_FALSE; fprintf(gOutFile, "b %u, c %x (%c), i %ld, u %lu, j %ld\n", b, c, (char)c, i, u, j); fprintf(gOutFile, "d %g, I %g, s %s, S %s, W %s, obj %s, fun %s\n" "v %s, re %g, im %g\n", d, I, s, str ? JS_GetStringBytes(str) : "", EscapeWideString(w), JS_GetStringBytes(JS_ValueToString(cx, OBJECT_TO_JSVAL(obj2))), fun ? JS_GetStringBytes(JS_DecompileFunction(cx, fun, 4)) : "", JS_GetStringBytes(JS_ValueToString(cx, v)), re, im); return JS_TRUE; } #endif static JSBool BuildDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { fprintf(gOutFile, "built on %s at %s\n", __DATE__, __TIME__); return JS_TRUE; } static JSBool Clear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { if (argc != 0 && !JS_ValueToObject(cx, argv[0], &obj)) return JS_FALSE; JS_ClearScope(cx, obj); return JS_TRUE; } static JSBool Intern(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSString *str; str = JS_ValueToString(cx, argv[0]); if (!str) return JS_FALSE; if (!JS_InternUCStringN(cx, JS_GetStringChars(str), JS_GetStringLength(str))) { return JS_FALSE; } return JS_TRUE; } static JSBool Clone(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSFunction *fun; JSObject *funobj, *parent, *clone; fun = JS_ValueToFunction(cx, argv[0]); if (!fun) return JS_FALSE; funobj = JS_GetFunctionObject(fun); if (argc > 1) { if (!JS_ValueToObject(cx, argv[1], &parent)) return JS_FALSE; } else { parent = JS_GetParent(cx, funobj); } clone = JS_CloneFunctionObject(cx, funobj, parent); if (!clone) return JS_FALSE; *rval = OBJECT_TO_JSVAL(clone); return JS_TRUE; } static JSBool Seal(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSObject *target; JSBool deep = JS_FALSE; if (!JS_ConvertArguments(cx, argc, argv, "o/b", &target, &deep)) return JS_FALSE; if (!target) return JS_TRUE; return JS_SealObject(cx, target, deep); } static JSBool GetPDA(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSObject *vobj, *aobj, *pdobj; JSBool ok; JSPropertyDescArray pda; JSPropertyDesc *pd; uint32 i; jsval v; if (!JS_ValueToObject(cx, argv[0], &vobj)) return JS_FALSE; if (!vobj) return JS_TRUE; aobj = JS_NewArrayObject(cx, 0, NULL); if (!aobj) return JS_FALSE; *rval = OBJECT_TO_JSVAL(aobj); ok = JS_GetPropertyDescArray(cx, vobj, &pda); if (!ok) return JS_FALSE; pd = pda.array; for (i = 0; i < pda.length; i++) { pdobj = JS_NewObject(cx, NULL, NULL, NULL); if (!pdobj) { ok = JS_FALSE; break; } ok = JS_SetProperty(cx, pdobj, "id", &pd->id) && JS_SetProperty(cx, pdobj, "value", &pd->value) && (v = INT_TO_JSVAL(pd->flags), JS_SetProperty(cx, pdobj, "flags", &v)) && (v = INT_TO_JSVAL(pd->slot), JS_SetProperty(cx, pdobj, "slot", &v)) && JS_SetProperty(cx, pdobj, "alias", &pd->alias); if (!ok) break; v = OBJECT_TO_JSVAL(pdobj); ok = JS_SetElement(cx, aobj, i, &v); if (!ok) break; } JS_PutPropertyDescArray(cx, &pda); return ok; } static JSBool GetSLX(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSScript *script; script = ValueToScript(cx, argv[0]); if (!script) return JS_FALSE; *rval = INT_TO_JSVAL(js_GetScriptLineExtent(script)); return JS_TRUE; } static JSBool ToInt32(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { int32 i; if (!JS_ValueToInt32(cx, argv[0], &i)) return JS_FALSE; return JS_NewNumberValue(cx, i, rval); } static JSBool StringsAreUtf8(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { *rval = JS_CStringsAreUTF8() ? JSVAL_TRUE : JSVAL_FALSE; return JS_TRUE; } static const char* badUtf8 = "...\xC0..."; static const char* bigUtf8 = "...\xFB\xBF\xBF\xBF\xBF..."; static const jschar badSurrogate[] = { 'A', 'B', 'C', 0xDEEE, 'D', 'E', 0 }; static JSBool TestUtf8(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { intN mode = 1; jschar chars[20]; size_t charsLength = 5; char bytes[20]; size_t bytesLength = 20; if (argc && !JS_ValueToInt32(cx, *argv, &mode)) return JS_FALSE; /* The following throw errors if compiled with UTF-8. */ switch (mode) { /* mode 1: malformed UTF-8 string. */ case 1: JS_NewStringCopyZ(cx, badUtf8); break; /* mode 2: big UTF-8 character. */ case 2: JS_NewStringCopyZ(cx, bigUtf8); break; /* mode 3: bad surrogate character. */ case 3: JS_EncodeCharacters(cx, badSurrogate, 6, bytes, &bytesLength); break; /* mode 4: use a too small buffer. */ case 4: JS_DecodeBytes(cx, "1234567890", 10, chars, &charsLength); break; default: JS_ReportError(cx, "invalid mode parameter"); return JS_FALSE; } return !JS_IsExceptionPending (cx); } static JSFunctionSpec shell_functions[] = { {"version", Version, 0}, {"options", Options, 0}, {"load", Load, 1}, {"readline", ReadLine, 0}, {"print", Print, 0}, {"help", Help, 0}, {"quit", Quit, 0}, {"gc", GC, 0}, {"trap", Trap, 3}, {"untrap", Untrap, 2}, {"line2pc", LineToPC, 0}, {"pc2line", PCToLine, 0}, {"stringsAreUtf8", StringsAreUtf8, 0}, {"testUtf8", TestUtf8, 1}, #ifdef DEBUG {"dis", Disassemble, 1}, {"dissrc", DisassWithSrc, 1}, {"notes", Notes, 1}, {"tracing", Tracing, 0}, {"stats", DumpStats, 1}, #endif #ifdef TEST_EXPORT {"xport", DoExport, 2}, #endif #ifdef TEST_CVTARGS {"cvtargs", ConvertArgs, 0, 0, 12}, #endif {"build", BuildDate, 0}, {"clear", Clear, 0}, {"intern", Intern, 1}, {"clone", Clone, 1}, {"seal", Seal, 1, 0, 1}, {"getpda", GetPDA, 1}, {"getslx", GetSLX, 1}, {"toint32", ToInt32, 1}, {0} }; /* NOTE: These must be kept in sync with the above. */ static char *shell_help_messages[] = { "version([number]) Get or set JavaScript version number", "options([option ...]) Get or toggle JavaScript options", "load(['foo.js' ...]) Load files named by string arguments", "readline() Read a single line from stdin", "print([exp ...]) Evaluate and print expressions", "help([name ...]) Display usage and help messages", "quit() Quit the shell", "gc() Run the garbage collector", "trap([fun, [pc,]] exp) Trap bytecode execution", "untrap(fun[, pc]) Remove a trap", "line2pc([fun,] line) Map line number to PC", "pc2line(fun[, pc]) Map PC to line number", "stringsAreUTF8() Check if strings are UTF-8 encoded", "testUTF8(mode) Perform UTF-8 tests (modes are 1 to 4)", #ifdef DEBUG "dis([fun]) Disassemble functions into bytecodes", "dissrc([fun]) Disassemble functions with source lines", "notes([fun]) Show source notes for functions", "tracing([toggle]) Turn tracing on or off", "stats([string ...]) Dump 'arena', 'atom', 'global' stats", #endif #ifdef TEST_EXPORT "xport(obj, id) Export identified property from object", #endif #ifdef TEST_CVTARGS "cvtargs(b, c, ...) Test JS_ConvertArguments", #endif "build() Show build date and time", "clear([obj]) Clear properties of object", "intern(str) Internalize str in the atom table", "clone(fun[, scope]) Clone function object", "seal(obj[, deep]) Seal object, or object graph if deep", "getpda(obj) Get the property descriptors for obj", "getslx(obj) Get script line extent", "toint32(n) Testing hook for JS_ValueToInt32", 0 }; static void ShowHelpHeader(void) { fprintf(gOutFile, "%-14s %-22s %s\n", "Command", "Usage", "Description"); fprintf(gOutFile, "%-14s %-22s %s\n", "=======", "=====", "==========="); } static void ShowHelpForCommand(uintN n) { fprintf(gOutFile, "%-14.14s %s\n", shell_functions[n].name, shell_help_messages[n]); } static JSBool Help(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { uintN i, j; int did_header, did_something; JSType type; JSFunction *fun; JSString *str; const char *bytes; fprintf(gOutFile, "%s\n", JS_GetImplementationVersion()); if (argc == 0) { ShowHelpHeader(); for (i = 0; shell_functions[i].name; i++) ShowHelpForCommand(i); } else { did_header = 0; for (i = 0; i < argc; i++) { did_something = 0; type = JS_TypeOfValue(cx, argv[i]); if (type == JSTYPE_FUNCTION) { fun = JS_ValueToFunction(cx, argv[i]); str = fun->atom ? ATOM_TO_STRING(fun->atom) : NULL; } else if (type == JSTYPE_STRING) { str = JSVAL_TO_STRING(argv[i]); } else { str = NULL; } if (str) { bytes = JS_GetStringBytes(str); for (j = 0; shell_functions[j].name; j++) { if (!strcmp(bytes, shell_functions[j].name)) { if (!did_header) { did_header = 1; ShowHelpHeader(); } did_something = 1; ShowHelpForCommand(j); break; } } } if (!did_something) { str = JS_ValueToString(cx, argv[i]); if (!str) return JS_FALSE; fprintf(gErrFile, "Sorry, no help for %s\n", JS_GetStringBytes(str)); } } } return JS_TRUE; } /* * Define a JS object called "it". Give it class operations that printf why * they're being called for tutorial purposes. */ enum its_tinyid { ITS_COLOR, ITS_HEIGHT, ITS_WIDTH, ITS_FUNNY, ITS_ARRAY, ITS_RDONLY }; static JSPropertySpec its_props[] = { {"color", ITS_COLOR, JSPROP_ENUMERATE}, {"height", ITS_HEIGHT, JSPROP_ENUMERATE}, {"width", ITS_WIDTH, JSPROP_ENUMERATE}, {"funny", ITS_FUNNY, JSPROP_ENUMERATE}, {"array", ITS_ARRAY, JSPROP_ENUMERATE}, {"rdonly", ITS_RDONLY, JSPROP_READONLY}, {0} }; static JSBool its_item(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { *rval = OBJECT_TO_JSVAL(obj); if (argc != 0) JS_SetCallReturnValue2(cx, argv[0]); return JS_TRUE; } static JSBool its_bindMethod(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { char *name; JSObject *method; if (!JS_ConvertArguments(cx, argc, argv, "so", &name, &method)) return JS_FALSE; *rval = OBJECT_TO_JSVAL(method); if (JS_TypeOfValue(cx, *rval) != JSTYPE_FUNCTION) { JSString *valstr = JS_ValueToString(cx, *rval); if (valstr) { JS_ReportError(cx, "can't bind method %s to non-callable object %s", name, JS_GetStringBytes(valstr)); } return JS_FALSE; } if (!JS_DefineProperty(cx, obj, name, *rval, NULL, NULL, JSPROP_ENUMERATE)) return JS_FALSE; return JS_SetParent(cx, method, obj); } static JSFunctionSpec its_methods[] = { {"item", its_item, 0}, {"bindMethod", its_bindMethod, 2}, {0} }; #ifdef JSD_LOWLEVEL_SOURCE /* * This facilitates sending source to JSD (the debugger system) in the shell * where the source is loaded using the JSFILE hack in jsscan. The function * below is used as a callback for the jsdbgapi JS_SetSourceHandler hook. * A more normal embedding (e.g. mozilla) loads source itself and can send * source directly to JSD without using this hook scheme. */ static void SendSourceToJSDebugger(const char *filename, uintN lineno, jschar *str, size_t length, void **listenerTSData, JSDContext* jsdc) { JSDSourceText *jsdsrc = (JSDSourceText *) *listenerTSData; if (!jsdsrc) { if (!filename) filename = "typein"; if (1 == lineno) { jsdsrc = JSD_NewSourceText(jsdc, filename); } else { jsdsrc = JSD_FindSourceForURL(jsdc, filename); if (jsdsrc && JSD_SOURCE_PARTIAL != JSD_GetSourceStatus(jsdc, jsdsrc)) { jsdsrc = NULL; } } } if (jsdsrc) { jsdsrc = JSD_AppendUCSourceText(jsdc,jsdsrc, str, length, JSD_SOURCE_PARTIAL); } *listenerTSData = jsdsrc; } #endif /* JSD_LOWLEVEL_SOURCE */ static JSBool its_noisy; /* whether to be noisy when finalizing it */ static JSBool its_addProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { if (its_noisy) { fprintf(gOutFile, "adding its property %s,", JS_GetStringBytes(JS_ValueToString(cx, id))); fprintf(gOutFile, " initial value %s\n", JS_GetStringBytes(JS_ValueToString(cx, *vp))); } return JS_TRUE; } static JSBool its_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { if (its_noisy) { fprintf(gOutFile, "deleting its property %s,", JS_GetStringBytes(JS_ValueToString(cx, id))); fprintf(gOutFile, " current value %s\n", JS_GetStringBytes(JS_ValueToString(cx, *vp))); } return JS_TRUE; } static JSBool its_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { if (its_noisy) { fprintf(gOutFile, "getting its property %s,", JS_GetStringBytes(JS_ValueToString(cx, id))); fprintf(gOutFile, " current value %s\n", JS_GetStringBytes(JS_ValueToString(cx, *vp))); } return JS_TRUE; } static JSBool its_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { if (its_noisy) { fprintf(gOutFile, "setting its property %s,", JS_GetStringBytes(JS_ValueToString(cx, id))); fprintf(gOutFile, " new value %s\n", JS_GetStringBytes(JS_ValueToString(cx, *vp))); } if (JSVAL_IS_STRING(id) && !strcmp(JS_GetStringBytes(JSVAL_TO_STRING(id)), "noisy")) { return JS_ValueToBoolean(cx, *vp, &its_noisy); } return JS_TRUE; } static JSBool its_enumerate(JSContext *cx, JSObject *obj) { if (its_noisy) fprintf(gOutFile, "enumerate its properties\n"); return JS_TRUE; } static JSBool its_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp) { if (its_noisy) { fprintf(gOutFile, "resolving its property %s, flags {%s,%s,%s}\n", JS_GetStringBytes(JS_ValueToString(cx, id)), (flags & JSRESOLVE_QUALIFIED) ? "qualified" : "", (flags & JSRESOLVE_ASSIGNING) ? "assigning" : "", (flags & JSRESOLVE_DETECTING) ? "detecting" : ""); } return JS_TRUE; } static JSBool its_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) { if (its_noisy) fprintf(gOutFile, "converting it to %s type\n", JS_GetTypeName(cx, type)); return JS_TRUE; } static void its_finalize(JSContext *cx, JSObject *obj) { if (its_noisy) fprintf(gOutFile, "finalizing it\n"); } static JSClass its_class = { "It", JSCLASS_NEW_RESOLVE, its_addProperty, its_delProperty, its_getProperty, its_setProperty, its_enumerate, (JSResolveOp)its_resolve, its_convert, its_finalize }; JSErrorFormatString jsShell_ErrorFormatString[JSErr_Limit] = { #if JS_HAS_DFLT_MSG_STRINGS #define MSG_DEF(name, number, count, exception, format) \ { format, count } , #else #define MSG_DEF(name, number, count, exception, format) \ { NULL, count } , #endif #include "jsshell.msg" #undef MSG_DEF }; static const JSErrorFormatString * my_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber) { if ((errorNumber > 0) && (errorNumber < JSShellErr_Limit)) return &jsShell_ErrorFormatString[errorNumber]; return NULL; } static void my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) { int i, j, k, n; char *prefix, *tmp; const char *ctmp; if (!report) { fprintf(gErrFile, "%s\n", message); return; } /* Conditionally ignore reported warnings. */ if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings) return; prefix = NULL; if (report->filename) prefix = JS_smprintf("%s:", report->filename); if (report->lineno) { tmp = prefix; prefix = JS_smprintf("%s%u: ", tmp ? tmp : "", report->lineno); JS_free(cx, tmp); } if (JSREPORT_IS_WARNING(report->flags)) { tmp = prefix; prefix = JS_smprintf("%s%swarning: ", tmp ? tmp : "", JSREPORT_IS_STRICT(report->flags) ? "strict " : ""); JS_free(cx, tmp); } /* embedded newlines -- argh! */ while ((ctmp = strchr(message, '\n')) != 0) { ctmp++; if (prefix) fputs(prefix, gErrFile); fwrite(message, 1, ctmp - message, gErrFile); message = ctmp; } /* If there were no filename or lineno, the prefix might be empty */ if (prefix) fputs(prefix, gErrFile); fputs(message, gErrFile); if (!report->linebuf) { fputc('\n', gErrFile); goto out; } /* report->linebuf usually ends with a newline. */ n = strlen(report->linebuf); fprintf(gErrFile, ":\n%s%s%s%s", prefix, report->linebuf, (n > 0 && report->linebuf[n-1] == '\n') ? "" : "\n", prefix); n = PTRDIFF(report->tokenptr, report->linebuf, char); for (i = j = 0; i < n; i++) { if (report->linebuf[i] == '\t') { for (k = (j + 8) & ~7; j < k; j++) { fputc('.', gErrFile); } continue; } fputc('.', gErrFile); j++; } fputs("^\n", gErrFile); out: if (!JSREPORT_IS_WARNING(report->flags)) gExitCode = EXITCODE_RUNTIME_ERROR; JS_free(cx, prefix); } #if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX) static JSBool Exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSFunction *fun; const char *name, **nargv; uintN i, nargc; JSString *str; pid_t pid; int status; fun = JS_ValueToFunction(cx, argv[-2]); if (!fun) return JS_FALSE; if (!fun->atom) return JS_TRUE; name = JS_GetStringBytes(ATOM_TO_STRING(fun->atom)); nargc = 1 + argc; nargv = JS_malloc(cx, (nargc + 1) * sizeof(char *)); if (!nargv) return JS_FALSE; nargv[0] = name; for (i = 1; i < nargc; i++) { str = JS_ValueToString(cx, argv[i-1]); if (!str) { JS_free(cx, nargv); return JS_FALSE; } nargv[i] = JS_GetStringBytes(str); } nargv[nargc] = 0; pid = fork(); switch (pid) { case -1: perror("js"); break; case 0: (void) execvp(name, (char **)nargv); perror("js"); exit(127); default: while (waitpid(pid, &status, 0) < 0 && errno == EINTR) continue; break; } JS_free(cx, nargv); return JS_TRUE; } #endif #define LAZY_STANDARD_CLASSES static JSBool global_enumerate(JSContext *cx, JSObject *obj) { #ifdef LAZY_STANDARD_CLASSES return JS_EnumerateStandardClasses(cx, obj); #else return JS_TRUE; #endif } static JSBool global_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp) { #ifdef LAZY_STANDARD_CLASSES if ((flags & JSRESOLVE_ASSIGNING) == 0) { JSBool resolved; if (!JS_ResolveStandardClass(cx, obj, id, &resolved)) return JS_FALSE; if (resolved) { *objp = obj; return JS_TRUE; } } #endif #if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX) if ((flags & (JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING)) == 0) { /* * Do this expensive hack only for unoptimized Unix builds, which are * not used for benchmarking. */ char *path, *comp, *full; const char *name; JSBool ok, found; JSFunction *fun; if (!JSVAL_IS_STRING(id)) return JS_TRUE; path = getenv("PATH"); if (!path) return JS_TRUE; path = JS_strdup(cx, path); if (!path) return JS_FALSE; name = JS_GetStringBytes(JSVAL_TO_STRING(id)); ok = JS_TRUE; for (comp = strtok(path, ":"); comp; comp = strtok(NULL, ":")) { if (*comp != '\0') { full = JS_smprintf("%s/%s", comp, name); if (!full) { JS_ReportOutOfMemory(cx); ok = JS_FALSE; break; } } else { full = (char *)name; } found = (access(full, X_OK) == 0); if (*comp != '\0') free(full); if (found) { fun = JS_DefineFunction(cx, obj, name, Exec, 0, JSPROP_ENUMERATE); ok = (fun != NULL); if (ok) *objp = obj; break; } } JS_free(cx, path); return ok; } #else return JS_TRUE; #endif } JSClass global_class = { "global", JSCLASS_NEW_RESOLVE, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, global_enumerate, (JSResolveOp) global_resolve, JS_ConvertStub, JS_FinalizeStub }; static JSBool env_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { /* XXX porting may be easy, but these don't seem to supply setenv by default */ #if !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS JSString *idstr, *valstr; const char *name, *value; int rv; idstr = JS_ValueToString(cx, id); valstr = JS_ValueToString(cx, *vp); if (!idstr || !valstr) return JS_FALSE; name = JS_GetStringBytes(idstr); value = JS_GetStringBytes(valstr); #if defined XP_WIN || defined HPUX || defined OSF1 || defined IRIX { char *waste = JS_smprintf("%s=%s", name, value); if (!waste) { JS_ReportOutOfMemory(cx); return JS_FALSE; } rv = putenv(waste); #ifdef XP_WIN /* * HPUX9 at least still has the bad old non-copying putenv. * * Per mail from , OSF1 also has a putenv * that will crash if you pass it an auto char array (so it must place * its argument directly in the char *environ[] array). */ free(waste); #endif } #else rv = setenv(name, value, 1); #endif if (rv < 0) { JS_ReportError(cx, "can't set envariable %s to %s", name, value); return JS_FALSE; } *vp = STRING_TO_JSVAL(valstr); #endif /* !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS */ return JS_TRUE; } static JSBool env_enumerate(JSContext *cx, JSObject *obj) { static JSBool reflected; char **evp, *name, *value; JSString *valstr; JSBool ok; if (reflected) return JS_TRUE; for (evp = (char **)JS_GetPrivate(cx, obj); (name = *evp) != NULL; evp++) { value = strchr(name, '='); if (!value) continue; *value++ = '\0'; valstr = JS_NewStringCopyZ(cx, value); if (!valstr) { ok = JS_FALSE; } else { ok = JS_DefineProperty(cx, obj, name, STRING_TO_JSVAL(valstr), NULL, NULL, JSPROP_ENUMERATE); } value[-1] = '='; if (!ok) return JS_FALSE; } reflected = JS_TRUE; return JS_TRUE; } static JSBool env_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp) { JSString *idstr, *valstr; const char *name, *value; if (flags & JSRESOLVE_ASSIGNING) return JS_TRUE; idstr = JS_ValueToString(cx, id); if (!idstr) return JS_FALSE; name = JS_GetStringBytes(idstr); value = getenv(name); if (value) { valstr = JS_NewStringCopyZ(cx, value); if (!valstr) return JS_FALSE; if (!JS_DefineProperty(cx, obj, name, STRING_TO_JSVAL(valstr), NULL, NULL, JSPROP_ENUMERATE)) { return JS_FALSE; } *objp = obj; } return JS_TRUE; } static JSClass env_class = { "environment", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, env_setProperty, env_enumerate, (JSResolveOp) env_resolve, JS_ConvertStub, JS_FinalizeStub }; #ifdef NARCISSUS static JSBool defineProperty(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSString *str; jsval value; JSBool dontDelete, readOnly, dontEnum; const jschar *chars; size_t length; uintN attrs; dontDelete = readOnly = dontEnum = JS_FALSE; if (!JS_ConvertArguments(cx, argc, argv, "Sv/bbb", &str, &value, &dontDelete, &readOnly, &dontEnum)) { return JS_FALSE; } chars = JS_GetStringChars(str); length = JS_GetStringLength(str); attrs = dontEnum ? 0 : JSPROP_ENUMERATE; if (dontDelete) attrs |= JSPROP_PERMANENT; if (readOnly) attrs |= JSPROP_READONLY; return JS_DefineUCProperty(cx, obj, chars, length, value, NULL, NULL, attrs); } static JSBool Evaluate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { /* function evaluate(source, filename, lineno) { ... } */ JSString *source; const char *filename = ""; jsuint lineno = 0; uint32 oldopts; JSBool ok; if (argc == 0) { *rval = JSVAL_VOID; return JS_TRUE; } if (!JS_ConvertArguments(cx, argc, argv, "S/su", &source, &filename, &lineno)) { return JS_FALSE; } oldopts = JS_GetOptions(cx); JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO); ok = JS_EvaluateUCScript(cx, obj, JS_GetStringChars(source), JS_GetStringLength(source), filename, lineno, rval); JS_SetOptions(cx, oldopts); return ok; } #include #include /* * Returns a JS_malloc'd string (that the caller needs to JS_free) * containing the directory (non-leaf) part of |from| prepended to |leaf|. * If |from| is empty or a leaf, MakeAbsolutePathname returns a copy of leaf. * Returns NULL to indicate an error. */ static char * MakeAbsolutePathname(JSContext *cx, const char *from, const char *leaf) { size_t dirlen; char *dir; const char *slash = NULL, *cp; cp = from; while (*cp) { if (*cp == '/' #ifdef XP_WIN || *cp == '\\' #endif ) { slash = cp; } ++cp; } if (!slash) { /* We were given a leaf or |from| was empty. */ return JS_strdup(cx, leaf); } /* Else, we were given a real pathname, return that + the leaf. */ dirlen = slash - from + 1; dir = JS_malloc(cx, dirlen + strlen(leaf) + 1); if (!dir) return NULL; strncpy(dir, from, dirlen); strcpy(dir + dirlen, leaf); /* Note: we can't use strcat here. */ return dir; } static JSBool snarf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSString *str; const char *filename; char *pathname; JSStackFrame *fp; int fd, cc; JSBool ok; size_t len; char *buf; struct stat sb; str = JS_ValueToString(cx, argv[0]); if (!str) return JS_FALSE; filename = JS_GetStringBytes(str); /* Get the currently executing script's name. */ fp = JS_GetScriptedCaller(cx, NULL); JS_ASSERT(fp && fp->script->filename); pathname = MakeAbsolutePathname(cx, fp->script->filename, filename); if (!pathname) return JS_FALSE; fd = open(pathname, O_RDONLY); ok = JS_TRUE; len = 0; buf = NULL; if (fd < 0) { JS_ReportError(cx, "can't open %s: %s", pathname, strerror(errno)); ok = JS_FALSE; } else if (fstat(fd, &sb) < 0) { JS_ReportError(cx, "can't stat %s", pathname); ok = JS_FALSE; } else { len = sb.st_size; buf = JS_malloc(cx, len + 1); if (!buf) { ok = JS_FALSE; } else if ((cc = read(fd, buf, len)) != len) { JS_free(cx, buf); JS_ReportError(cx, "can't read %s: %s", pathname, (cc < 0) ? strerror(errno) : "short read"); ok = JS_FALSE; } } close(fd); JS_free(cx, pathname); if (!ok) return ok; buf[len] = '\0'; str = JS_NewString(cx, buf, len); if (!str) { JS_free(cx, buf); return JS_FALSE; } *rval = STRING_TO_JSVAL(str); return JS_TRUE; } #endif /* NARCISSUS */ int main(int argc, char **argv, char **envp) { int stackDummy; JSRuntime *rt; JSContext *cx; JSObject *glob, *it, *envobj; int result; #ifdef LIVECONNECT JavaVM *java_vm = NULL; #endif #ifdef JSDEBUGGER_JAVA_UI JNIEnv *java_env; #endif gStackBase = (jsuword)&stackDummy; #ifdef XP_OS2 /* these streams are normally line buffered on OS/2 and need a \n, * * so we need to unbuffer then to get a reasonable prompt */ setbuf(stdout,0); setbuf(stderr,0); #endif #if defined(OSSP) && defined(XP_WIN) setvbuf(stderr, 0, _IONBF, 0); setvbuf(stdout, 0, _IONBF, 0); #endif gErrFile = stderr; gOutFile = stdout; argc--; argv++; rt = JS_NewRuntime(64L * 1024L * 1024L); if (!rt) return 1; cx = JS_NewContext(rt, gStackChunkSize); if (!cx) return 1; JS_SetErrorReporter(cx, my_ErrorReporter); glob = JS_NewObject(cx, &global_class, NULL, NULL); if (!glob) return 1; #ifdef LAZY_STANDARD_CLASSES JS_SetGlobalObject(cx, glob); #else if (!JS_InitStandardClasses(cx, glob)) return 1; #ifdef OSSP #if defined(JS_HAS_FILE_OBJECT) && (JS_HAS_FILE_OBJECT - 0) /* OSSP BUGFIX */ if (!js_InitFileClass(cx, glob)) return 1; #endif #if defined(JS_HAS_DSO_OBJECT) && (JS_HAS_DSO_OBJECT - 0) if (!js_InitDSOClass(cx, glob)) return 1; #endif #endif #endif if (!JS_DefineFunctions(cx, glob, shell_functions)) return 1; it = JS_DefineObject(cx, glob, "it", &its_class, NULL, 0); if (!it) return 1; if (!JS_DefineProperties(cx, it, its_props)) return 1; if (!JS_DefineFunctions(cx, it, its_methods)) return 1; #ifdef PERLCONNECT if (!JS_InitPerlClass(cx, glob)) return 1; #endif #ifdef JSDEBUGGER /* * XXX A command line option to enable debugging (or not) would be good */ _jsdc = JSD_DebuggerOnForUser(rt, NULL, NULL); if (!_jsdc) return 1; JSD_JSContextInUse(_jsdc, cx); #ifdef JSD_LOWLEVEL_SOURCE JS_SetSourceHandler(rt, SendSourceToJSDebugger, _jsdc); #endif /* JSD_LOWLEVEL_SOURCE */ #ifdef JSDEBUGGER_JAVA_UI _jsdjc = JSDJ_CreateContext(); if (! _jsdjc) return 1; JSDJ_SetJSDContext(_jsdjc, _jsdc); java_env = JSDJ_CreateJavaVMAndStartDebugger(_jsdjc); #ifdef LIVECONNECT if (java_env) (*java_env)->GetJavaVM(java_env, &java_vm); #endif /* * XXX This would be the place to wait for the debugger to start. * Waiting would be nice in general, but especially when a js file * is passed on the cmd line. */ #endif /* JSDEBUGGER_JAVA_UI */ #ifdef JSDEBUGGER_C_UI JSDB_InitDebugger(rt, _jsdc, 0); #endif /* JSDEBUGGER_C_UI */ #endif /* JSDEBUGGER */ #ifdef LIVECONNECT if (!JSJ_SimpleInit(cx, glob, java_vm, getenv("CLASSPATH"))) return 1; #endif envobj = JS_DefineObject(cx, glob, "environment", &env_class, NULL, 0); if (!envobj || !JS_SetPrivate(cx, envobj, envp)) return 1; #ifdef NARCISSUS { jsval v; static const char Object_prototype[] = "Object.prototype"; if (!JS_DefineFunction(cx, glob, "snarf", snarf, 1, 0)) return 1; if (!JS_DefineFunction(cx, glob, "evaluate", Evaluate, 3, 0)) return 1; if (!JS_EvaluateScript(cx, glob, Object_prototype, sizeof Object_prototype - 1, NULL, 0, &v)) { return 1; } if (!JS_DefineFunction(cx, JSVAL_TO_OBJECT(v), "__defineProperty__", defineProperty, 5, 0)) { return 1; } } #endif result = ProcessArgs(cx, glob, argv, argc); #ifdef JSDEBUGGER if (_jsdc) JSD_DebuggerOff(_jsdc); #endif /* JSDEBUGGER */ JS_DestroyContext(cx); JS_DestroyRuntime(rt); JS_ShutDown(); return result; } @ 1.6 log @Be more clean and replace weak "#if JS_HAS_FILE_OBJECT" constructs with the stronger "#if defined(JS_HAS_FILE_OBJECT) && (JS_HAS_FILE_OBJECT - 0)" as the JS_HAS_FILE_OBJECT can be not defined at all (in contrast to other JS_HAS_XXXX defines which are all listed in src/jsconfig.h) @ text @d70 3 d2543 4 @ 1.5 log @Fix a bunch of compiler warnings. @ text @d67 1 a67 1 #if JS_HAS_FILE_OBJECT d2536 1 a2536 1 #if JS_HAS_FILE_OBJECT @ 1.4 log @Add support for Windows CygWin and MinGW environments. @ text @d1190 3 d1194 1 d1215 3 d1219 1 @ 1.3 log @Resolve conflicts after import of new upstream version: Mozilla JavaScript (SpiderMonkey) 1.6 as of 2006-07-24 @ text @d209 3 d213 1 d2499 5 @ 1.2 log @o Install all src/js*.h headers during "make install" to allow applications to at least optionally poke around in the internals. This also allows an application to call js_InitFileClass() from without us having to really call this function in the standard API function JS_InitStandardClasses(). o Change the default of the --with-file/--without from --without-file to --with-file (enable the File object by default), but activate it only in the CLI (where it doesn't hurt and where it is actually really required to get something useful running there in practice) but explicitly _NOT_ in JS_InitStandardClasses() (as this is what would hurt the security in applications which assume that JS_InitStandardClasses() initialized only really the standard classes). @ text @a556 6 static void my_LoadErrorReporter(JSContext *cx, const char *message, JSErrorReport *report); static void my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report); a565 1 JSErrorReporter older; a574 1 older = JS_SetErrorReporter(cx, my_LoadErrorReporter); a586 1 JS_SetErrorReporter(cx, older); d1565 48 d1626 2 d1667 2 d1696 2 a1697 2 fprintf(gOutFile, "%-9s %-22s %s\n", "Command", "Usage", "Description"); fprintf(gOutFile, "%-9s %-22s %s\n", "=======", "=====", "==========="); d1703 1 a1703 1 fprintf(gOutFile, "%-9.9s %s\n", shell_functions[n].name, shell_help_messages[n]); a1974 16 my_LoadErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) { if (!report) { fprintf(gErrFile, "%s\n", message); return; } /* Ignore any exceptions */ if (JSREPORT_IS_EXCEPTION(report->flags)) return; /* Otherwise, fall back to the ordinary error reporter. */ my_ErrorReporter(cx, message, report); } static void @ 1.1 log @Initial revision @ text @d66 6 d2491 6 @ 1.1.1.1 log @Import new upstream version: Mozilla JavaScript 1.6-1.5.0.5-20060722 @ text @@ 1.1.1.2 log @Import new upstream version: Mozilla JavaScript (SpiderMonkey) 1.6 as of 2006-07-24 @ text @d551 6 d566 1 d576 1 d589 1 a1567 48 static JSBool StringsAreUtf8(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { *rval = JS_CStringsAreUTF8() ? JSVAL_TRUE : JSVAL_FALSE; return JS_TRUE; } static const char* badUtf8 = "...\xC0..."; static const char* bigUtf8 = "...\xFB\xBF\xBF\xBF\xBF..."; static const jschar badSurrogate[] = { 'A', 'B', 'C', 0xDEEE, 'D', 'E', 0 }; static JSBool TestUtf8(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { intN mode = 1; jschar chars[20]; size_t charsLength = 5; char bytes[20]; size_t bytesLength = 20; if (argc && !JS_ValueToInt32(cx, *argv, &mode)) return JS_FALSE; /* The following throw errors if compiled with UTF-8. */ switch (mode) { /* mode 1: malformed UTF-8 string. */ case 1: JS_NewStringCopyZ(cx, badUtf8); break; /* mode 2: big UTF-8 character. */ case 2: JS_NewStringCopyZ(cx, bigUtf8); break; /* mode 3: bad surrogate character. */ case 3: JS_EncodeCharacters(cx, badSurrogate, 6, bytes, &bytesLength); break; /* mode 4: use a too small buffer. */ case 4: JS_DecodeBytes(cx, "1234567890", 10, chars, &charsLength); break; default: JS_ReportError(cx, "invalid mode parameter"); return JS_FALSE; } return !JS_IsExceptionPending (cx); } a1580 2 {"stringsAreUtf8", StringsAreUtf8, 0}, {"testUtf8", TestUtf8, 1}, a1619 2 "stringsAreUTF8() Check if strings are UTF-8 encoded", "testUTF8(mode) Perform UTF-8 tests (modes are 1 to 4)", d1647 2 a1648 2 fprintf(gOutFile, "%-14s %-22s %s\n", "Command", "Usage", "Description"); fprintf(gOutFile, "%-14s %-22s %s\n", "=======", "=====", "==========="); d1654 1 a1654 1 fprintf(gOutFile, "%-14.14s %s\n", shell_functions[n].name, shell_help_messages[n]); d1926 16 @