// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #include #include #include #include "config.h" #ifdef HAVE_JS_JSAPI_H #include #elif HAVE_MOZJS_JSAPI_H #include #else #include #endif #include "utf8.h" #include "http.h" int gExitCode = 0; #ifdef JS_THREADSAFE #define SETUP_REQUEST(cx) \ JS_SetContextThread(cx); \ JS_BeginRequest(cx); #define FINISH_REQUEST(cx) \ JS_EndRequest(cx); \ JS_ClearContextThread(cx); #else #define SETUP_REQUEST(cx) #define FINISH_REQUEST(cx) #endif static JSBool evalcx(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSString *str; JSObject *sandbox; JSContext *subcx; const jschar *src; size_t srclen; JSBool ret = JS_FALSE; jsval v; sandbox = NULL; if(!JS_ConvertArguments(cx, argc, argv, "S / o", &str, &sandbox)) { return JS_FALSE; } subcx = JS_NewContext(JS_GetRuntime(cx), 8L * 1024L); if(!subcx) { JS_ReportOutOfMemory(cx); return JS_FALSE; } SETUP_REQUEST(subcx); src = JS_GetStringChars(str); srclen = JS_GetStringLength(str); if(!sandbox) { sandbox = JS_NewObject(subcx, NULL, NULL, NULL); if(!sandbox || !JS_InitStandardClasses(subcx, sandbox)) goto done; } if(srclen == 0) { *rval = OBJECT_TO_JSVAL(sandbox); } else { JS_EvaluateUCScript(subcx, sandbox, src, srclen, NULL, 0, rval); } ret = JS_TRUE; done: FINISH_REQUEST(subcx); JS_DestroyContext(subcx); return ret; } static JSBool gc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JS_GC(cx); return JS_TRUE; } static JSBool print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { uintN i; char *bytes; for(i = 0; i < argc; i++) { bytes = enc_string(cx, argv[i], NULL); if(!bytes) return JS_FALSE; fprintf(stdout, "%s%s", i ? " " : "", bytes); JS_free(cx, bytes); } fputc('\n', stdout); fflush(stdout); return JS_TRUE; } static JSBool quit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JS_ConvertArguments(cx, argc, argv, "/ i", &gExitCode); return JS_FALSE; } static char* readfp(JSContext* cx, FILE* fp, size_t* buflen) { char* bytes = NULL; char* tmp = NULL; size_t used = 0; size_t byteslen = 256; size_t readlen = 0; bytes = JS_malloc(cx, byteslen); if(bytes == NULL) return NULL; while((readlen = js_fgets(bytes+used, byteslen-used, stdin)) > 0) { used += readlen; if(bytes[used-1] == '\n') { bytes[used-1] = '\0'; break; } // Double our buffer and read more. byteslen *= 2; tmp = JS_realloc(cx, bytes, byteslen); if(!tmp) { JS_free(cx, bytes); return NULL; } bytes = tmp; } *buflen = used; return bytes; } static JSBool readline(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { jschar *chars; JSString *str; char* bytes; char* tmp; size_t byteslen; /* GC Occasionally */ JS_MaybeGC(cx); bytes = readfp(cx, stdin, &byteslen); if(!bytes) return JS_FALSE; /* Treat the empty string specially */ if(byteslen == 0) { *rval = JS_GetEmptyStringValue(cx); JS_free(cx, bytes); return JS_TRUE; } /* Shrink the buffer to the real size */ tmp = JS_realloc(cx, bytes, byteslen); if(!tmp) { JS_free(cx, bytes); return JS_FALSE; } bytes = tmp; str = dec_string(cx, bytes, byteslen); JS_free(cx, bytes); if(!str) return JS_FALSE; *rval = STRING_TO_JSVAL(str); 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 void execute_script(JSContext *cx, JSObject *obj, const char *filename) { FILE *file; JSScript *script; jsval result; if(!filename || strcmp(filename, "-") == 0) { file = stdin; } else { file = fopen(filename, "r"); if (!file) { fprintf(stderr, "could not open script file %s\n", filename); gExitCode = 1; return; } } script = JS_CompileFileHandle(cx, obj, filename, file); if(script) { JS_ExecuteScript(cx, obj, script, &result); JS_DestroyScript(cx, script); } } static void printerror(JSContext *cx, const char *mesg, JSErrorReport *report) { if(!report || !JSREPORT_IS_WARNING(report->flags)) { fprintf(stderr, "%s\n", mesg); } } static JSFunctionSpec global_functions[] = { {"evalcx", evalcx, 0, 0, 0}, {"gc", gc, 0, 0, 0}, {"print", print, 0, 0, 0}, {"quit", quit, 0, 0, 0}, {"readline", readline, 0, 0, 0}, {"seal", seal, 0, 0, 0}, {0, 0, 0, 0, 0} }; static JSClass global_class = { "GlobalClass", JSCLASS_GLOBAL_FLAGS, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, JSCLASS_NO_OPTIONAL_MEMBERS }; int main(int argc, const char * argv[]) { JSRuntime* rt = NULL; JSContext* cx = NULL; JSObject* global = NULL; JSFunctionSpec* sp = NULL; int i = 0; rt = JS_NewRuntime(64L * 1024L * 1024L); if (!rt) return 1; cx = JS_NewContext(rt, 8L * 1024L); if (!cx) return 1; JS_SetErrorReporter(cx, printerror); JS_ToggleOptions(cx, JSOPTION_XML); SETUP_REQUEST(cx); global = JS_NewObject(cx, &global_class, NULL, NULL); if (!global) return 1; if (!JS_InitStandardClasses(cx, global)) return 1; for(sp = global_functions; sp->name != NULL; sp++) { if(!JS_DefineFunction(cx, global, sp->name, sp->call, sp->nargs, sp->flags)) { fprintf(stderr, "Failed to create function: %s\n", sp->name); return 1; } } if(!install_http(cx, global)) { return 1; } JS_SetGlobalObject(cx, global); if(argc > 2) { fprintf(stderr, "incorrect number of arguments\n\n"); fprintf(stderr, "usage: %s \n", argv[0]); return 2; } if(argc == 0) { execute_script(cx, global, NULL); } else { execute_script(cx, global, argv[1]); } FINISH_REQUEST(cx); JS_DestroyContext(cx); JS_DestroyRuntime(rt); JS_ShutDown(); return gExitCode; }