[Pkg-mozext-commits] [adblock-plus] 11/464: Initial import.
David Prévot
taffit at moszumanska.debian.org
Tue Jul 22 20:43:57 UTC 2014
This is an automated email from the git hooks/post-receive script.
taffit pushed a commit to branch master
in repository adblock-plus.
commit 2b10021ab2dd896f2daac29756efa73565fd23ae
Author: Joshua Cranmer <Pidgeot18 at gmail.com>
Date: Fri Jan 23 14:15:34 2009 -0500
Initial import.
This builds and works.
---
Makefile | 24 ++++
README | 7 +
jshydra.c | 237 +++++++++++++++++++++++++++++++
jshydra_bridge.c | 233 ++++++++++++++++++++++++++++++
jshydra_bridge.h | 30 ++++
jshydra_funcs.c | 421 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
jshydra_funcs.h | 39 ++++++
7 files changed, 991 insertions(+)
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..857d631
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,24 @@
+INCLUDE = -I/src/build/trunk/browser/dist/include/js/ \
+ -I/src/build/trunk/browser/dist/include/nspr/ -DXP_UNIX \
+ -I/src/trunk/mozilla/js/src/
+LINK := -L/src/build/trunk/browser/dist/lib -lnspr4 -lm
+
+OBJS := jsapi.o jsarena.o jsarray.o jsatom.o jsbool.o jscntxt.o jsdate.o \
+ jsdbgapi.o jsdhash.o jsdtoa.o jsemit.o jsexn.o jsfun.o jsgc.o jshash.o \
+ jsinterp.o jsinvoke.o jsiter.o jslock.o jslog2.o jslong.o jsmath.o jsnum.o \
+ jsobj.o json.o jsopcode.o jsparse.o jsprf.o jsregexp.o jsscan.o jsscope.o \
+ jsscript.o jsstr.o jsutil.o jsxdrapi.o jsxml.o prmjtime.o jstracer.o \
+ Assembler.o Fragmento.o LIR.o RegAlloc.o avmplus.o Nativei386.o jsbuiltins.o
+
+OBJS := $(addprefix /src/build/trunk/browser/js/src/, $(OBJS))
+
+jshydra: jshydra.o jshydra_funcs.o jshydra_bridge.o
+ g++ -o jshydra jshydra.o jshydra_funcs.o jshydra_bridge.o $(OBJS) $(LINK)
+
+jshydra.o: jshydra.c
+ gcc -o jshydra.o -g $(INCLUDE) -c jshydra.c
+
+jshydra_funcs.o: jshydra_funcs.c
+ gcc -o jshydra_funcs.o -g $(INCLUDE) -c jshydra_funcs.c
+jshydra_bridge.o: jshydra_bridge.c
+ gcc -o jshydra_bridge.o -g $(INCLUDE) -c jshydra_bridge.c
diff --git a/README b/README
new file mode 100644
index 0000000..7a20499
--- /dev/null
+++ b/README
@@ -0,0 +1,7 @@
+JSHydra static analysis tool
+
+jshydra_builtins.c and jshydra_funcs.c are copied from the dehydra sources with
+minor changes.
+
+The code requires a recent spidermonkey build, as it uses part of the internal
+API. Modify the /src/ paths in Makefile as appropriate to build.
diff --git a/jshydra.c b/jshydra.c
new file mode 100644
index 0000000..b57e314
--- /dev/null
+++ b/jshydra.c
@@ -0,0 +1,237 @@
+typedef int bool;
+
+#include "jsapi.h"
+#include "jsparse.h"
+#include "jscntxt.h"
+#include <stdio.h>
+
+#include "jshydra_bridge.h"
+
+/*static JSRuntime *rt;
+static JSContext *cx;
+static JSObject *globalObject;*/
+
+static char *opcodes[] = {
+#define OPDEF(op, val, name, image, len, use, def, prec, format) \
+ #op,
+#include "jsopcode.tbl"
+#undef OPDEF
+ NULL
+};
+
+void setIntProperty(JSObject *obj, const char *name, int value) {
+ jshydra_defineProperty(cx, obj, name, INT_TO_JSVAL(value));
+}
+void setObjectProperty(JSObject *obj, const char *name, JSObject *value) {
+ jshydra_defineProperty(cx, obj, name, OBJECT_TO_JSVAL(value));
+}
+void setArrayElement(JSObject *array, jsint index, JSObject *value) {
+ jsval argv[1];
+ if (value)
+ argv[0] = OBJECT_TO_JSVAL(value);
+ else
+ argv[0] = JSVAL_NULL;
+ JS_SetElement(cx, array, index, argv);
+}
+
+typedef enum TokenValue {
+ FUNCTION, LIST, TERNARY, BINARY, UNARY, NAME, LEXICAL, APAIR, OBJLITERAL, DOUBLELITERAL, NULLARY, ERROR
+} TokenValue;
+
+TokenValue tokens[] = {
+ ERROR, /*TOK_EOF*/
+ ERROR, /*TOK_EOL*/
+ UNARY, /*TOK_SEMI*/
+ LIST, /*TOK_COMMA*/
+ BINARY, /*TOK_ASSIGN*/
+ BINARY, /*TOK_HOOK*/
+ NAME, /*TOK_COLON*/
+ BINARY, /*TOK_OR*/
+ BINARY, /*TOK_AND*/
+ BINARY, /*TOK_BITOR*/
+ BINARY, /*TOK_BITXOR*/
+ BINARY, /*TOK_BITAND*/
+ BINARY, /*TOK_EQOP*/
+ BINARY, /*TOK_RELOP*/
+ BINARY, /*TOK_SHOP*/
+ BINARY, /*TOK_PLUS*/
+ BINARY, /*TOK_MINUS*/
+ BINARY, /*TOK_STAR*/
+ BINARY, /*TOK_DIVOP*/
+ UNARY, /*TOK_UNARYOP*/
+ UNARY, /*TOK_INC*/
+ UNARY, /*TOK_DEC*/
+ NAME, /*TOK_DOT*/
+ BINARY, /*TOK_LB*/
+ LIST, /*TOK_RB*/
+ LIST, /*TOK_LC*/
+ LIST, /*TOK_RC*/
+ LIST, /*TOK_LP*/
+ UNARY, /*TOK_RP*/
+ NAME, /*TOK_NAME*/
+ DOUBLELITERAL, /*TOK_NUMBER*/
+ NAME, /*TOK_STRING*/
+ NAME, /*TOK_REGEXP*/
+ NULLARY, /*TOK_PRIMARY*/
+ FUNCTION, /*TOK_FUNCTION*/
+ TERNARY, /*TOK_IF*/
+ ERROR, /*TOK_ELSE (not present) */
+ BINARY, /*TOK_SWITCH*/
+ BINARY, /*TOK_CASE*/
+ BINARY, /*TOK_DEFAULT*/
+ BINARY, /*TOK_WHILE*/
+ BINARY, /*TOK_DO*/
+ BINARY, /*TOK_FOR*/
+ NAME, /*TOK_BREAK*/
+ NAME, /*TOK_CONTINUE*/
+ ERROR, /*TOK_IN*/
+ LIST, /*TOK_VAR*/
+ BINARY, /*TOK_WITH*/
+ UNARY, /*TOK_RETURN*/
+ ERROR, /*TOK_NEW*/
+ ERROR, /*TOK_DELETE*/
+ UNARY, /*TOK_DEFSHARP*/
+ NULLARY, /*TOK_USESHARP (use pn_num)*/
+ TERNARY, /*TOK_TRY*/
+ TERNARY, /*TOK_CATCH*/
+ ERROR, /*TOK_FINALLY*/
+ UNARY, /*TOK_THROW*/
+ ERROR, /*TOK_INSTANCEOF*/
+ ERROR, /*TOK_DEBUGGER*/
+ ERROR, /*TOK_XMLSTAGO*/
+ ERROR, /*TOK_XMLETAGO*/
+ ERROR, /*TOK_XMLPTAGC*/
+ ERROR, /*TOK_XMLTAGC*/
+ ERROR, /*TOK_XMLNAME*/
+ ERROR, /*TOK_XMLATTR*/
+ ERROR, /*TOK_XMLSPACE*/
+ ERROR, /*TOK_XMLTEXT*/
+ ERROR, /*TOK_XMLCOMMENT*/
+ ERROR, /*TOK_XMLCDATA*/
+ ERROR, /*TOK_XMLPI*/
+ ERROR, /*TOK_AT*/
+ ERROR, /*TOK_DBLCOLON*/
+ ERROR, /*TOK_ANYNAME*/
+ NAME, /*TOK_DBLDOT*/
+ ERROR, /*TOK_FILTER*/
+ ERROR, /*TOK_XMLELEM*/
+ ERROR, /*TOK_XMLLIST*/
+ ERROR, /*TOK_YIELD*/
+ LIST, /*TOK_ARRAYCOMP*/
+ UNARY, /*TOK_ARRAYPUSH*/
+ NAME, /*TOK_LEXICALSCOPE*/
+ ERROR, /*TOK_LET*/
+ ERROR, /*TOK_SEQ*/
+ ERROR, /*TOK_FORHEAD*/
+ //TOK_RESERVED,
+ //TOK_LIMIT
+ ERROR
+};
+
+JSObject *makeNode(JSParseNode *node) {
+ if (!node)
+ return NULL;
+ JSObject *object = JS_NewObject(cx, &js_node_class, NULL, NULL);
+ setIntProperty(object, "line", node->pn_pos.begin.lineno);
+ setIntProperty(object, "column", node->pn_pos.begin.index);
+ setIntProperty(object, "op", node->pn_op);
+ setIntProperty(object, "type", node->pn_type);
+ switch (tokens[node->pn_type]) {
+ case FUNCTION: {
+ setIntProperty(object, "flags", node->pn_flags);
+ JSObject *array = JS_NewArrayObject(cx, 0, NULL);
+ setArrayElement(array, 0, makeNode(node->pn_body));
+ setObjectProperty(object, "kids", array);
+ break;
+ }
+ case LIST: {
+ JSObject *array = JS_NewArrayObject(cx, 0, NULL);
+ int i = 0;
+ for (node = node->pn_head; node; node = node->pn_next) {
+ setArrayElement(array, i++, makeNode(node));
+ }
+ setObjectProperty(object, "kids", array);
+ break;
+ }
+ case TERNARY: {
+ JSObject *array = JS_NewArrayObject(cx, 0, NULL);
+ setArrayElement(array, 0, makeNode(node->pn_kid1));
+ setArrayElement(array, 1, makeNode(node->pn_kid2));
+ setArrayElement(array, 2, makeNode(node->pn_kid3));
+ setObjectProperty(object, "kids", array);
+ break;
+ }
+ case BINARY: {
+ jshydra_defineProperty(cx, object, "value", node->pn_val);
+ JSObject *array = JS_NewArrayObject(cx, 0, NULL);
+ setArrayElement(array, 0, makeNode(node->pn_left));
+ setArrayElement(array, 1, makeNode(node->pn_right));
+ setObjectProperty(object, "kids", array);
+ break;
+ }
+ case UNARY: {
+ JSObject *array = JS_NewArrayObject(cx, 0, NULL);
+ setArrayElement(array, 0, makeNode(node->pn_kid));
+ setObjectProperty(object, "kids", array);
+ break;
+ }
+ case NAME: {
+ JS_DefineProperty(cx, object, "atom", ATOM_KEY(node->pn_atom), NULL, NULL, JSPROP_READONLY);
+ JSObject *array = JS_NewArrayObject(cx, 0, NULL);
+ setArrayElement(array, 0, makeNode(node->pn_expr));
+ setObjectProperty(object, "kids", array);
+ break;
+ }
+ //case LEXICAL:
+ //case APAIR:
+ //case OBJLITERAL:
+ case DOUBLELITERAL:
+ jshydra_defineProperty(cx, object, "value", DOUBLE_TO_JSVAL(node->pn_dval));
+ break;
+ case NULLARY:
+ break;
+ case ERROR:
+ default:
+ fprintf(stderr, "Unexpected type: %d\n", node->pn_type);
+ break;
+ }
+ return object;
+}
+
+void parseFile(FILE *file, char *filename) {
+ JSParseContext pc;
+ if (!js_InitParseContext(cx, &pc, NULL, NULL, NULL, 0, file, filename, 1))
+ return;
+ JSParseNode *root = js_ParseScript(cx, globalObj, &pc);
+ JSObject *ast = makeNode(root);
+ jsval func = jshydra_getToplevelFunction(cx, "process_js");
+ if (JS_TypeOfValue(cx, func) != JSTYPE_FUNCTION) {
+ fprintf(stderr, "No function process_js!\n");
+ return;
+ }
+ jsval rval, argv[1];
+ argv[0] = OBJECT_TO_JSVAL(ast);
+ JS_CallFunctionValue(cx, globalObj, func, 1, argv, &rval);
+}
+
+int main(int argc, char **argv) {
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s script filename...\n", argv[0]);
+ return -1;
+ }
+ jshydra_init(argv[1]);
+ jshydra_includeScript(cx, argv[1]);
+ argc--;
+ argv++;
+ do {
+ argc--;
+ argv++;
+ FILE *input = fopen(argv[0], "r");
+ if (!input) {
+ fprintf(stderr, "No such file %s\n", argv[0]);
+ continue;
+ }
+ parseFile(input, argv[0]);
+ } while (argc > 1);
+
+}
diff --git a/jshydra_bridge.c b/jshydra_bridge.c
new file mode 100644
index 0000000..d63c02d
--- /dev/null
+++ b/jshydra_bridge.c
@@ -0,0 +1,233 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+#include <jsapi.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "jshydra_bridge.h"
+#include "jshydra_funcs.h"
+
+JSRuntime *rt;
+JSContext *cx;
+JSObject *globalObj;
+
+static char *my_dirname (char *path);
+
+JSClass js_node_class = {
+ "JSHydraNode", /* name */
+ JSCLASS_CONSTRUCT_PROTOTYPE, /* flags */
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub,JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+void jshydra_init(const char *file) {
+ static JSFunctionSpec shell_functions[] = {
+ {"_print", Print, 0},
+ {"include", Include, 1},
+ {"write_file", WriteFile, 1},
+ {"read_file", ReadFile, 1},
+ {"diagnostic", Diagnostic, 0},
+ {"require", Require, 1},
+ {"hashcode", Hashcode, 1},
+ {0}
+ };
+
+ //this->fndeclMap = pointer_map_create ();
+ rt = JS_NewRuntime (0x9000000L);
+ cx = JS_NewContext (rt, 8192);
+ JS_BeginRequest(cx);
+
+ //JS_SetContextPrivate (this->cx, this);
+
+ globalObj = JS_NewObject (cx, NULL, 0, 0);
+ JS_InitStandardClasses (cx, globalObj);
+ /* register error handler */
+ JS_SetErrorReporter (cx, ErrorReporter);
+ xassert (JS_DefineFunctions (cx, globalObj, shell_functions));
+ if (jshydra_getToplevelFunction(cx, "include") == JSVAL_VOID) {
+ fprintf (stderr, "Your version of spidermonkey has broken JS_DefineFunctions, upgrade it or ./configure with another version\n");
+ exit(1);
+ }
+ //this->rootedArgDestArray =
+ // JS_NewArrayObject (this->cx, 0, NULL);
+ //JS_AddRoot (this->cx, &this->rootedArgDestArray);
+ // this is to be added at function_decl time
+ //this->rootedFreeArray = JS_NewArrayObject (this->cx, 0, NULL);
+ //JS_DefineElement (this->cx, this->rootedArgDestArray, 0,
+ // OBJECT_TO_JSVAL (this->rootedFreeArray),
+ // NULL, NULL, JSPROP_ENUMERATE);
+ JS_SetVersion (cx, (JSVersion) 170);
+
+
+ /* Initialize namespace for plugin system stuff. */
+ JSObject *sys = jshydra_defineObjectProperty(cx, globalObj, "sys");
+ /* Set version info */
+ //dehydra_defineStringProperty (this, sys, VERSION_STRING, version_string);
+ //dehydra_defineStringProperty (this, sys, FRONTEND, lang_hooks.name);
+ /* Initialize include path. */
+ jshydra_defineArrayProperty (cx, sys, "include_path", 0);
+
+ char *filename_copy = strdup(file);
+ char *dir = my_dirname(filename_copy);
+ jshydra_appendToPath(cx, dir);
+ char *libdir = malloc(strlen(dir) + strlen("libs") + 2);
+ sprintf(libdir, "%s/%s", dir, "libs");
+ jshydra_appendToPath(cx, libdir);
+ free(libdir);
+ free(filename_copy);
+
+ /* Output filename info */
+ //if (aux_base_name) {
+ // dehydra_defineStringProperty (this, sys, "aux_base_name", aux_base_name);
+ //}
+ xassert (JS_InitClass(cx, globalObj, NULL
+ ,&js_node_class , NULL, 0, NULL, NULL, NULL, NULL));
+}
+
+/*int dehydra_startup (Dehydra *this) {
+ return dehydra_includeScript (this, "dehydra.js");
+}*/
+
+int jshydra_includeScript (JSContext *cx, const char *script) {
+ jsval strval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, script));
+ //int key = dehydra_rootObject (this, strval);
+ jsval rval;
+ int ret = !Include (cx, globalObj, 1, &strval, &rval);
+ //dehydra_unrootObject (this, key);
+ return ret;
+}
+
+JSObject *jshydra_getIncludePath (JSContext *cx)
+{
+ jsval sys_val, path_val;
+ JS_GetProperty(cx, globalObj, "sys", &sys_val);
+ JS_GetProperty(cx, JSVAL_TO_OBJECT(sys_val), "include_path", &path_val);
+ return JSVAL_TO_OBJECT(path_val);
+}
+
+/* Append a directory name to the script include path. */
+void jshydra_appendToPath (JSContext *cx, const char *dir)
+{
+ JSObject *path = jshydra_getIncludePath(cx);
+ unsigned int length = jshydra_getArrayLength(cx, path);
+ JSString *dir_str = JS_NewStringCopyZ(cx, dir);
+ jsval dir_val = STRING_TO_JSVAL(dir_str);
+ JS_DefineElement(cx, path, length, dir_val, NULL, NULL,
+ JSPROP_ENUMERATE);
+}
+
+/* Avoiding bug 431100. Spec from man 2 dirname */
+static char *my_dirname (char *path) {
+ char *r = strrchr(path, '/');
+ if (!r) {
+ strcpy (path, ".");
+ return path;
+ } else if (r == path && r[1] == 0) {
+ return path; // '/'
+ } else if (r[1] == 0) {
+ // /foo/ foo/ cases
+ *r = 0;
+ return my_dirname (path);
+ }
+ *r = 0;
+ return path;
+}
+
+/* Search the include path for a file matching the given name. The current
+ * directory will be searched last. */
+FILE *jshydra_searchPath (JSContext *cx, const char *filename, char **realname)
+{
+ if (filename && filename[0] != '/') {
+ JSObject *path = jshydra_getIncludePath(cx);
+ int length = jshydra_getArrayLength(cx, path);
+ int i;
+ for (i = 0; i < length; ++i) {
+ jsval val;
+ JS_GetElement(cx, path, i, &val);
+
+ JSString *dir_str = JS_ValueToString(cx, val);
+ if (!dir_str) continue;
+ char *dir = JS_GetStringBytes(dir_str);
+
+ char *buf = malloc(strlen(dir) + strlen(filename) + 2);
+ /* Doing a little extra work here to get rid of unneeded '/'. */
+ char *sep = dir[strlen(dir)-1] == '/' ? "" : "/";
+ sprintf(buf, "%s%s%s", dir, sep, filename);
+ FILE *f = fopen(buf, "r");
+ if (f) {
+ *realname = buf;
+ return f;
+ } else {
+ free(buf);
+ }
+ }
+ }
+
+ FILE *f = fopen(filename, "r");
+ if (f) {
+ *realname = strdup(filename);
+ return f;
+ }
+
+ return NULL;
+}
+
+jsuint jshydra_getArrayLength (JSContext *cx, JSObject *array) {
+ jsuint length = 0;
+ xassert (JS_GetArrayLength (cx, array, &length));
+ return length;
+}
+
+JSObject *definePropertyObject (JSContext *cx, JSObject *obj,
+ const char *name, JSClass *clasp,
+ JSObject *proto, uintN flags) {
+ JSObject *nobj = JS_NewObject (cx, clasp, proto, NULL);
+ JS_DefineProperty (cx, obj, name, OBJECT_TO_JSVAL(nobj), NULL, NULL, flags);
+ return nobj;
+}
+
+void jshydra_defineProperty (JSContext *cx, JSObject *obj,
+ char const *name, jsval value)
+{
+ JS_DefineProperty (cx, obj, name, value,
+ NULL, NULL, JSPROP_ENUMERATE);
+}
+/*
+void dehydra_defineStringProperty (Dehydra *this, JSObject *obj,
+ char const *name, char const *value)
+{
+ JSString *str = JS_NewStringCopyZ (this->cx, value);
+ dehydra_defineProperty (this, obj, name, STRING_TO_JSVAL(str));
+}
+*/
+JSObject *jshydra_defineArrayProperty (JSContext *cx, JSObject *obj,
+ char const *name, int length) {
+ JSObject *destArray = JS_NewArrayObject (cx, length, NULL);
+ jshydra_defineProperty (cx, obj, name, OBJECT_TO_JSVAL (destArray));
+ return destArray;
+}
+
+JSObject *jshydra_defineObjectProperty (JSContext *cx, JSObject *obj,
+ char const *name) {
+ return definePropertyObject(
+ cx, obj, name, NULL, NULL,
+ JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
+}
+
+/* Load and execute a Javascript file.
+ * Return: 0 on success
+ * 1 on failure if a Javascript exception is pending
+ * does not return if a Javascript error is reported
+ * The general behavior of (De|Tree)hydra is to print a message and
+ * exit if a JS error is reported at the top level. But if this function
+ * is called from JS, then the JS_* functions will instead set an
+ * exception, which will be propgated back up to the callers for
+ * eventual handling or exit. */
+
+jsval jshydra_getToplevelFunction(JSContext *cx, char const *name) {
+ jsval val = JSVAL_VOID;
+ return (JS_GetProperty(cx, globalObj, name, &val)
+ && val != JSVAL_VOID
+ && JS_TypeOfValue(cx, val) == JSTYPE_FUNCTION) ? val : JSVAL_VOID;
+}
diff --git a/jshydra_bridge.h b/jshydra_bridge.h
new file mode 100644
index 0000000..735ad6c
--- /dev/null
+++ b/jshydra_bridge.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+#ifndef JSHYDRA_BRIDGE_H
+#define JSHYDRA_BRIDGE_H
+
+extern JSContext *cx;
+extern JSObject *globalObj;
+
+extern JSClass js_node_class;
+
+void jshydra_init(const char *file);
+FILE *jshydra_searchPath(JSContext *cx, const char *filename, char **realname);
+void jshydra_appendToPath (JSContext *cx, const char *dir);
+int jshydra_includeScript(JSContext *cx, const char *filename);
+
+/* Drop-in replacement for JS_DefineObject, required as a workaround
+ * because JS_DefineObject always sets the parent property. */
+JSObject *definePropertyObject (JSContext *cx, JSObject *obj,
+ const char *name, JSClass *clasp,
+ JSObject *proto, uintN flags);
+JSObject *jshydra_defineArrayProperty (JSContext *cx, JSObject *obj,
+ char const *name, int length);
+JSObject *jshydra_defineObjectProperty (JSContext *cx, JSObject *obj,
+ char const *name);
+void jshydra_defineProperty(JSContext *cx, JSObject *obj,
+ char const *name, jsval value);
+
+jsuint jshydra_getArrayLength(JSContext *cx, JSObject *array);
+jsval jshydra_getToplevelFunction(JSContext *cx, char const *name);
+
+#endif
diff --git a/jshydra_funcs.c b/jshydra_funcs.c
new file mode 100644
index 0000000..961b03a
--- /dev/null
+++ b/jshydra_funcs.c
@@ -0,0 +1,421 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "jsapi.h"
+#include "jshydra_funcs.h"
+#include "jshydra_bridge.h"
+
+JSBool require_version(JSContext *cx, jsval val) {
+ JSString *version_str = JS_ValueToString(cx, val);
+ if (!version_str) return JS_FALSE;
+ char *version_cstr = JS_GetStringBytes(version_str);
+ JSVersion version = JS_StringToVersion(version_cstr);
+ JSBool retval;
+ if (version == JSVERSION_UNKNOWN) {
+ JS_ReportError(cx, "Invalid version '%s'", version_cstr);
+ retval = JS_FALSE;
+ } else {
+ JS_SetVersion(cx, version);
+ retval = JS_TRUE;
+ }
+ return retval;
+}
+
+JSBool require_option(JSContext *cx, jsval val, uint32 option) {
+ JSBool flag;
+ if (!JS_ValueToBoolean(cx, val, &flag)) return JS_FALSE;
+ if (flag) {
+ JS_SetOptions(cx, JS_GetOptions(cx) | option);
+ } else {
+ JS_SetOptions(cx, JS_GetOptions(cx) & ~option);
+ }
+ return JS_TRUE;
+}
+
+JSBool dispatch_require(JSContext *cx, const char *prop_name, jsval prop_val) {
+ if (strcmp(prop_name, "version") == 0) {
+ return require_version(cx, prop_val);
+ } else if (strcmp(prop_name, "strict") == 0) {
+ return require_option(cx, prop_val, JSOPTION_STRICT);
+ } else if (strcmp(prop_name, "werror") == 0) {
+ return require_option(cx, prop_val, JSOPTION_WERROR);
+ } else if (strcmp(prop_name, "gczeal") == 0) {
+#ifdef JS_GC_ZEAL
+ uintN zeal;
+ if (!JS_ValueToECMAUint32(cx, prop_val, &zeal))
+ return JS_FALSE;
+ JS_SetGCZeal(cx, zeal);
+#else
+#ifdef DEBUG
+ JS_ReportWarning(cx, "gczeal not available: xhydra built with a SpiderMonkey version"
+ " lacking JS_SetGCZeal");
+#else
+ JS_ReportWarning(cx, "gczeal not available: xhydra built without -DDEBUG");
+#endif //DEBUG
+#endif //JS_GC_ZEAL
+ return JS_TRUE;
+ } else {
+ JS_ReportWarning(cx, "Unrecognized require keyword '%s'", prop_name);
+ return JS_TRUE;
+ }
+}
+
+/* Helper to return the current version as a JS string. */
+jsval get_version(JSContext *cx)
+{
+ const char *version_cstr = JS_VersionToString(JS_GetVersion(cx));
+ if (version_cstr == NULL) {
+ return JSVAL_VOID;
+ }
+ JSString *version_str = JS_NewStringCopyZ(cx, version_cstr);
+ return STRING_TO_JSVAL(version_str);
+}
+
+JSBool Require(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSObject *args;
+ if (!JS_ConvertArguments(cx, argc, argv, "o", &args)) return JS_FALSE;
+ JSIdArray *prop_ids = JS_Enumerate(cx, args);
+ if (!prop_ids) return JS_FALSE;
+
+ /* Apply the options. */
+ JSBool retval = JS_TRUE;
+ int i;
+ for (i = 0; i < prop_ids->length; ++i) {
+ jsval prop;
+ JSBool rv = JS_IdToValue(cx, prop_ids->vector[i], &prop);
+ argv[argc+1] = prop;
+ xassert(rv);
+ JSString *prop_str = JSVAL_TO_STRING(prop);
+ char *prop_name = JS_GetStringBytes(prop_str);
+ jsval prop_val;
+ rv = JS_GetProperty(cx, args, prop_name, &prop_val);
+ xassert(rv);
+
+ rv = dispatch_require(cx, prop_name, prop_val);
+ if (rv == JS_FALSE) retval = JS_FALSE;
+ }
+ JS_DestroyIdArray(cx, prop_ids);
+ if (!retval) return retval;
+
+ /* Report the now-current options. */
+ JSObject *rvalo = JS_NewObject(cx, NULL, NULL, NULL);
+ if (!rvalo) return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(rvalo);
+ JS_DefineProperty(
+ cx, rvalo, "version", get_version(cx), NULL, NULL, JSPROP_ENUMERATE);
+ uint32 options = JS_GetOptions(cx);
+ JS_DefineProperty(
+ cx, rvalo, "strict",
+ (options | JSOPTION_STRICT) ? JSVAL_TRUE : JSVAL_FALSE,
+ NULL, NULL, JSPROP_ENUMERATE);
+ JS_DefineProperty(
+ cx, rvalo, "werror",
+ (options | JSOPTION_WERROR) ? JSVAL_TRUE : JSVAL_FALSE,
+ NULL, NULL, JSPROP_ENUMERATE);
+ return JS_TRUE;
+}
+
+/* Load and run the named script. The last argument is the object to use
+ as "this" when evaluating the script, which is effectively a namespace
+ for the script. */
+static JSBool jshydra_loadScript (JSContext *cx, const char *filename,
+ JSObject *namespace) {
+ /* Read the file. There's a JS function for reading scripts, but Dehydra
+ wants to search for the file in different dirs. */
+ long size = 0;
+ char *realname;
+ FILE *f = jshydra_searchPath(cx, filename, &realname);
+ if (!f) {
+ REPORT_ERROR_1(cx, "Cannot find include file '%s'", filename);
+ return JS_FALSE;
+ }
+ char *content = readEntireFile(f, &size);
+ if (!content) {
+ REPORT_ERROR_1(cx, "Cannot read include file '%s'", realname);
+ free(realname);
+ return JS_FALSE;
+ }
+
+ JSScript *script = JS_CompileScript(cx, namespace,
+ content, size, realname, 1);
+ free(realname);
+ if (script == NULL) {
+ xassert(JS_IsExceptionPending(cx));
+ return JS_FALSE;
+ }
+
+ JSObject *sobj = JS_NewScriptObject(cx, script);
+ JS_AddNamedRoot(cx, &sobj, filename);
+ jsval rval;
+ JSBool rv = JS_ExecuteScript(cx, namespace, script, &rval);
+ JS_RemoveRoot(cx, &sobj);
+ if (!rv) {
+ xassert(JS_IsExceptionPending(cx));
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+/* should use this function to load all objects to avoid possibity of objects including themselves */
+JSBool Include(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval) {
+ char *filename;
+ JSObject *namespace = globalObj;
+ if (!JS_ConvertArguments(cx, argc, argv, "s/o", &filename, &namespace))
+ return JS_FALSE;
+
+ *rval = OBJECT_TO_JSVAL (namespace);
+ JSObject *includedArray = NULL;
+ jsval val;
+ JS_GetProperty(cx, namespace, "_includedArray", &val);
+ if (!JSVAL_IS_OBJECT (val)) {
+ includedArray = JS_NewArrayObject (cx, 0, NULL);
+ jshydra_defineProperty (cx, namespace, "_includedArray",
+ OBJECT_TO_JSVAL (includedArray));
+ } else {
+ includedArray = JSVAL_TO_OBJECT (val);
+ xassert (JS_CallFunctionName (cx, includedArray, "lastIndexOf",
+ 1, argv, &val));
+ /* Return if file was already included in this namespace. */
+ if (JSVAL_TO_INT (val) != -1) return JS_TRUE;
+ }
+
+ JS_CallFunctionName (cx, includedArray, "push", 1, argv, rval);
+ return jshydra_loadScript (cx, filename, namespace);
+}
+
+JSBool Diagnostic(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval) {
+ JSBool is_error;
+ const char *msg, *file, *error_string;
+ jsint line;
+ JSObject *loc_obj = NULL;
+
+ if (!JS_ConvertArguments(cx, argc, argv, "bs/o", &is_error, &msg, &loc_obj))
+ return JS_FALSE;
+ error_string = is_error ? "error" : "warning";
+ if (loc_obj) {
+ jsval jsfile, jsline;
+ if (JS_GetProperty(cx, loc_obj, "file", &jsfile) &&
+ JS_GetProperty(cx, loc_obj, "line", &jsline)) {
+ file = JS_GetStringBytes(JSVAL_TO_STRING(jsfile));
+ line = JSVAL_TO_INT(jsline);
+ printf("%s:%d: %s: %s\n", file, line, error_string, msg);
+ return JS_TRUE;
+ }
+ }
+
+ printf("%s: %s\n", error_string, msg);
+ return JS_TRUE;
+}
+
+JSBool Print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ uintN i;
+ for (i = 0; i < argc; i++) {
+ JSString *str = JS_ValueToString(cx, argv[i]);
+ if (!str)
+ return JS_FALSE;
+ printf("%s", JS_GetStringBytes(str));
+ }
+ printf("\n");
+ return JS_TRUE;
+}
+
+JSBool WriteFile(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval) {
+ const char *filename;
+ JSString *str;
+ JSBool rv = JS_ConvertArguments(cx, argc, argv, "sS", &filename, &str);
+ if (!rv) return JS_FALSE;
+
+ FILE *f = fopen (filename, "w");
+ if (!f) {
+ REPORT_ERROR_2(cx, "write_file: error opening file '%s': %s",
+ filename, strerror(errno));
+ return JS_FALSE;
+ }
+ fwrite (JS_GetStringBytes(str), 1, JS_GetStringLength(str), f);
+ fclose (f);
+ return JS_TRUE;
+}
+
+JSBool ReadFile(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval) {
+ const char *filename;
+ JSBool rv = JS_ConvertArguments(cx, argc, argv, "s", &filename);
+ if (!rv) return JS_FALSE;
+
+ long size = 0;
+ char *buf = readFile (filename, &size);
+ if(!buf) {
+ REPORT_ERROR_2(cx, "read_file: error opening file '%s': %s",
+ filename, strerror(errno));
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(JS_NewString(cx, buf, size));
+ return JS_TRUE;
+}
+
+/* author: tglek
+ Return the primitive if it's a primitive, otherwise compute a seq #
+ The ES4 spec says that it shouldn't be a pointer(with good reason).
+ A counter is morally wrong because in theory it could loop around and bite me,
+ but I lack in moral values and don't enjoy abusing pointers any further */
+JSBool Hashcode(JSContext *cx, JSObject *obj_this, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ if (!argc)
+ return JSVAL_FALSE;
+ jsval o = *argv;
+ if (!JSVAL_IS_OBJECT (o)) {
+ *rval = o;
+ return JSVAL_TRUE;
+ }
+ JSObject *obj = JSVAL_TO_OBJECT (*argv);
+ JSBool has_prop;
+ /* Need to check for property first to keep treehydra from getting angry */
+#if JS_VERSION < 180
+#define JS_AlreadyHasOwnProperty JS_HasProperty
+#endif
+ if (JS_AlreadyHasOwnProperty(cx, obj, "_hashcode", &has_prop) && has_prop) {
+ JS_GetProperty(cx, obj, "_hashcode", rval);
+ } else {
+ static int counter = 0;
+ char str[256];
+ jsval val;
+ snprintf (str, sizeof (str), "%x", ++counter);
+ val = STRING_TO_JSVAL (JS_NewStringCopyZ (cx, str));
+ JS_DefineProperty (cx, obj, "_hashcode", val,
+ NULL, NULL, JSPROP_PERMANENT | JSPROP_READONLY);
+ *rval = val;
+ }
+ return JS_TRUE;
+}
+
+/* Read the entire contents of a file.
+ * path path of the file to read
+ * size (out) number of bytes of file data read
+ * return null-terminated file contents, or NULL on error. Caller
+ * should free when done. */
+char *readFile(const char *path, long *size) {
+ FILE *f = fopen(path, "r");
+ if (!f) return NULL;
+ return readEntireFile(f, size);
+}
+
+/* Find a file, searching another dir if necessary. If the file is
+ * found, return a file handle open for reading and store the malloc'd
+ * name where the file was found in realname. Otherwise, return
+ * NULL. */
+FILE *findFile(const char *filename, const char *dir, char **realname) {
+ FILE *f = fopen(filename, "r");
+ if (f) {
+ *realname = strdup(filename);
+ return f;
+ }
+ if (dir && dir[0] && filename[0] && filename[0] != '/') {
+ char *buf = malloc(strlen(dir) + strlen(filename) + 2);
+ /* Doing a little extra work here to get rid of unneeded '/'. */
+ char *sep = dir[strlen(dir)-1] == '/' ? "" : "/";
+ sprintf(buf, "%s%s%s", dir, sep, filename);
+ f = fopen(buf, "r");
+ if (f) {
+ *realname = buf;
+ return f;
+ } else {
+ free(buf);
+ }
+ }
+ return NULL;
+}
+
+char *readEntireFile(FILE *f, long *size) {
+ xassert(f);
+ if (fseek(f, 0, SEEK_END)) return NULL;
+ *size = ftell(f);
+ if (fseek(f, 0, SEEK_SET)) return NULL;
+ char *buf = malloc(*size + 1);
+ xassert(*size == fread(buf, 1, *size, f));
+ buf[*size] = 0;
+ fclose(f);
+ return buf;
+}
+
+/* Report an error.
+ * If we are currently inside JS, we'll report an error to JS. But
+ * otherwise, we'll report it to the user and then exit. */
+void reportError(JSContext *cx, const char *file, int line,
+ const char *fmt, ...)
+{
+ char msg[1024];
+ const int size = sizeof(msg) / sizeof(msg[0]);
+ va_list ap;
+ va_start(ap, fmt);
+ int nw = vsnprintf(msg, size, fmt, ap);
+ va_end(ap);
+ if (nw >= size) msg[size-1] = '\0';
+
+ if (JS_IsRunning(cx)) {
+ JS_ReportError(cx, "%s (from %s:%d)", msg, file, line);
+ } else {
+ fflush(stdout);
+ fprintf(stderr, "%s:%d: Error: %s\n", file, line, msg);
+ exit(1);
+ }
+}
+
+void
+ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
+{
+ int error = JSREPORT_IS_EXCEPTION(report->flags);
+ jsval exn;
+ fflush(stdout);
+ fprintf(stderr, "%s:%d: ", (report->filename ? report->filename : "NULL"),
+ report->lineno);
+ if (JSREPORT_IS_WARNING(report->flags)) fprintf(stderr, "JS Warning");
+ if (JSREPORT_IS_STRICT(report->flags)) fprintf(stderr, "JS STRICT");
+ if (error) fprintf(stderr, "JS Exception");
+
+ fprintf(stderr, ": %s\n", message);
+ if (report->linebuf) {
+ fprintf(stderr, "%s\n", report->linebuf);
+ }
+ if (error && JS_GetPendingException(cx, &exn)
+ && JS_TypeOfValue (cx, exn) == JSTYPE_OBJECT) {
+ jsval stack;
+ /* reformat the spidermonkey stack */
+ JS_GetProperty(cx, JSVAL_TO_OBJECT (exn), "stack", &stack);
+ if (JS_TypeOfValue (cx, stack) == JSTYPE_STRING) {
+ char *str = JS_GetStringBytes (JSVAL_TO_STRING (stack));
+ int counter = 0;
+ do {
+ char *eol = strchr (str, '\n');
+ if (eol)
+ *eol = 0;
+ char *at = strrchr (str, '@');
+ if (!at) break;
+ *at = 0;
+ if (!*str) break;
+ fprintf (stderr, "%s:\t#%d: %s\n", at+1, counter++, str);
+ *at = '@';
+ if (eol) {
+ *eol = '\n';
+ str = eol + 1;
+ } else {
+ break;
+ }
+ } while (*str);
+ }
+ }
+ fflush(stderr);
+
+ if (!JSREPORT_IS_WARNING(report->flags))
+ exit(1);
+}
diff --git a/jshydra_funcs.h b/jshydra_funcs.h
new file mode 100644
index 0000000..942bbe9
--- /dev/null
+++ b/jshydra_funcs.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+#ifndef JSHYDRA_FUNCS_H
+#define JSHYDRA_FUNCS_H
+
+/* JS Natives */
+
+#define DH_JSNATIVE(fname) JSBool fname(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+
+DH_JSNATIVE(Require);
+DH_JSNATIVE(Include);
+
+DH_JSNATIVE(Diagnostic);
+DH_JSNATIVE(Print);
+
+DH_JSNATIVE(WriteFile);
+DH_JSNATIVE(ReadFile);
+DH_JSNATIVE(Hashcode);
+
+void ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report);
+
+/* Related C functions */
+
+char *readFile(const char *path, long *size);
+FILE *findFile(const char *filename, const char *dir, char **realname);
+char *readEntireFile(FILE *f, long *size);
+void reportError(JSContext *cx, const char *file, int line,
+ const char *fmt, ...);
+
+#define REPORT_ERROR_0(cx, fmt) reportError(cx, __FILE__, __LINE__, fmt);
+#define REPORT_ERROR_1(cx, fmt, arg1) reportError(cx, __FILE__, __LINE__, fmt, arg1);
+#define REPORT_ERROR_2(cx, fmt, arg1, arg2) reportError(cx, __FILE__, __LINE__, fmt, arg1, arg1);
+
+#define xassert(cond) \
+ if (!(cond)) { \
+ fprintf(stderr, "%s:%d: Assertion failed:" #cond "\n", __FILE__, __LINE__);\
+ exit(1); \
+ }
+
+#endif
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/adblock-plus.git
More information about the Pkg-mozext-commits
mailing list